crypticorn 2.8.0rc1__py3-none-any.whl → 2.8.0rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
crypticorn/__init__.py CHANGED
@@ -3,6 +3,10 @@
3
3
  .. include:: ../CHANGELOG.md
4
4
  """
5
5
 
6
+ from crypticorn.common.logging import configure_logging
7
+ configure_logging("crypticorn")
8
+
6
9
  from crypticorn.client import ApiClient
7
10
 
8
11
  __all__ = ["ApiClient"]
12
+
@@ -78,10 +78,12 @@ class CreateApiKeyRequest(BaseModel):
78
78
  "read:metrics:tokens",
79
79
  "read:metrics:markets",
80
80
  "read:sentiment",
81
+ "read:admin",
82
+ "write:admin",
81
83
  ]
82
84
  ):
83
85
  raise ValueError(
84
- "each list item must be one of ('read:predictions', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment')"
86
+ "each list item must be one of ('read:predictions', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:admin', 'write:admin')"
85
87
  )
86
88
  return value
87
89
 
@@ -86,10 +86,12 @@ class GetApiKeys200ResponseInner(BaseModel):
86
86
  "read:metrics:tokens",
87
87
  "read:metrics:markets",
88
88
  "read:sentiment",
89
+ "read:admin",
90
+ "write:admin",
89
91
  ]
90
92
  ):
91
93
  raise ValueError(
92
- "each list item must be one of ('read:predictions', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment')"
94
+ "each list item must be one of ('read:predictions', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:admin', 'write:admin')"
93
95
  )
94
96
  return value
95
97
 
@@ -10,5 +10,6 @@ from crypticorn.common.exceptions import *
10
10
  from crypticorn.common.pagination import *
11
11
  from crypticorn.common.logging import *
12
12
  from crypticorn.common.ansi_colors import *
13
+ from crypticorn.common.middleware import *
13
14
  from crypticorn.common.router.status_router import router as status_router
14
15
  from crypticorn.common.router.admin_router import router as admin_router
@@ -1,10 +1,6 @@
1
1
  from enum import StrEnum
2
2
  from typing import TYPE_CHECKING
3
3
 
4
- if TYPE_CHECKING:
5
- pass
6
-
7
-
8
4
  class AnsiColors(StrEnum):
9
5
  # Regular Text Colors
10
6
  BLACK = "\033[30m" # black
crypticorn/common/auth.py CHANGED
@@ -75,7 +75,9 @@ class AuthHandler:
75
75
  raise HTTPException(
76
76
  content=ExceptionContent(
77
77
  error=ApiError.INSUFFICIENT_SCOPES,
78
- message="Insufficient scopes to access this resource (required: " + ", ".join(api_scopes) + ")",
78
+ message="Insufficient scopes to access this resource (required: "
79
+ + ", ".join(api_scopes)
80
+ + ")",
79
81
  ),
80
82
  )
81
83
 
@@ -95,28 +95,35 @@ class WebSocketException(HTTPException):
95
95
  async def general_handler(request: Request, exc: Exception) -> JSONResponse:
96
96
  """This is the default exception handler for all exceptions."""
97
97
  body = ExceptionContent(message=str(exc), error=ApiError.UNKNOWN_ERROR)
98
- res = JSONResponse(
99
- status_code=body.enrich().status_code, content=HTTPException(content=body).detail
98
+ res = JSONResponse(
99
+ status_code=body.enrich().status_code,
100
+ content=HTTPException(content=body).detail,
100
101
  )
101
102
  logger.error(f"Response validation error: {res}")
102
103
  return res
103
104
 
104
105
 
105
- async def request_validation_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
106
+ async def request_validation_handler(
107
+ request: Request, exc: RequestValidationError
108
+ ) -> JSONResponse:
106
109
  """This is the exception handler for all request validation errors."""
107
110
  body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_REQUEST)
108
111
  res = JSONResponse(
109
- status_code=body.enrich().status_code, content=HTTPException(content=body).detail
112
+ status_code=body.enrich().status_code,
113
+ content=HTTPException(content=body).detail,
110
114
  )
111
115
  logger.error(f"Response validation error: {res}")
112
116
  return res
113
117
 
114
118
 
115
- async def response_validation_handler(request: Request, exc: ResponseValidationError) -> JSONResponse:
119
+ async def response_validation_handler(
120
+ request: Request, exc: ResponseValidationError
121
+ ) -> JSONResponse:
116
122
  """This is the exception handler for all response validation errors."""
117
123
  body = ExceptionContent(message=str(exc), error=ApiError.INVALID_DATA_RESPONSE)
118
124
  res = JSONResponse(
119
- status_code=body.enrich().status_code, content=HTTPException(content=body).detail
125
+ status_code=body.enrich().status_code,
126
+ content=HTTPException(content=body).detail,
120
127
  )
121
128
  logger.error(f"Response validation error: {res}")
122
129
  return res
@@ -1,8 +1,9 @@
1
+ from __future__ import annotations
1
2
  # shared_logger.py
2
3
  import logging
3
- from logging import _nameToLevel, _levelToName
4
4
  import sys
5
5
  from contextvars import ContextVar
6
+ from contextlib import asynccontextmanager
6
7
  import json
7
8
  from pydantic import BaseModel
8
9
  from enum import StrEnum
@@ -10,6 +11,7 @@ from crypticorn.common.mixins import ValidateEnumMixin
10
11
  from crypticorn.common.ansi_colors import AnsiColors as C
11
12
  from datetime import datetime
12
13
 
14
+
13
15
  class LogLevel(ValidateEnumMixin, StrEnum):
14
16
  DEBUG = "DEBUG"
15
17
  INFO = "INFO"
@@ -34,11 +36,11 @@ class LogLevel(ValidateEnumMixin, StrEnum):
34
36
 
35
37
  @staticmethod
36
38
  def get_level(level: "LogLevel") -> int:
37
- return _nameToLevel.get(level, logging.INFO)
39
+ return logging._nameToLevel.get(level, logging.INFO)
38
40
 
39
41
  @staticmethod
40
42
  def get_name(level: int) -> "LogLevel":
41
- return LogLevel(_levelToName.get(level, "INFO"))
43
+ return LogLevel(logging._levelToName.get(level, "INFO"))
42
44
 
43
45
 
44
46
  _LOGFORMAT = (
@@ -47,9 +49,7 @@ _LOGFORMAT = (
47
49
  f"%(levelcolor)s%(levelname)s{C.RESET} - "
48
50
  f"%(message)s"
49
51
  )
50
- _PLAIN_LOGFORMAT = (
51
- "%(asctime)s - " "%(name)s - " "%(levelname)s - " "%(message)s"
52
- )
52
+ _PLAIN_LOGFORMAT = "%(asctime)s - " "%(name)s - " "%(levelname)s - " "%(message)s"
53
53
  _DATEFMT = "%Y-%m-%d %H:%M:%S.%f:"
54
54
 
55
55
 
@@ -67,20 +67,26 @@ class CustomFormatter(logging.Formatter):
67
67
  s = dt.strftime(datefmt)
68
68
  return s[:-3] # Trim last 3 digits to get milliseconds
69
69
 
70
- def get_logger(
71
- name: str, fmt: str = _LOGFORMAT, datefmt: str = _DATEFMT,
70
+
71
+ def configure_logging(
72
+ name: str,
73
+ fmt: str = _LOGFORMAT,
74
+ datefmt: str = _DATEFMT,
72
75
  stdout_level: int = logging.INFO,
73
76
  file_level: int = logging.INFO,
74
77
  log_file: str = None,
75
78
  filters: list[logging.Filter] = [],
76
- ) -> logging.Logger:
77
- """Returns crypticorn logger instance."""
79
+ ) -> None:
80
+ """Configures the logging for the application.
81
+ Run this function as early as possible in the application (for example using the `lifespan` parameter in FastAPI).
82
+ Then use can use the default `logging.getLogger(__name__)` method to get the logger.
83
+ """
78
84
  logger = logging.getLogger(name)
79
85
 
80
- if logger.handlers: # clear existing handlers to avoid duplicates
86
+ if logger.handlers: # clear existing handlers to avoid duplicates
81
87
  logger.handlers.clear()
82
88
 
83
- logger.setLevel(min(stdout_level, file_level)) # set to most verbose level
89
+ logger.setLevel(min(stdout_level, file_level)) # set to most verbose level
84
90
 
85
91
  # Configure stdout handler
86
92
  stdout_handler = logging.StreamHandler(sys.stdout)
@@ -93,11 +99,18 @@ def get_logger(
93
99
  # Configure file handler
94
100
  if log_file:
95
101
  os.makedirs(os.path.dirname(log_file), exist_ok=True)
96
- file_handler = logging.RotatingFileHandler(log_file, maxBytes=10*1024*1024, backupCount=5)
102
+ file_handler = logging.RotatingFileHandler(
103
+ log_file, maxBytes=10 * 1024 * 1024, backupCount=5
104
+ )
97
105
  file_handler.setLevel(file_level)
98
106
  file_handler.setFormatter(CustomFormatter(fmt=fmt, datefmt=datefmt))
99
107
  for filter in filters:
100
108
  file_handler.addFilter(filter)
101
109
  logger.addHandler(file_handler)
102
110
 
103
- return logger
111
+
112
+ def disable_logging():
113
+ """Disable logging for the crypticorn logger.
114
+ """
115
+ logger = logging.getLogger("crypticorn")
116
+ logger.disabled = True
@@ -0,0 +1,27 @@
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from crypticorn.common.logging import configure_logging
4
+ import logging
5
+
6
+
7
+ def add_cors_middleware(app: "FastAPI"):
8
+ app.add_middleware(
9
+ CORSMiddleware,
10
+ allow_origins=[
11
+ "http://localhost:5173", # vite dev server
12
+ "http://localhost:4173", # vite preview server
13
+ ],
14
+ allow_origin_regex="^https:\/\/([a-zA-Z0-9-]+\.)*crypticorn\.(dev|com)\/?$", # matches (multiple or no) subdomains of crypticorn.dev and crypticorn.com
15
+ allow_credentials=True,
16
+ allow_methods=["*"],
17
+ allow_headers=["*"],
18
+ )
19
+
20
+ async def default_lifespan(app: FastAPI):
21
+ """Default lifespan for the applications.
22
+ This is used to configure the logging for the application.
23
+ To override this, pass a different lifespan to the FastAPI constructor or call this lifespan within a custom lifespan.
24
+ """
25
+ configure_logging(__name__) # for the consuming app
26
+ logger = logging.getLogger(__name__)
27
+ yield
@@ -6,15 +6,12 @@ ONLY ALLOW ACCESS TO THIS ROUTER WITH ADMIN SCOPES.
6
6
  """
