crypticorn 2.3.0__py3-none-any.whl → 2.4.1__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/cli/__init__.py +3 -0
- crypticorn/cli/__main__.py +14 -0
- crypticorn/cli/init.py +86 -0
- crypticorn/cli/templates/__init__.py +0 -0
- crypticorn/cli/templates/auth.py +34 -0
- crypticorn/common/enums.py +28 -8
- crypticorn/common/scopes.py +21 -4
- crypticorn/trade/client/__init__.py +1 -1
- crypticorn/trade/client/api/api_keys_api.py +41 -41
- crypticorn/trade/client/models/__init__.py +1 -1
- crypticorn/trade/client/models/api_error_identifier.py +11 -6
- crypticorn/trade/client/models/exchange.py +1 -1
- crypticorn/trade/client/models/exchange_key_model.py +156 -0
- crypticorn/trade/client/models/market_type.py +1 -1
- crypticorn/trade/main.py +1 -1
- {crypticorn-2.3.0.dist-info → crypticorn-2.4.1.dist-info}/METADATA +17 -2
- {crypticorn-2.3.0.dist-info → crypticorn-2.4.1.dist-info}/RECORD +20 -13
- crypticorn-2.4.1.dist-info/entry_points.txt +2 -0
- {crypticorn-2.3.0.dist-info → crypticorn-2.4.1.dist-info}/WHEEL +0 -0
- {crypticorn-2.3.0.dist-info → crypticorn-2.4.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# crypticorn/cli.py
|
2
|
+
|
3
|
+
import click
|
4
|
+
from crypticorn.cli import init_group
|
5
|
+
|
6
|
+
@click.group()
|
7
|
+
def cli():
|
8
|
+
"""🧙 Crypticorn CLI — magic for our microservices."""
|
9
|
+
pass
|
10
|
+
|
11
|
+
cli.add_command(init_group, name="init")
|
12
|
+
|
13
|
+
if __name__ == "__main__":
|
14
|
+
cli()
|
crypticorn/cli/init.py
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
import click
|
2
|
+
from pathlib import Path
|
3
|
+
import subprocess
|
4
|
+
import importlib.resources as pkg_resources
|
5
|
+
import crypticorn.cli.templates as templates
|
6
|
+
|
7
|
+
def get_git_root() -> Path:
|
8
|
+
'''Get the root directory of the git repository.'''
|
9
|
+
try:
|
10
|
+
return Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True).strip())
|
11
|
+
except Exception:
|
12
|
+
return Path.cwd()
|
13
|
+
|
14
|
+
def copy_template(template_name: str, target_path: Path):
|
15
|
+
'''Copy a template file to the target path.'''
|
16
|
+
with pkg_resources.files(templates).joinpath(template_name).open("r") as template_file:
|
17
|
+
content = template_file.read()
|
18
|
+
|
19
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
20
|
+
with target_path.open("w") as f:
|
21
|
+
f.write(content)
|
22
|
+
|
23
|
+
click.secho(f"✅ Created: {target_path}", fg="green")
|
24
|
+
|
25
|
+
@click.group()
|
26
|
+
def init_group():
|
27
|
+
"""Initialize files like CI configs, linters, etc."""
|
28
|
+
pass
|
29
|
+
|
30
|
+
@init_group.command("ruff")
|
31
|
+
@click.option('-f', '--force', is_flag=True, help='Force overwrite the ruff.yml')
|
32
|
+
def init_ruff(force):
|
33
|
+
"""Add .github/workflows/ruff.yml"""
|
34
|
+
root = get_git_root()
|
35
|
+
target = root / ".github/workflows/ruff.yml"
|
36
|
+
if target.exists() and not force:
|
37
|
+
click.secho("File already exists, use --force / -f to overwrite", fg="red")
|
38
|
+
return
|
39
|
+
copy_template("ruff.yml", target)
|
40
|
+
|
41
|
+
@init_group.command("docker")
|
42
|
+
@click.option('-o', '--output', type=click.Path(), help='Custom output path for the Dockerfile')
|
43
|
+
@click.option('-f', '--force', is_flag=True, help='Force overwrite the Dockerfile')
|
44
|
+
def init_docker(output, force):
|
45
|
+
"""Add Dockerfile"""
|
46
|
+
root = get_git_root()
|
47
|
+
target = Path(output) if output else root / "Dockerfile"
|
48
|
+
if target.exists() and not force:
|
49
|
+
click.secho("File already exists, use --force / -f to overwrite", fg="red")
|
50
|
+
return
|
51
|
+
copy_template("Dockerfile", target)
|
52
|
+
click.secho("Make sure to update the Dockerfile", fg="yellow")
|
53
|
+
|
54
|
+
@init_group.command("auth")
|
55
|
+
@click.option('-o', '--output', type=click.Path(), help='Custom output path for the auth handler')
|
56
|
+
@click.option('-f', '--force', is_flag=True, help='Force overwrite the auth handler')
|
57
|
+
def init_auth(output, force):
|
58
|
+
"""Add auth.py with auth handler. Everything you need to start using the auth service."""
|
59
|
+
root = get_git_root()
|
60
|
+
if Path(output).is_dir():
|
61
|
+
click.secho("Output path is a directory, please provide a file path", fg="red")
|
62
|
+
return
|
63
|
+
target = Path(output) if output else root / "src/auth.py"
|
64
|
+
if target.exists() and not force:
|
65
|
+
click.secho("File already exists, use --force / -f to overwrite", fg="red")
|
66
|
+
return
|
67
|
+
copy_template("auth.py", target)
|
68
|
+
click.secho('''
|
69
|
+
Make sure to update the .env file with:
|
70
|
+
IS_DOCKER=0
|
71
|
+
API_ENV=local
|
72
|
+
and the docker-compose.yml file with:
|
73
|
+
environment:
|
74
|
+
- IS_DOCKER=1
|
75
|
+
''', fg="yellow")
|
76
|
+
|
77
|
+
@init_group.command("dependabot")
|
78
|
+
@click.option('-f', '--force', is_flag=True, help='Force overwrite the dependabot.yml')
|
79
|
+
def init_dependabot(force):
|
80
|
+
"""Add dependabot.yml"""
|
81
|
+
root = get_git_root()
|
82
|
+
target = root / ".github/dependabot.yml"
|
83
|
+
if target.exists() and not force:
|
84
|
+
click.secho("File already exists, use --force / -f to overwrite", fg="red")
|
85
|
+
return
|
86
|
+
copy_template("dependabot.yml", target)
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from crypticorn.common import (
|
2
|
+
AuthHandler as AuthHandler,
|
3
|
+
Scope as Scope,
|
4
|
+
Verify200Response as Verify200Response,
|
5
|
+
BaseUrl as BaseUrl,
|
6
|
+
ApiEnv as ApiEnv,
|
7
|
+
)
|
8
|
+
from fastapi import Security as Security
|
9
|
+
import os
|
10
|
+
import dotenv
|
11
|
+
import logging
|
12
|
+
|
13
|
+
dotenv.load_dotenv()
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
DOCKER_ENV = os.getenv("IS_DOCKER")
|
18
|
+
API_ENV = os.getenv("API_ENV")
|
19
|
+
|
20
|
+
if not DOCKER_ENV:
|
21
|
+
raise ValueError("IS_DOCKER is not set. Please set it to '0' in .env and '1' in the docker-compose.yml file.")
|
22
|
+
|
23
|
+
if not API_ENV:
|
24
|
+
raise ValueError("API_ENV is not set. Please set it to 'prod', 'dev' or 'local' in .env (of type ApiEnv).")
|
25
|
+
|
26
|
+
if DOCKER_ENV == "0":
|
27
|
+
logger.info(f"Using {API_ENV} environment")
|
28
|
+
base_url = BaseUrl.from_env(ApiEnv(API_ENV))
|
29
|
+
else:
|
30
|
+
base_url = BaseUrl.DOCKER
|
31
|
+
logger.info("Using docker environment")
|
32
|
+
|
33
|
+
auth_handler = AuthHandler(base_url=base_url)
|
34
|
+
logger.info(f"Auth URL: {auth_handler.client.config.host}")
|
crypticorn/common/enums.py
CHANGED
@@ -1,16 +1,38 @@
|
|
1
1
|
from enum import StrEnum
|
2
2
|
|
3
|
+
class ValidateEnumMixin:
|
4
|
+
"""
|
5
|
+
Mixin for validating enum values manually.
|
3
6
|
|
4
|
-
|
5
|
-
|
7
|
+
⚠️ Note:
|
8
|
+
This does NOT enforce validation automatically on enum creation.
|
9
|
+
It's up to the developer to call `Class.validate(value)` where needed.
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
>>> class Color(ValidateEnumMixin, StrEnum):
|
13
|
+
>>> RED = "red"
|
14
|
+
>>> GREEN = "green"
|
6
15
|
|
16
|
+
>>> Color.validate("red") # True
|
17
|
+
>>> Color.validate("yellow") # False
|
18
|
+
|
19
|
+
Order of inheritance matters — the mixin must come first.
|
20
|
+
"""
|
21
|
+
@classmethod
|
22
|
+
def validate(cls, value) -> bool:
|
23
|
+
try:
|
24
|
+
cls(value)
|
25
|
+
return True
|
26
|
+
except ValueError:
|
27
|
+
return False
|
28
|
+
|
29
|
+
class Exchange(ValidateEnumMixin, StrEnum):
|
30
|
+
"""Supported exchanges for trading"""
|
7
31
|
KUCOIN = "kucoin"
|
8
32
|
BINGX = "bingx"
|
9
33
|
|
10
|
-
|
11
|
-
class InternalExchange(StrEnum):
|
34
|
+
class InternalExchange(ValidateEnumMixin, StrEnum):
|
12
35
|
"""All exchanges we are using, including public (Exchange)"""
|
13
|
-
|
14
36
|
KUCOIN = "kucoin"
|
15
37
|
BINGX = "bingx"
|
16
38
|
BINANCE = "binance"
|
@@ -18,11 +40,9 @@ class InternalExchange(StrEnum):
|
|
18
40
|
HYPERLIQUID = "hyperliquid"
|
19
41
|
BITGET = "bitget"
|
20
42
|
|
21
|
-
|
22
|
-
class MarketType(StrEnum):
|
43
|
+
class MarketType(ValidateEnumMixin, StrEnum):
|
23
44
|
"""
|
24
45
|
Market types
|
25
46
|
"""
|
26
|
-
|
27
47
|
SPOT = "spot"
|
28
48
|
FUTURES = "futures"
|
crypticorn/common/scopes.py
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
-
from enum import StrEnum
|
1
|
+
from enum import StrEnum, EnumMeta
|
2
|
+
import logging
|
2
3
|
|
4
|
+
logger = logging.getLogger('uvicorn')
|
3
5
|
|
4
|
-
class
|
6
|
+
class Fallback(EnumMeta):
|
7
|
+
"""Fallback to no scope for unknown scopes."""
|
8
|
+
def __getattr__(cls, name):
|
9
|
+
logger.warning(
|
10
|
+
f"Unknown scope '{name}' - falling back to no scope - update crypticorn package or check for typos"
|
11
|
+
)
|
12
|
+
return None
|
13
|
+
|
14
|
+
class Scope(StrEnum, metaclass=Fallback):
|
5
15
|
"""
|
6
16
|
The permission scopes for the API.
|
7
17
|
"""
|
@@ -12,6 +22,9 @@ class Scope(StrEnum):
|
|
12
22
|
def from_str(cls, value: str) -> "Scope":
|
13
23
|
return cls(value)
|
14
24
|
|
25
|
+
# Scopes that can be purchased - these actually exist in the jwt token
|
26
|
+
READ_PREDICTIONS = "read:predictions"
|
27
|
+
|
15
28
|
# Hive scopes
|
16
29
|
READ_HIVE_MODEL = "read:hive:model"
|
17
30
|
READ_HIVE_DATA = "read:hive:data"
|
@@ -40,5 +53,9 @@ class Scope(StrEnum):
|
|
40
53
|
READ_PAY_NOW = "read:pay:now"
|
41
54
|
WRITE_PAY_NOW = "write:pay:now"
|
42
55
|
|
43
|
-
#
|
44
|
-
|
56
|
+
# Metrics scopes
|
57
|
+
READ_METRICS_MARKETCAP = "read:metrics:marketcap"
|
58
|
+
READ_METRICS_INDICATORS = "read:metrics:indicators"
|
59
|
+
READ_METRICS_EXCHANGES = "read:metrics:exchanges"
|
60
|
+
READ_METRICS_TOKENS = "read:metrics:tokens"
|
61
|
+
READ_METRICS_MARKETS = "read:metrics:markets"
|
@@ -39,7 +39,6 @@ from crypticorn.trade.client.exceptions import ApiAttributeError
|
|
39
39
|
from crypticorn.trade.client.exceptions import ApiException
|
40
40
|
|
41
41
|
# import models into sdk package
|
42
|
-
from crypticorn.trade.client.models.api_key_model import APIKeyModel
|
43
42
|
from crypticorn.trade.client.models.action_model import ActionModel
|
44
43
|
from crypticorn.trade.client.models.api_error_identifier import ApiErrorIdentifier
|
45
44
|
from crypticorn.trade.client.models.api_error_level import ApiErrorLevel
|
@@ -47,6 +46,7 @@ from crypticorn.trade.client.models.api_error_type import ApiErrorType
|
|
47
46
|
from crypticorn.trade.client.models.bot_model import BotModel
|
48
47
|
from crypticorn.trade.client.models.bot_status import BotStatus
|
49
48
|
from crypticorn.trade.client.models.exchange import Exchange
|
49
|
+
from crypticorn.trade.client.models.exchange_key_model import ExchangeKeyModel
|
50
50
|
from crypticorn.trade.client.models.execution_ids import ExecutionIds
|
51
51
|
from crypticorn.trade.client.models.futures_balance import FuturesBalance
|
52
52
|
from crypticorn.trade.client.models.futures_trading_action import FuturesTradingAction
|
@@ -18,7 +18,7 @@ from typing_extensions import Annotated
|
|
18
18
|
|
19
19
|
from pydantic import StrictInt, StrictStr
|
20
20
|
from typing import Any, List, Optional
|
21
|
-
from crypticorn.trade.client.models.
|
21
|
+
from crypticorn.trade.client.models.exchange_key_model import ExchangeKeyModel
|
22
22
|
|
23
23
|
from crypticorn.trade.client.api_client import ApiClient, RequestSerialized
|
24
24
|
from crypticorn.trade.client.api_response import ApiResponse
|
@@ -40,7 +40,7 @@ class APIKeysApi:
|
|
40
40
|
@validate_call
|
41
41
|
async def create_exchange_key(
|
42
42
|
self,
|
43
|
-
|
43
|
+
exchange_key_model: ExchangeKeyModel,
|
44
44
|
_request_timeout: Union[
|
45
45
|
None,
|
46
46
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -56,8 +56,8 @@ class APIKeysApi:
|
|
56
56
|
"""Post Exchange Key
|
57
57
|
|
58
58
|
|
59
|
-
:param
|
60
|
-
:type
|
59
|
+
:param exchange_key_model: (required)
|
60
|
+
:type exchange_key_model: ExchangeKeyModel
|
61
61
|
:param _request_timeout: timeout setting for this request. If one
|
62
62
|
number provided, it will be total request
|
63
63
|
timeout. It can also be a pair (tuple) of
|
@@ -81,7 +81,7 @@ class APIKeysApi:
|
|
81
81
|
""" # noqa: E501
|
82
82
|
|
83
83
|
_param = self._create_exchange_key_serialize(
|
84
|
-
|
84
|
+
exchange_key_model=exchange_key_model,
|
85
85
|
_request_auth=_request_auth,
|
86
86
|
_content_type=_content_type,
|
87
87
|
_headers=_headers,
|
@@ -104,7 +104,7 @@ class APIKeysApi:
|
|
104
104
|
@validate_call
|
105
105
|
async def create_exchange_key_with_http_info(
|
106
106
|
self,
|
107
|
-
|
107
|
+
exchange_key_model: ExchangeKeyModel,
|
108
108
|
_request_timeout: Union[
|
109
109
|
None,
|
110
110
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -120,8 +120,8 @@ class APIKeysApi:
|
|
120
120
|
"""Post Exchange Key
|
121
121
|
|
122
122
|
|
123
|
-
:param
|
124
|
-
:type
|
123
|
+
:param exchange_key_model: (required)
|
124
|
+
:type exchange_key_model: ExchangeKeyModel
|
125
125
|
:param _request_timeout: timeout setting for this request. If one
|
126
126
|
number provided, it will be total request
|
127
127
|
timeout. It can also be a pair (tuple) of
|
@@ -145,7 +145,7 @@ class APIKeysApi:
|
|
145
145
|
""" # noqa: E501
|
146
146
|
|
147
147
|
_param = self._create_exchange_key_serialize(
|
148
|
-
|
148
|
+
exchange_key_model=exchange_key_model,
|
149
149
|
_request_auth=_request_auth,
|
150
150
|
_content_type=_content_type,
|
151
151
|
_headers=_headers,
|
@@ -168,7 +168,7 @@ class APIKeysApi:
|
|
168
168
|
@validate_call
|
169
169
|
async def create_exchange_key_without_preload_content(
|
170
170
|
self,
|
171
|
-
|
171
|
+
exchange_key_model: ExchangeKeyModel,
|
172
172
|
_request_timeout: Union[
|
173
173
|
None,
|
174
174
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -184,8 +184,8 @@ class APIKeysApi:
|
|
184
184
|
"""Post Exchange Key
|
185
185
|
|
186
186
|
|
187
|
-
:param
|
188
|
-
:type
|
187
|
+
:param exchange_key_model: (required)
|
188
|
+
:type exchange_key_model: ExchangeKeyModel
|
189
189
|
:param _request_timeout: timeout setting for this request. If one
|
190
190
|
number provided, it will be total request
|
191
191
|
timeout. It can also be a pair (tuple) of
|
@@ -209,7 +209,7 @@ class APIKeysApi:
|
|
209
209
|
""" # noqa: E501
|
210
210
|
|
211
211
|
_param = self._create_exchange_key_serialize(
|
212
|
-
|
212
|
+
exchange_key_model=exchange_key_model,
|
213
213
|
_request_auth=_request_auth,
|
214
214
|
_content_type=_content_type,
|
215
215
|
_headers=_headers,
|
@@ -227,7 +227,7 @@ class APIKeysApi:
|
|
227
227
|
|
228
228
|
def _create_exchange_key_serialize(
|
229
229
|
self,
|
230
|
-
|
230
|
+
exchange_key_model,
|
231
231
|
_request_auth,
|
232
232
|
_content_type,
|
233
233
|
_headers,
|
@@ -252,8 +252,8 @@ class APIKeysApi:
|
|
252
252
|
# process the header parameters
|
253
253
|
# process the form parameters
|
254
254
|
# process the body parameter
|
255
|
-
if
|
256
|
-
_body_params =
|
255
|
+
if exchange_key_model is not None:
|
256
|
+
_body_params = exchange_key_model
|
257
257
|
|
258
258
|
# set the HTTP header `Accept`
|
259
259
|
if "Accept" not in _header_params:
|
@@ -546,7 +546,7 @@ class APIKeysApi:
|
|
546
546
|
_content_type: Optional[StrictStr] = None,
|
547
547
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
548
548
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
549
|
-
) ->
|
549
|
+
) -> ExchangeKeyModel:
|
550
550
|
"""Get Exchange Key By Id
|
551
551
|
|
552
552
|
|
@@ -583,7 +583,7 @@ class APIKeysApi:
|
|
583
583
|
)
|
584
584
|
|
585
585
|
_response_types_map: Dict[str, Optional[str]] = {
|
586
|
-
"200": "
|
586
|
+
"200": "ExchangeKeyModel",
|
587
587
|
"422": "HTTPValidationError",
|
588
588
|
}
|
589
589
|
response_data = await self.api_client.call_api(
|
@@ -610,7 +610,7 @@ class APIKeysApi:
|
|
610
610
|
_content_type: Optional[StrictStr] = None,
|
611
611
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
612
612
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
613
|
-
) -> ApiResponse[
|
613
|
+
) -> ApiResponse[ExchangeKeyModel]:
|
614
614
|
"""Get Exchange Key By Id
|
615
615
|
|
616
616
|
|
@@ -647,7 +647,7 @@ class APIKeysApi:
|
|
647
647
|
)
|
648
648
|
|
649
649
|
_response_types_map: Dict[str, Optional[str]] = {
|
650
|
-
"200": "
|
650
|
+
"200": "ExchangeKeyModel",
|
651
651
|
"422": "HTTPValidationError",
|
652
652
|
}
|
653
653
|
response_data = await self.api_client.call_api(
|
@@ -711,7 +711,7 @@ class APIKeysApi:
|
|
711
711
|
)
|
712
712
|
|
713
713
|
_response_types_map: Dict[str, Optional[str]] = {
|
714
|
-
"200": "
|
714
|
+
"200": "ExchangeKeyModel",
|
715
715
|
"422": "HTTPValidationError",
|
716
716
|
}
|
717
717
|
response_data = await self.api_client.call_api(
|
@@ -789,7 +789,7 @@ class APIKeysApi:
|
|
789
789
|
_content_type: Optional[StrictStr] = None,
|
790
790
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
791
791
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
792
|
-
) -> List[
|
792
|
+
) -> List[ExchangeKeyModel]:
|
793
793
|
"""Get Exchange Keys
|
794
794
|
|
795
795
|
|
@@ -829,7 +829,7 @@ class APIKeysApi:
|
|
829
829
|
)
|
830
830
|
|
831
831
|
_response_types_map: Dict[str, Optional[str]] = {
|
832
|
-
"200": "List[
|
832
|
+
"200": "List[ExchangeKeyModel]",
|
833
833
|
"422": "HTTPValidationError",
|
834
834
|
}
|
835
835
|
response_data = await self.api_client.call_api(
|
@@ -857,7 +857,7 @@ class APIKeysApi:
|
|
857
857
|
_content_type: Optional[StrictStr] = None,
|
858
858
|
_headers: Optional[Dict[StrictStr, Any]] = None,
|
859
859
|
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
860
|
-
) -> ApiResponse[List[
|
860
|
+
) -> ApiResponse[List[ExchangeKeyModel]]:
|
861
861
|
"""Get Exchange Keys
|
862
862
|
|
863
863
|
|
@@ -897,7 +897,7 @@ class APIKeysApi:
|
|
897
897
|
)
|
898
898
|
|
899
899
|
_response_types_map: Dict[str, Optional[str]] = {
|
900
|
-
"200": "List[
|
900
|
+
"200": "List[ExchangeKeyModel]",
|
901
901
|
"422": "HTTPValidationError",
|
902
902
|
}
|
903
903
|
response_data = await self.api_client.call_api(
|
@@ -965,7 +965,7 @@ class APIKeysApi:
|
|
965
965
|
)
|
966
966
|
|
967
967
|
_response_types_map: Dict[str, Optional[str]] = {
|
968
|
-
"200": "List[
|
968
|
+
"200": "List[ExchangeKeyModel]",
|
969
969
|
"422": "HTTPValidationError",
|
970
970
|
}
|
971
971
|
response_data = await self.api_client.call_api(
|
@@ -1038,7 +1038,7 @@ class APIKeysApi:
|
|
1038
1038
|
async def update_exchange_key(
|
1039
1039
|
self,
|
1040
1040
|
id: StrictStr,
|
1041
|
-
|
1041
|
+
exchange_key_model: ExchangeKeyModel,
|
1042
1042
|
_request_timeout: Union[
|
1043
1043
|
None,
|
1044
1044
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -1056,8 +1056,8 @@ class APIKeysApi:
|
|
1056
1056
|
|
1057
1057
|
:param id: (required)
|
1058
1058
|
:type id: str
|
1059
|
-
:param
|
1060
|
-
:type
|
1059
|
+
:param exchange_key_model: (required)
|
1060
|
+
:type exchange_key_model: ExchangeKeyModel
|
1061
1061
|
:param _request_timeout: timeout setting for this request. If one
|
1062
1062
|
number provided, it will be total request
|
1063
1063
|
timeout. It can also be a pair (tuple) of
|
@@ -1082,7 +1082,7 @@ class APIKeysApi:
|
|
1082
1082
|
|
1083
1083
|
_param = self._update_exchange_key_serialize(
|
1084
1084
|
id=id,
|
1085
|
-
|
1085
|
+
exchange_key_model=exchange_key_model,
|
1086
1086
|
_request_auth=_request_auth,
|
1087
1087
|
_content_type=_content_type,
|
1088
1088
|
_headers=_headers,
|
@@ -1106,7 +1106,7 @@ class APIKeysApi:
|
|
1106
1106
|
async def update_exchange_key_with_http_info(
|
1107
1107
|
self,
|
1108
1108
|
id: StrictStr,
|
1109
|
-
|
1109
|
+
exchange_key_model: ExchangeKeyModel,
|
1110
1110
|
_request_timeout: Union[
|
1111
1111
|
None,
|
1112
1112
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -1124,8 +1124,8 @@ class APIKeysApi:
|
|
1124
1124
|
|
1125
1125
|
:param id: (required)
|
1126
1126
|
:type id: str
|
1127
|
-
:param
|
1128
|
-
:type
|
1127
|
+
:param exchange_key_model: (required)
|
1128
|
+
:type exchange_key_model: ExchangeKeyModel
|
1129
1129
|
:param _request_timeout: timeout setting for this request. If one
|
1130
1130
|
number provided, it will be total request
|
1131
1131
|
timeout. It can also be a pair (tuple) of
|
@@ -1150,7 +1150,7 @@ class APIKeysApi:
|
|
1150
1150
|
|
1151
1151
|
_param = self._update_exchange_key_serialize(
|
1152
1152
|
id=id,
|
1153
|
-
|
1153
|
+
exchange_key_model=exchange_key_model,
|
1154
1154
|
_request_auth=_request_auth,
|
1155
1155
|
_content_type=_content_type,
|
1156
1156
|
_headers=_headers,
|
@@ -1174,7 +1174,7 @@ class APIKeysApi:
|
|
1174
1174
|
async def update_exchange_key_without_preload_content(
|
1175
1175
|
self,
|
1176
1176
|
id: StrictStr,
|
1177
|
-
|
1177
|
+
exchange_key_model: ExchangeKeyModel,
|
1178
1178
|
_request_timeout: Union[
|
1179
1179
|
None,
|
1180
1180
|
Annotated[StrictFloat, Field(gt=0)],
|
@@ -1192,8 +1192,8 @@ class APIKeysApi:
|
|
1192
1192
|
|
1193
1193
|
:param id: (required)
|
1194
1194
|
:type id: str
|
1195
|
-
:param
|
1196
|
-
:type
|
1195
|
+
:param exchange_key_model: (required)
|
1196
|
+
:type exchange_key_model: ExchangeKeyModel
|
1197
1197
|
:param _request_timeout: timeout setting for this request. If one
|
1198
1198
|
number provided, it will be total request
|
1199
1199
|
timeout. It can also be a pair (tuple) of
|
@@ -1218,7 +1218,7 @@ class APIKeysApi:
|
|
1218
1218
|
|
1219
1219
|
_param = self._update_exchange_key_serialize(
|
1220
1220
|
id=id,
|
1221
|
-
|
1221
|
+
exchange_key_model=exchange_key_model,
|
1222
1222
|
_request_auth=_request_auth,
|
1223
1223
|
_content_type=_content_type,
|
1224
1224
|
_headers=_headers,
|
@@ -1237,7 +1237,7 @@ class APIKeysApi:
|
|
1237
1237
|
def _update_exchange_key_serialize(
|
1238
1238
|
self,
|
1239
1239
|
id,
|
1240
|
-
|
1240
|
+
exchange_key_model,
|
1241
1241
|
_request_auth,
|
1242
1242
|
_content_type,
|
1243
1243
|
_headers,
|
@@ -1264,8 +1264,8 @@ class APIKeysApi:
|
|
1264
1264
|
# process the header parameters
|
1265
1265
|
# process the form parameters
|
1266
1266
|
# process the body parameter
|
1267
|
-
if
|
1268
|
-
_body_params =
|
1267
|
+
if exchange_key_model is not None:
|
1268
|
+
_body_params = exchange_key_model
|
1269
1269
|
|
1270
1270
|
# set the HTTP header `Accept`
|
1271
1271
|
if "Accept" not in _header_params:
|
@@ -14,7 +14,6 @@
|
|
14
14
|
|
15
15
|
|
16
16
|
# import models into model package
|
17
|
-
from crypticorn.trade.client.models.api_key_model import APIKeyModel
|
18
17
|
from crypticorn.trade.client.models.action_model import ActionModel
|
19
18
|
from crypticorn.trade.client.models.api_error_identifier import ApiErrorIdentifier
|
20
19
|
from crypticorn.trade.client.models.api_error_level import ApiErrorLevel
|
@@ -22,6 +21,7 @@ from crypticorn.trade.client.models.api_error_type import ApiErrorType
|
|
22
21
|
from crypticorn.trade.client.models.bot_model import BotModel
|
23
22
|
from crypticorn.trade.client.models.bot_status import BotStatus
|
24
23
|
from crypticorn.trade.client.models.exchange import Exchange
|
24
|
+
from crypticorn.trade.client.models.exchange_key_model import ExchangeKeyModel
|
25
25
|
from crypticorn.trade.client.models.execution_ids import ExecutionIds
|
26
26
|
from crypticorn.trade.client.models.futures_balance import FuturesBalance
|
27
27
|
from crypticorn.trade.client.models.futures_trading_action import FuturesTradingAction
|
@@ -26,7 +26,8 @@ class ApiErrorIdentifier(str, Enum):
|
|
26
26
|
"""
|
27
27
|
allowed enum values
|
28
28
|
"""
|
29
|
-
|
29
|
+
ALLOCATION_BELOW_CURRENT_EXPOSURE = "allocation_below_current_exposure"
|
30
|
+
ALLOCATION_BELOW_MIN_AMOUNT = "allocation_below_min_amount"
|
30
31
|
BLACK_SWAN = "black_swan"
|
31
32
|
BOT_ALREADY_DELETED = "bot_already_deleted"
|
32
33
|
BOT_DISABLED = "bot_disabled"
|
@@ -34,12 +35,16 @@ class ApiErrorIdentifier(str, Enum):
|
|
34
35
|
CLIENT_ORDER_ID_ALREADY_EXISTS = "client_order_id_already_exists"
|
35
36
|
INVALID_CONTENT_TYPE = "invalid_content_type"
|
36
37
|
DELETE_BOT_ERROR = "delete_bot_error"
|
37
|
-
EXCHANGE_API_KEY_IN_USE = "exchange_api_key_in_use"
|
38
38
|
EXCHANGE_INVALID_SIGNATURE = "exchange_invalid_signature"
|
39
39
|
EXCHANGE_INVALID_TIMESTAMP = "exchange_invalid_timestamp"
|
40
40
|
EXCHANGE_IP_ADDRESS_IS_NOT_AUTHORIZED = "exchange_ip_address_is_not_authorized"
|
41
|
+
EXCHANGE_KEY_ALREADY_EXISTS = "exchange_key_already_exists"
|
42
|
+
EXCHANGE_KEY_IN_USE = "exchange_key_in_use"
|
41
43
|
EXCHANGE_SYSTEM_UNDER_MAINTENANCE = "exchange_system_under_maintenance"
|
42
44
|
EXCHANGE_RATE_LIMIT_EXCEEDED = "exchange_rate_limit_exceeded"
|
45
|
+
INSUFFICIENT_PERMISSIONS_SPOT_AND_FUTURES_REQUIRED = (
|
46
|
+
"insufficient_permissions_spot_and_futures_required"
|
47
|
+
)
|
43
48
|
EXCHANGE_SERVICE_TEMPORARILY_UNAVAILABLE = (
|
44
49
|
"exchange_service_temporarily_unavailable"
|
45
50
|
)
|
@@ -47,9 +52,6 @@ class ApiErrorIdentifier(str, Enum):
|
|
47
52
|
EXCHANGE_SYSTEM_CONFIGURATION_ERROR = "exchange_system_configuration_error"
|
48
53
|
EXCHANGE_INTERNAL_SYSTEM_ERROR = "exchange_internal_system_error"
|
49
54
|
EXCHANGE_USER_ACCOUNT_IS_FROZEN = "exchange_user_account_is_frozen"
|
50
|
-
INSUFFICIENT_PERMISSIONS_SPOT_AND_FUTURES_REQUIRED = (
|
51
|
-
"insufficient_permissions_spot_and_futures_required"
|
52
|
-
)
|
53
55
|
HEDGE_MODE_NOT_ACTIVE = "hedge_mode_not_active"
|
54
56
|
HTTP_REQUEST_ERROR = "http_request_error"
|
55
57
|
INSUFFICIENT_BALANCE = "insufficient_balance"
|
@@ -66,6 +68,7 @@ class ApiErrorIdentifier(str, Enum):
|
|
66
68
|
"order_violates_liquidation_price_constraints"
|
67
69
|
)
|
68
70
|
NO_CREDENTIALS = "no_credentials"
|
71
|
+
NOW_API_DOWN = "now_api_down"
|
69
72
|
OBJECT_NOT_FOUND = "object_not_found"
|
70
73
|
ORDER_IS_ALREADY_FILLED = "order_is_already_filled"
|
71
74
|
ORDER_IS_BEING_PROCESSED = "order_is_being_processed"
|
@@ -83,11 +86,13 @@ class ApiErrorIdentifier(str, Enum):
|
|
83
86
|
RPC_TIMEOUT = "rpc_timeout"
|
84
87
|
SYSTEM_SETTLEMENT_IN_PROCESS = "system_settlement_in_process"
|
85
88
|
STRATEGY_DISABLED = "strategy_disabled"
|
89
|
+
STRATEGY_LEVERAGE_MISMATCH = "strategy_leverage_mismatch"
|
90
|
+
STRATEGY_NOT_SUPPORTING_EXCHANGE = "strategy_not_supporting_exchange"
|
86
91
|
SUCCESS = "success"
|
87
92
|
SYMBOL_DOES_NOT_EXIST = "symbol_does_not_exist"
|
88
|
-
TRADING_HAS_BEEN_LOCKED = "trading_has_been_locked"
|
89
93
|
TRADING_ACTION_EXPIRED = "trading_action_expired"
|
90
94
|
TRADING_ACTION_SKIPPED = "trading_action_skipped"
|
95
|
+
TRADING_HAS_BEEN_LOCKED = "trading_has_been_locked"
|
91
96
|
TRADING_IS_SUSPENDED = "trading_is_suspended"
|
92
97
|
UNKNOWN_ERROR_OCCURRED = "unknown_error_occurred"
|
93
98
|
REQUESTED_RESOURCE_NOT_FOUND = "requested_resource_not_found"
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
"""
|
4
|
+
Trading API
|
5
|
+
|
6
|
+
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
7
|
+
|
8
|
+
The version of the OpenAPI document: 0.1.0
|
9
|
+
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
10
|
+
|
11
|
+
Do not edit the class manually.
|
12
|
+
""" # noqa: E501
|
13
|
+
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
import pprint
|
17
|
+
import re # noqa: F401
|
18
|
+
import json
|
19
|
+
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
22
|
+
from typing import Optional, Set
|
23
|
+
from typing_extensions import Self
|
24
|
+
|
25
|
+
|
26
|
+
class ExchangeKeyModel(BaseModel):
|
27
|
+
"""
|
28
|
+
ExchangeKeyModel
|
29
|
+
""" # noqa: E501
|
30
|
+
|
31
|
+
created_at: Optional[StrictInt] = None
|
32
|
+
updated_at: Optional[StrictInt] = None
|
33
|
+
id: Optional[StrictStr] = None
|
34
|
+
exchange: StrictStr = Field(description="Exchange name")
|
35
|
+
api_key: Optional[StrictStr] = None
|
36
|
+
secret: Optional[StrictStr] = None
|
37
|
+
passphrase: Optional[StrictStr] = None
|
38
|
+
label: StrictStr = Field(description="Label for the API key")
|
39
|
+
enabled: Optional[StrictBool] = None
|
40
|
+
user_id: Optional[StrictStr] = None
|
41
|
+
__properties: ClassVar[List[str]] = [
|
42
|
+
"created_at",
|
43
|
+
"updated_at",
|
44
|
+
"id",
|
45
|
+
"exchange",
|
46
|
+
"api_key",
|
47
|
+
"secret",
|
48
|
+
"passphrase",
|
49
|
+
"label",
|
50
|
+
"enabled",
|
51
|
+
"user_id",
|
52
|
+
]
|
53
|
+
|
54
|
+
model_config = ConfigDict(
|
55
|
+
populate_by_name=True,
|
56
|
+
validate_assignment=True,
|
57
|
+
protected_namespaces=(),
|
58
|
+
)
|
59
|
+
|
60
|
+
def to_str(self) -> str:
|
61
|
+
"""Returns the string representation of the model using alias"""
|
62
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
63
|
+
|
64
|
+
def to_json(self) -> str:
|
65
|
+
"""Returns the JSON representation of the model using alias"""
|
66
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
67
|
+
return json.dumps(self.to_dict())
|
68
|
+
|
69
|
+
@classmethod
|
70
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
71
|
+
"""Create an instance of ExchangeKeyModel from a JSON string"""
|
72
|
+
return cls.from_dict(json.loads(json_str))
|
73
|
+
|
74
|
+
def to_dict(self) -> Dict[str, Any]:
|
75
|
+
"""Return the dictionary representation of the model using alias.
|
76
|
+
|
77
|
+
This has the following differences from calling pydantic's
|
78
|
+
`self.model_dump(by_alias=True)`:
|
79
|
+
|
80
|
+
* `None` is only added to the output dict for nullable fields that
|
81
|
+
were set at model initialization. Other fields with value `None`
|
82
|
+
are ignored.
|
83
|
+
"""
|
84
|
+
excluded_fields: Set[str] = set([])
|
85
|
+
|
86
|
+
_dict = self.model_dump(
|
87
|
+
by_alias=True,
|
88
|
+
exclude=excluded_fields,
|
89
|
+
exclude_none=True,
|
90
|
+
)
|
91
|
+
# set to None if created_at (nullable) is None
|
92
|
+
# and model_fields_set contains the field
|
93
|
+
if self.created_at is None and "created_at" in self.model_fields_set:
|
94
|
+
_dict["created_at"] = None
|
95
|
+
|
96
|
+
# set to None if updated_at (nullable) is None
|
97
|
+
# and model_fields_set contains the field
|
98
|
+
if self.updated_at is None and "updated_at" in self.model_fields_set:
|
99
|
+
_dict["updated_at"] = None
|
100
|
+
|
101
|
+
# set to None if id (nullable) is None
|
102
|
+
# and model_fields_set contains the field
|
103
|
+
if self.id is None and "id" in self.model_fields_set:
|
104
|
+
_dict["id"] = None
|
105
|
+
|
106
|
+
# set to None if api_key (nullable) is None
|
107
|
+
# and model_fields_set contains the field
|
108
|
+
if self.api_key is None and "api_key" in self.model_fields_set:
|
109
|
+
_dict["api_key"] = None
|
110
|
+
|
111
|
+
# set to None if secret (nullable) is None
|
112
|
+
# and model_fields_set contains the field
|
113
|
+
if self.secret is None and "secret" in self.model_fields_set:
|
114
|
+
_dict["secret"] = None
|
115
|
+
|
116
|
+
# set to None if passphrase (nullable) is None
|
117
|
+
# and model_fields_set contains the field
|
118
|
+
if self.passphrase is None and "passphrase" in self.model_fields_set:
|
119
|
+
_dict["passphrase"] = None
|
120
|
+
|
121
|
+
# set to None if enabled (nullable) is None
|
122
|
+
# and model_fields_set contains the field
|
123
|
+
if self.enabled is None and "enabled" in self.model_fields_set:
|
124
|
+
_dict["enabled"] = None
|
125
|
+
|
126
|
+
# set to None if user_id (nullable) is None
|
127
|
+
# and model_fields_set contains the field
|
128
|
+
if self.user_id is None and "user_id" in self.model_fields_set:
|
129
|
+
_dict["user_id"] = None
|
130
|
+
|
131
|
+
return _dict
|
132
|
+
|
133
|
+
@classmethod
|
134
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
135
|
+
"""Create an instance of ExchangeKeyModel from a dict"""
|
136
|
+
if obj is None:
|
137
|
+
return None
|
138
|
+
|
139
|
+
if not isinstance(obj, dict):
|
140
|
+
return cls.model_validate(obj)
|
141
|
+
|
142
|
+
_obj = cls.model_validate(
|
143
|
+
{
|
144
|
+
"created_at": obj.get("created_at"),
|
145
|
+
"updated_at": obj.get("updated_at"),
|
146
|
+
"id": obj.get("id"),
|
147
|
+
"exchange": obj.get("exchange"),
|
148
|
+
"api_key": obj.get("api_key"),
|
149
|
+
"secret": obj.get("secret"),
|
150
|
+
"passphrase": obj.get("passphrase"),
|
151
|
+
"label": obj.get("label"),
|
152
|
+
"enabled": obj.get("enabled"),
|
153
|
+
"user_id": obj.get("user_id"),
|
154
|
+
}
|
155
|
+
)
|
156
|
+
return _obj
|
crypticorn/trade/main.py
CHANGED
@@ -33,4 +33,4 @@ class TradeClient:
|
|
33
33
|
self.strategies = StrategiesApi(self.base_client)
|
34
34
|
self.actions = TradingActionsApi(self.base_client)
|
35
35
|
self.futures = FuturesTradingPanelApi(self.base_client)
|
36
|
-
self.
|
36
|
+
self.keys = APIKeysApi(self.base_client)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: crypticorn
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.4.1
|
4
4
|
Summary: Maximise Your Crypto Trading Profits with AI Predictions
|
5
5
|
Author-email: Crypticorn <timon@crypticorn.com>
|
6
6
|
Project-URL: Homepage, https://crypticorn.com
|
@@ -14,6 +14,7 @@ Classifier: Typing :: Typed
|
|
14
14
|
Requires-Python: >=3.10
|
15
15
|
Description-Content-Type: text/markdown
|
16
16
|
Requires-Dist: fastapi
|
17
|
+
Requires-Dist: click
|
17
18
|
Requires-Dist: urllib3<3.0.0,>=1.25.3
|
18
19
|
Requires-Dist: python_dateutil<3.0.0,>=2.8.2
|
19
20
|
Requires-Dist: aiohttp<4.0.0,>=3.8.4
|
@@ -71,6 +72,20 @@ Our API is available as an asynchronous Python SDK. The main entry point you nee
|
|
71
72
|
```python
|
72
73
|
from crypticorn import ApiClient
|
73
74
|
```
|
75
|
+
The ApiClient serves as the central interface for API operations. It instantiates multiple API wrappers corresponding to our microservices.
|
76
|
+
|
77
|
+
Specific imports, such as request models, should be accessed through the appropriate submodules.
|
78
|
+
|
79
|
+
Note: All symbols are re-exported at the first submodule layer for convenience.
|
80
|
+
|
81
|
+
```python
|
82
|
+
from crypticorn.trade import BotStatus
|
83
|
+
```
|
84
|
+
|
85
|
+
The `common` submodule contains shared classes not bound to a specific API.
|
86
|
+
```python
|
87
|
+
from crypticorn.common import Scope, Exchange
|
88
|
+
```
|
74
89
|
|
75
90
|
## Usage
|
76
91
|
|
@@ -121,7 +136,7 @@ On top of that you get some information about the request:
|
|
121
136
|
print(res.status_code)
|
122
137
|
print(res.raw_data)
|
123
138
|
print(res.headers)
|
124
|
-
|
139
|
+
```
|
125
140
|
|
126
141
|
### JSON Response
|
127
142
|
You can receive a classical JSON response by suffixing the function name with `_without_preload_content`
|
@@ -54,12 +54,17 @@ crypticorn/auth/client/models/verify_email_request.py,sha256=8MBfxPTLn5X6Z3vE2bl
|
|
54
54
|
crypticorn/auth/client/models/verify_wallet_request.py,sha256=b0DAocvhKzPXPjM62DZqezlHxq3cNL7UVKl0d2judHQ,2691
|
55
55
|
crypticorn/auth/client/models/wallet_verified200_response.py,sha256=QILnTLsCKdI-WdV_fsLBy1UH4ZZU-U-wWJ9ot8v08tI,2465
|
56
56
|
crypticorn/auth/client/models/whoami200_response.py,sha256=uehdq5epgeOphhrIR3tbrseflxcLAzGyKF-VW-o5cY8,2974
|
57
|
+
crypticorn/cli/__init__.py,sha256=P5wOAU00ylb1uROkv6BmQwnKtSMGMB4HA0utVYxEhu8,68
|
58
|
+
crypticorn/cli/__main__.py,sha256=XujzQmkfLN6zDJ-AiUAUTn8Kq-G3HhQ0y3TaUvs9J1E,250
|
59
|
+
crypticorn/cli/init.py,sha256=n9ldSI5yNYlYTt4jSlOXVSiHBmb2QlE__MYcNkz6Cl0,3321
|
60
|
+
crypticorn/cli/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
|
+
crypticorn/cli/templates/auth.py,sha256=pr4O9ejxEz10QphEjXAtl0qfwLNKHYzLwvNKHs--WUQ,954
|
57
62
|
crypticorn/common/__init__.py,sha256=r--xgeJUW4FGRabb1AyqlEFsySiSNfxO_Qi3uOpZ-xI,231
|
58
63
|
crypticorn/common/auth.py,sha256=5aVNsl39ngsoFaR5xGuWERRccq4HibYbSp61Z4QOVew,7483
|
59
|
-
crypticorn/common/enums.py,sha256=
|
64
|
+
crypticorn/common/enums.py,sha256=OQQT6uaounQzCGoYEM91yjhu8pU2eD5VaYiY8K89k3o,1235
|
60
65
|
crypticorn/common/errors.py,sha256=HZvd4J2HAN7TvqlZxWtp29XV0wbkacWNZzgdVO-YWpw,14197
|
61
66
|
crypticorn/common/pydantic.py,sha256=pmnGYCIrLv59wZkDbvPyK9NJmgPJWW74LXTdIWSjOkY,1063
|
62
|
-
crypticorn/common/scopes.py,sha256=
|
67
|
+
crypticorn/common/scopes.py,sha256=kzCaGRusoYGt_IIPpVQGmvapBGlDmEgdnTQot98x3uE,2133
|
63
68
|
crypticorn/common/sorter.py,sha256=Lx7hZMzsqrx2nqWOO0sFrSXSK1t2CqQJux70xU49Bz0,1282
|
64
69
|
crypticorn/common/urls.py,sha256=X557WaODUqW2dECi-mOjTbmhkSpnp40fPXDdvlnBXfo,805
|
65
70
|
crypticorn/hive/__init__.py,sha256=hRfTlEzEql4msytdUC_04vfaHzVKG5CGZle1M-9QFgY,81
|
@@ -219,8 +224,8 @@ crypticorn/pay/client/models/unified_payment_model.py,sha256=_Y9OtWZ-N7QDxsCte0U
|
|
219
224
|
crypticorn/pay/client/models/validation_error.py,sha256=vzw1GCCSx0Tct-t8b4IfNQe4jaioantmwbwz2Cmi4AA,3226
|
220
225
|
crypticorn/pay/client/models/validation_error_loc_inner.py,sha256=8Fp046J4qWnAIBATnrzS9qiKZKDY4C3UxSOJo9DTTcQ,5131
|
221
226
|
crypticorn/trade/__init__.py,sha256=QzScH9n-ly3QSaBSpPP7EqYwhdzDqYCZJs0-AhEhrsY,84
|
222
|
-
crypticorn/trade/main.py,sha256=
|
223
|
-
crypticorn/trade/client/__init__.py,sha256=
|
227
|
+
crypticorn/trade/main.py,sha256=jn17PsnMp_xKuYic92u2ApytvT71au1cBse5TjgRQdM,1040
|
228
|
+
crypticorn/trade/client/__init__.py,sha256=Xj4_g-RPqLUqSJ7QTjWfrHvS5_hVtbEUauzom0XGBBs,3490
|
224
229
|
crypticorn/trade/client/api_client.py,sha256=GZFlYDIxGpPWtK6CnTqZLN8kWSSSzcdziNY4kTB1hE4,26956
|
225
230
|
crypticorn/trade/client/api_response.py,sha256=WhxwYDSMm6wPixp9CegO8dJzjFxDz3JF1yCq9s0ZqKE,639
|
226
231
|
crypticorn/trade/client/configuration.py,sha256=Ih111_59QLT7CWHdE3L_5GRuw5ie0gx5mlu2Nyqu8Lc,18841
|
@@ -228,7 +233,7 @@ crypticorn/trade/client/exceptions.py,sha256=xSXlQpvCm5JkPI_N49jdTm72mSHMLOIDQ3g
|
|
228
233
|
crypticorn/trade/client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
229
234
|
crypticorn/trade/client/rest.py,sha256=o2sJyURJxO3XckjU_VuASM5AN0R5TsRcH1vtKCR97oI,6987
|
230
235
|
crypticorn/trade/client/api/__init__.py,sha256=s6jcukWHyom8Bp9Vj0yrOL37-dNPNvdvMK_aXwpKZzc,668
|
231
|
-
crypticorn/trade/client/api/api_keys_api.py,sha256=
|
236
|
+
crypticorn/trade/client/api/api_keys_api.py,sha256=pMMXtKi8E7XKHUAqXpMoHHLWfN7YrO-5kdA4Lm5go0M,51412
|
232
237
|
crypticorn/trade/client/api/bots_api.py,sha256=Ebd6741ucf4PGKZchmvxd0QFc_Nm4lj8wQeAbFuCvyg,41988
|
233
238
|
crypticorn/trade/client/api/exchanges_api.py,sha256=PX8yeVZFDWxmsortW0HdphbNtYRYWaLv8nkE8VUmPgg,10166
|
234
239
|
crypticorn/trade/client/api/futures_trading_panel_api.py,sha256=xOxjCqg2o0exmQofO4l65LVFTOLHC8YBbVNzcyyBou0,50581
|
@@ -237,21 +242,22 @@ crypticorn/trade/client/api/orders_api.py,sha256=zibuEr3448IefONOEcgti06nxNtJCvi
|
|
237
242
|
crypticorn/trade/client/api/status_api.py,sha256=deaW23XWpUMqhFzxO9GqT0MI8ZlAIC_f4ewdPLExBMw,9934
|
238
243
|
crypticorn/trade/client/api/strategies_api.py,sha256=asNtn8mZDTRu36PGGGHLRtevQ3NFs-6nQ1XRju2xSaU,42444
|
239
244
|
crypticorn/trade/client/api/trading_actions_api.py,sha256=BfW61jUsOZxhzcYgLLF19hGeSHElarxUeK1Re0q_wpY,32402
|
240
|
-
crypticorn/trade/client/models/__init__.py,sha256=
|
245
|
+
crypticorn/trade/client/models/__init__.py,sha256=pYftF6baXUaReQDn54rRln4KljNnN4nbbJqedqW1XaU,2244
|
241
246
|
crypticorn/trade/client/models/action_model.py,sha256=W-6IJl9KgeiBkZc95HH9kdvmmb-vzYtJ-HfKN0YzC_U,10131
|
242
|
-
crypticorn/trade/client/models/api_error_identifier.py,sha256=
|
247
|
+
crypticorn/trade/client/models/api_error_identifier.py,sha256=kwCKzYwf61WSiscwNHjNFtsX8fzJDJoOT9vZYO2dLxk,4448
|
243
248
|
crypticorn/trade/client/models/api_error_level.py,sha256=78zYTqbnUGvbjptf04e6-bpF8nN-YWqGxjGrdwNe4_4,799
|
244
249
|
crypticorn/trade/client/models/api_error_type.py,sha256=ANXQ3lPxQ9Jyh_-Q4ljHFHt5uH6ljBHPzK7SDy7etek,840
|
245
250
|
crypticorn/trade/client/models/api_key_model.py,sha256=CM6BeEc3ctmfLMnRht-_k_WDCjGWreOI7670h4KhhAM,5281
|
246
251
|
crypticorn/trade/client/models/bot_model.py,sha256=t1VetjZs20-ekukHlwBaOwvMiDuZ3-hjQa1V6iaUYtE,5875
|
247
252
|
crypticorn/trade/client/models/bot_status.py,sha256=p0oRXdqjqDwE1mcHjWjUwqqmWGIi1jTFWi8FgwArUOg,796
|
248
|
-
crypticorn/trade/client/models/exchange.py,sha256=
|
253
|
+
crypticorn/trade/client/models/exchange.py,sha256=jRDYT8x47bfWa394pXBavpArL3i8IoyTZK7i5UX6dFg,760
|
254
|
+
crypticorn/trade/client/models/exchange_key_model.py,sha256=-ELnZDj2zp--GJcX3pegG92lLpFAm2MGrSE-AYmtneY,5301
|
249
255
|
crypticorn/trade/client/models/execution_ids.py,sha256=7EO_v4LErOlLVbTCL412ST0GpstJOcn2A3zAA04VC6w,2876
|
250
256
|
crypticorn/trade/client/models/futures_balance.py,sha256=JAUaPUkV0AlQZxrlOtpqkd6HOP4jkdpYZ6gyvGbAmG8,4181
|
251
257
|
crypticorn/trade/client/models/futures_trading_action.py,sha256=aRXn0NeziJ_TuYvPsRWsBekWZiXvI7ZJoq-NXtoW_40,9498
|
252
258
|
crypticorn/trade/client/models/http_validation_error.py,sha256=7rSmsYpBLuxIkCgl2pM-U3jCLeRSAX4s9s1CzsdE_1s,3118
|
253
259
|
crypticorn/trade/client/models/margin_mode.py,sha256=Y02aSytOfvROKDZHrdD2xHOCDbW6tT9YL3fNkDyGIus,767
|
254
|
-
crypticorn/trade/client/models/market_type.py,sha256=
|
260
|
+
crypticorn/trade/client/models/market_type.py,sha256=u4oa-sYI6AdnQp-JnNPCNKCkdC3ppzvndrdLscDuIf8,745
|
255
261
|
crypticorn/trade/client/models/notification_model.py,sha256=pZc15SJRWPxGWjrKyEtJFLbBEPe-hBvQX9bOOjFeGQg,5010
|
256
262
|
crypticorn/trade/client/models/order_model.py,sha256=uAP7WxfiNpqV4qdX0UZxjKf70WaelEAVDJlgVTonc3M,12682
|
257
263
|
crypticorn/trade/client/models/order_status.py,sha256=cCS3aGJmqqVhoZ1JfLS-DeRj5qj-D82AI5OFblhAsik,842
|
@@ -263,7 +269,8 @@ crypticorn/trade/client/models/tpsl.py,sha256=QGPhcgadjxAgyzpRSwlZJg_CDLnKxdZgse
|
|
263
269
|
crypticorn/trade/client/models/trading_action_type.py,sha256=jW0OsNz_ZNXlITxAfh979BH5U12oTXSr6qUVcKcGHhw,847
|
264
270
|
crypticorn/trade/client/models/validation_error.py,sha256=uTkvsKrOAt-21UC0YPqCdRl_OMsuu7uhPtWuwRSYvv0,3228
|
265
271
|
crypticorn/trade/client/models/validation_error_loc_inner.py,sha256=22ql-H829xTBgfxNQZsqd8fS3zQt9tLW1pj0iobo0jY,5131
|
266
|
-
crypticorn-2.
|
267
|
-
crypticorn-2.
|
268
|
-
crypticorn-2.
|
269
|
-
crypticorn-2.
|
272
|
+
crypticorn-2.4.1.dist-info/METADATA,sha256=5IBnH4H9R_BsBIiHgeXyFpyK47_X3i2inHZsZ08Z4eE,5927
|
273
|
+
crypticorn-2.4.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
274
|
+
crypticorn-2.4.1.dist-info/entry_points.txt,sha256=d_xHsGvUTebPveVUK0SrpDFQ5ZRSjlI7lNCc11sn2PM,59
|
275
|
+
crypticorn-2.4.1.dist-info/top_level.txt,sha256=EP3NY216qIBYfmvGl0L2Zc9ItP0DjGSkiYqd9xJwGcM,11
|
276
|
+
crypticorn-2.4.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|