7
7
 
8
8
  import os
9
- import sys
10
9
  import pkg_resources
11
10
  import threading
12
11
  import time
13
- import json
14
12
  import psutil
15
- from fastapi import APIRouter, HTTPException, Body, Query
13
+ from fastapi import APIRouter, Query
16
14
  from typing import Literal, Union
17
- from dotenv import dotenv_values
18
15
  from crypticorn.common.logging import LogLevel
19
16
  import logging
20
17
 
@@ -22,6 +19,7 @@ router = APIRouter(tags=["Admin"], prefix="/admin")
22
19
 
23
20
  START_TIME = time.time()
24
21
 
22
+
25
23
  @router.get("/log-level", status_code=200, operation_id="getLogLevel")
26
24
  async def get_logging_level() -> LogLevel:
27
25
  """
@@ -29,10 +27,9 @@ async def get_logging_level() -> LogLevel:
29
27
  """
30
28
  return LogLevel.get_name(logging.getLogger().level)
31
29
 
30
+
32
31
  @router.get("/uptime", operation_id="getUptime", status_code=200)
33
- def get_uptime(
34
- type: Literal["seconds", "human"] = "seconds"
35
- ) -> Union[int, str]:
32
+ def get_uptime(type: Literal["seconds", "human"] = "seconds") -> Union[int, str]:
36
33
  """Return the server uptime in seconds or human-readable form."""
37
34
  uptime_seconds = int(time.time() - START_TIME)
38
35
  if type == "seconds":
@@ -73,7 +70,9 @@ def get_container_limits() -> dict:
73
70
  limits["memory_limit_MB"] = "N/A"
74
71
 
75
72
  try:
76
- with open("/sys/fs/cgroup/cpu/cpu.cfs_quota_us") as f1, open("/sys/fs/cgroup/cpu/cpu.cfs_period_us") as f2:
73
+ with open("/sys/fs/cgroup/cpu/cpu.cfs_quota_us") as f1, open(
74
+ "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
75
+ ) as f2:
77
76
  quota = int(f1.read().strip())
78
77
  period = int(f2.read().strip())
79
78
  limits["cpu_limit_cores"] = quota / period if quota > 0 else "N/A"
@@ -86,11 +85,16 @@ def get_container_limits() -> dict:
86
85
  @router.get("/dependencies", operation_id="getDependencies", status_code=200)
87
86
  def list_installed_packages(
88
87
  include: list[str] = Query(
89
- default=None, description="List of dependencies to include in the response. If not provided, all installed packages will be returned."
88
+ default=None,
89
+ description="List of dependencies to include in the response. If not provided, all installed packages will be returned.",
90
90
  )
91
91
  ) -> list:
92
92
  """Return a list of installed packages and versions."""
93
93
  return sorted(
94
- [{dist.project_name: dist.version} for dist in pkg_resources.working_set if include is None or dist.project_name in include],
94
+ [
95
+ {dist.project_name: dist.version}
96
+ for dist in pkg_resources.working_set
97
+ if include is None or dist.project_name in include
98
+ ],
95
99
  key=lambda x: next(iter(x)),
96
100
  )
@@ -16,9 +16,9 @@ async def ping() -> str:
16
16
  @router.get("/time", operation_id="getTime")
17
17
  async def time(type: Literal["iso", "unix"] = "iso") -> str:
18
18
  """
19
- Returns the current time in the specified format.
19
+ Returns the current time in either ISO or Unix timestamp (seconds) format.
20
20
  """
21
21
  if type == "iso":
22
22
  return datetime.now().isoformat()
23
- else:
23
+ elif type == "unix":
24
24
  return str(int(datetime.now().timestamp()))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.8.0rc1
3
+ Version: 2.8.0rc2
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License: MIT
@@ -16,6 +16,7 @@ Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  Requires-Dist: fastapi<1.0.0,>=0.115.0
18
18
  Requires-Dist: click<9.0.0,>=8.0.0
19
+ Requires-Dist: psutil<8.0.0,>=7.0.0
19
20
  Requires-Dist: urllib3<3.0.0,>=1.25.3
20
21
  Requires-Dist: python_dateutil<3.0.0,>=2.8.2
21
22
  Requires-Dist: aiohttp<4.0.0,>=3.8.4
@@ -1,4 +1,4 @@
1
- crypticorn/__init__.py,sha256=TL41V09dmtbd2ee07wmOuG9KJJpyvLMPJi5DEd9bDyU,129
1
+ crypticorn/__init__.py,sha256=Fi5xI_NnK1cVteLdFY5SJ-mzYkYz3af-WOUauZkfTa0,219
2
2
  crypticorn/client.py,sha256=jMdF4mZuqB8YMZZOwJkTcvpHluGqw6Q-taSF6vQS5WM,3912
3
3
  crypticorn/auth/__init__.py,sha256=JAl1tBLK9pYLr_-YKaj581c-c94PWLoqnatTIVAVvMM,81
4
4
  crypticorn/auth/main.py,sha256=j8eRGN2gUWyeOCnWnUPe3mCAfaidGnOMnZRiSQy-yzM,720
@@ -22,9 +22,9 @@ crypticorn/auth/client/models/authorize_user200_response.py,sha256=fstTaffARzCe7
22
22
  crypticorn/auth/client/models/authorize_user200_response_auth.py,sha256=OQzmKNICdr7tHrlhEDIxagDZx7XuW8VO2U3OMsWIJOA,3208
23
23
  crypticorn/auth/client/models/authorize_user_request.py,sha256=o_1Ms6npD_1dJQ6aYshEk9JPV7JIkmAmuRawDDPUoTc,3205
24
24
  crypticorn/auth/client/models/create_api_key200_response.py,sha256=UGjZwITv2EdS7bbt55D0w2an6_uO4u6gYr-GihL9m80,2459
25
- crypticorn/auth/client/models/create_api_key_request.py,sha256=V98HWwlRT2AYo96D7W5L4P-MFrOVi62zvHsFY3CVl8M,5479
25
+ crypticorn/auth/client/models/create_api_key_request.py,sha256=VaxptajDgoPPIfkkF1qh_wU3a7aTSc5wcjqvDcR5mnQ,5577
26
26
  crypticorn/auth/client/models/create_user_request.py,sha256=nq4t2R4ldqSsJUoVhLw9YocdUwatH4gQ-jdFz3jaqrg,3481
27
- crypticorn/auth/client/models/get_api_keys200_response_inner.py,sha256=G5YxZyrm06NrhfdsS-JA2P97doso2jFscElmGR7teXs,5867
27
+ crypticorn/auth/client/models/get_api_keys200_response_inner.py,sha256=DiNnVej8GasK09PorQCk4jS_LWzwCxtjHEVH42cOA4U,5965
28
28
  crypticorn/auth/client/models/list_wallets200_response.py,sha256=G2LQiThhtynkuDGFvIs-BowR38ut7cRbIeCzK4wMnPw,4732
29
29
  crypticorn/auth/client/models/list_wallets200_response_balances_inner.py,sha256=acTJa8B5U8j3_wS1TUYXnprptqF_T4dlV-wVaQ5ZXig,4023
30
30
  crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py,sha256=KrCHFXXfc6U61nDFsq26gRtQQnc2_tSjL2fwQOnBfzI,3603
@@ -63,21 +63,22 @@ crypticorn/cli/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
63
63
  crypticorn/cli/templates/auth.py,sha256=Q1TxlA7qzhjvrqp1xz1aV2vGnj3DKFNN-VSl3o0B-dI,983
64
64
  crypticorn/cli/templates/dependabot.yml,sha256=ct5ieB8KAV1KLzoYKUNm6dZ9wKG_P_JQHgRjZUfT54w,861
65
65
  crypticorn/cli/templates/ruff.yml,sha256=gWicFFTzC4nToSmRkIIGipos8CZ447YG0kebBCJhtJE,319
66
- crypticorn/common/__init__.py,sha256=FkOmpnrSPtSyz5CoWWqIEslEF601vb_3H46ZUwwEtAQ,628
67
- crypticorn/common/ansi_colors.py,sha256=WqyRMlu3tJj5e-c3hEpa0dupNVZhzRmQcxJgRWSyJ_k,1202
68
- crypticorn/common/auth.py,sha256=6oJ26t0N2Msup-okC2iFhpHz9ZeaGnQZ5zaCODIsN_k,8673
66
+ crypticorn/common/__init__.py,sha256=29n5tUr9-yjjJ8sjkbMrwq7pDKZ2Z1qz1bR1msGJDkA,671
67
+ crypticorn/common/ansi_colors.py,sha256=7nRsc5TPRwKI_7yVHD2WrhcOhHUcysktAIEPw_Zl5qk,1173
68
+ crypticorn/common/auth.py,sha256=GIb9MikQsSxqz-K5rDIOroP5mFoTgQqwByTGO5JqcdM,8713
69
69
  crypticorn/common/decorators.py,sha256=pmnGYCIrLv59wZkDbvPyK9NJmgPJWW74LXTdIWSjOkY,1063
70
70
  crypticorn/common/enums.py,sha256=RitDVqlG_HTe6tHT6bWusZNFCeYk1eQvJVH-7x3_Zlg,668
71
71
  crypticorn/common/errors.py,sha256=8jxZ2lLn_NoFKKq6n2JwKPsR0dA2vkGnbXDfEK6ndH0,27851
72
- crypticorn/common/exceptions.py,sha256=tOg8WjJXTtDcqZjokwk4QD5cQtXq5-2gAbvbHENJTng,6050
73
- crypticorn/common/logging.py,sha256=ncy4E9ogL7HPPgvcHS4zMiXBF5kyOrNcxHFHYJ7IyMw,3220
72
+ crypticorn/common/exceptions.py,sha256=BuRLQIg2_pwsaQAhPKP3lY9q2GNp0SlRdXlvp1O2USo,6088
73
+ crypticorn/common/logging.py,sha256=aI1RfWMkNDTGov-qiUmvjRk0b9otBwZggWJ5cX5Zmdw,3651
74
+ crypticorn/common/middleware.py,sha256=mh1lNaN3X_UKH7PflewhlVEc1AKTqhB-tf7r1gLzV3E,1036
74
75
  crypticorn/common/mixins.py,sha256=LKPcNTR8uREeDGWTlWozNx7rS1mYdQVx1RllLhxIAsE,1640
75
76
  crypticorn/common/pagination.py,sha256=c07jrMNrBaNTmgx4sppdP7ND4RNT7NBqBXWvofazIlE,2251
76
77
  crypticorn/common/scopes.py,sha256=ofJ5FDf30wab572XvDzAXVKBIUWa3shScAmzNrJsWqQ,2453
77
78
  crypticorn/common/urls.py,sha256=3Gf1NU1XQYcOTjcdztG3bDAE98FVbgTK2QXzUe7tFVQ,878
78
79
  crypticorn/common/utils.py,sha256=Kz2-I96MKIGKM18PHQ77VbKHLMGUvZG_jjj7xpQed8k,2138
79
- crypticorn/common/router/admin_router.py,sha256=aaAqWAnaZ2CkHU9cJgeZKyUoc6JnC6oEQhUa_P0bWKw,3380
80
- crypticorn/common/router/status_router.py,sha256=RIgyNVVnD6Y5Qsfz_oJk0BDuPPmCBM_B4ytcRiSXvo8,576
80
+ crypticorn/common/router/admin_router.py,sha256=HUhFr5HVOM0JmVgAlLZbQMuSjNfcqULhBqJlNcMJTW4,3376
81
+ crypticorn/common/router/status_router.py,sha256=922dHfpVM5auOTuNswIhDRmk_1bmU5hH83bxoT70uss,616
81
82
  crypticorn/hive/__init__.py,sha256=hRfTlEzEql4msytdUC_04vfaHzVKG5CGZle1M-9QFgY,81
82
83
  crypticorn/hive/main.py,sha256=4oQ2RybZMbe0kRxVJrVAABsN5kUTCMExQFJDSnAzBUY,2428
83
84
  crypticorn/hive/utils.py,sha256=dxQ_OszrnTsslO5hDefMmgfj6yRwRPr8sr17fGizWIw,2066
@@ -227,8 +228,8 @@ crypticorn/trade/client/models/strategy_model_input.py,sha256=ala19jARyfA5ysys5D
227
228
  crypticorn/trade/client/models/strategy_model_output.py,sha256=2o2lhbgUSTznowpMLEHF1Ex9TG9oRmzlCIb-gXqo7_s,5643
228
229
  crypticorn/trade/client/models/tpsl.py,sha256=C2KgTIZs-a8W4msdaXgBKJcwtA-o5wR4rBauRP-iQxU,4317
229
230
  crypticorn/trade/client/models/trading_action_type.py,sha256=pGq_TFLMPfYFizYP-xKgEC1ZF4U3lGdJYoGa_ZH2x-Q,769
230
- crypticorn-2.8.0rc1.dist-info/METADATA,sha256=HdPQkiN3MMSTb4TS9IJQrhfN758XihFO2IG1OBJtrMg,6610
231
- crypticorn-2.8.0rc1.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
232
- crypticorn-2.8.0rc1.dist-info/entry_points.txt,sha256=d_xHsGvUTebPveVUK0SrpDFQ5ZRSjlI7lNCc11sn2PM,59
233
- crypticorn-2.8.0rc1.dist-info/top_level.txt,sha256=EP3NY216qIBYfmvGl0L2Zc9ItP0DjGSkiYqd9xJwGcM,11
234
- crypticorn-2.8.0rc1.dist-info/RECORD,,
231
+ crypticorn-2.8.0rc2.dist-info/METADATA,sha256=BiEarCgxuOZOuT9onAHw8ciilAQZ03IriGI21WKjYyY,6646
232
+ crypticorn-2.8.0rc2.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
233
+ crypticorn-2.8.0rc2.dist-info/entry_points.txt,sha256=d_xHsGvUTebPveVUK0SrpDFQ5ZRSjlI7lNCc11sn2PM,59
234
+ crypticorn-2.8.0rc2.dist-info/top_level.txt,sha256=EP3NY216qIBYfmvGl0L2Zc9ItP0DjGSkiYqd9xJwGcM,11
235
+ crypticorn-2.8.0rc2.dist-info/RECORD,,