crypticorn 2.17.0rc1__py3-none-any.whl → 2.17.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 +2 -2
- crypticorn/auth/client/api/admin_api.py +415 -13
- crypticorn/auth/client/api/auth_api.py +2622 -113
- crypticorn/auth/client/api/service_api.py +258 -7
- crypticorn/auth/client/api/user_api.py +2485 -270
- crypticorn/auth/client/api/wallet_api.py +1518 -77
- crypticorn/auth/client/models/create_api_key_request.py +2 -1
- crypticorn/auth/client/models/get_api_keys200_response_inner.py +2 -1
- crypticorn/auth/client/rest.py +23 -4
- crypticorn/auth/main.py +8 -5
- crypticorn/client.py +227 -59
- crypticorn/common/__init__.py +0 -1
- crypticorn/common/metrics.py +4 -6
- crypticorn/common/middleware.py +10 -5
- crypticorn/common/pagination.py +137 -18
- crypticorn/common/router/admin_router.py +1 -1
- crypticorn/common/utils.py +2 -1
- crypticorn/common/warnings.py +1 -0
- crypticorn/hive/client/api/admin_api.py +1234 -51
- crypticorn/hive/client/api/data_api.py +517 -13
- crypticorn/hive/client/api/models_api.py +1657 -83
- crypticorn/hive/client/api/status_api.py +415 -13
- crypticorn/hive/client/models/api_error_identifier.py +1 -1
- crypticorn/hive/client/rest.py +23 -4
- crypticorn/hive/main.py +99 -25
- crypticorn/klines/client/api/admin_api.py +1234 -51
- crypticorn/klines/client/api/change_in_timeframe_api.py +278 -7
- crypticorn/klines/client/api/funding_rates_api.py +324 -7
- crypticorn/klines/client/api/ohlcv_data_api.py +399 -7
- crypticorn/klines/client/api/status_api.py +415 -13
- crypticorn/klines/client/api/symbols_api.py +225 -7
- crypticorn/klines/client/api/udf_api.py +1393 -120
- crypticorn/klines/client/models/api_error_identifier.py +3 -1
- crypticorn/klines/client/rest.py +23 -4
- crypticorn/klines/main.py +89 -12
- crypticorn/metrics/client/api/admin_api.py +1234 -51
- crypticorn/metrics/client/api/exchanges_api.py +1405 -140
- crypticorn/metrics/client/api/indicators_api.py +640 -13
- crypticorn/metrics/client/api/logs_api.py +305 -7
- crypticorn/metrics/client/api/marketcap_api.py +1240 -60
- crypticorn/metrics/client/api/markets_api.py +352 -7
- crypticorn/metrics/client/api/quote_currencies_api.py +237 -7
- crypticorn/metrics/client/api/status_api.py +415 -13
- crypticorn/metrics/client/api/tokens_api.py +400 -13
- crypticorn/metrics/client/configuration.py +4 -2
- crypticorn/metrics/client/rest.py +23 -4
- crypticorn/metrics/main.py +113 -19
- crypticorn/pay/client/api/admin_api.py +1720 -126
- crypticorn/pay/client/api/now_payments_api.py +1013 -42
- crypticorn/pay/client/api/payments_api.py +580 -13
- crypticorn/pay/client/api/products_api.py +915 -25
- crypticorn/pay/client/api/status_api.py +415 -13
- crypticorn/pay/client/configuration.py +2 -2
- crypticorn/pay/client/models/api_error_identifier.py +7 -7
- crypticorn/pay/client/models/scope.py +1 -0
- crypticorn/pay/client/rest.py +23 -4
- crypticorn/pay/main.py +10 -6
- crypticorn/trade/client/__init__.py +2 -1
- crypticorn/trade/client/api/__init__.py +0 -1
- crypticorn/trade/client/api/admin_api.py +1718 -123
- crypticorn/trade/client/api/api_keys_api.py +1596 -103
- crypticorn/trade/client/api/bots_api.py +1106 -47
- crypticorn/trade/client/api/exchanges_api.py +592 -19
- crypticorn/trade/client/api/notifications_api.py +1340 -112
- crypticorn/trade/client/api/orders_api.py +240 -7
- crypticorn/trade/client/api/status_api.py +415 -13
- crypticorn/trade/client/api/strategies_api.py +1170 -69
- crypticorn/trade/client/api/trading_actions_api.py +650 -19
- crypticorn/trade/client/models/__init__.py +2 -0
- crypticorn/trade/client/models/exchange.py +6 -1
- crypticorn/trade/client/models/exchange_key_balance.py +111 -0
- crypticorn/trade/client/models/futures_balance.py +27 -25
- crypticorn/trade/client/models/spot_balance.py +110 -0
- crypticorn/trade/client/models/strategy.py +5 -3
- crypticorn/trade/client/models/strategy_create.py +6 -4
- crypticorn/trade/client/models/strategy_exchange_info.py +16 -4
- crypticorn/trade/client/models/strategy_update.py +2 -2
- crypticorn/trade/client/rest.py +23 -4
- crypticorn/trade/main.py +15 -12
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/METADATA +64 -20
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/RECORD +85 -84
- crypticorn/trade/client/api/futures_trading_panel_api.py +0 -1285
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/WHEEL +0 -0
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/entry_points.txt +0 -0
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/licenses/LICENSE +0 -0
- {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc2.dist-info}/top_level.txt +0 -0
@@ -24,6 +24,7 @@ from crypticorn.trade.client.models.bot_update import BotUpdate
|
|
24
24
|
from crypticorn.trade.client.models.exception_detail import ExceptionDetail
|
25
25
|
from crypticorn.trade.client.models.exchange import Exchange
|
26
26
|
from crypticorn.trade.client.models.exchange_key import ExchangeKey
|
27
|
+
from crypticorn.trade.client.models.exchange_key_balance import ExchangeKeyBalance
|
27
28
|
from crypticorn.trade.client.models.exchange_key_create import ExchangeKeyCreate
|
28
29
|
from crypticorn.trade.client.models.exchange_key_update import ExchangeKeyUpdate
|
29
30
|
from crypticorn.trade.client.models.execution_ids import ExecutionIds
|
@@ -41,6 +42,7 @@ from crypticorn.trade.client.models.notification_update import NotificationUpdat
|
|
41
42
|
from crypticorn.trade.client.models.order import Order
|
42
43
|
from crypticorn.trade.client.models.order_status import OrderStatus
|
43
44
|
from crypticorn.trade.client.models.post_futures_action import PostFuturesAction
|
45
|
+
from crypticorn.trade.client.models.spot_balance import SpotBalance
|
44
46
|
from crypticorn.trade.client.models.spot_trading_action_create import (
|
45
47
|
SpotTradingActionCreate,
|
46
48
|
)
|
@@ -20,7 +20,7 @@ from typing_extensions import Self
|
|
20
20
|
|
21
21
|
class Exchange(str, Enum):
|
22
22
|
"""
|
23
|
-
|
23
|
+
All exchanges used in the crypticorn ecosystem. Refer to the APIs for support for a specific usecase (data, trading, etc.).
|
24
24
|
"""
|
25
25
|
|
26
26
|
"""
|
@@ -28,7 +28,12 @@ class Exchange(str, Enum):
|
|
28
28
|
"""
|
29
29
|
KUCOIN = "kucoin"
|
30
30
|
BINGX = "bingx"
|
31
|
+
BINANCE = "binance"
|
32
|
+
BYBIT = "bybit"
|
31
33
|
HYPERLIQUID = "hyperliquid"
|
34
|
+
BITGET = "bitget"
|
35
|
+
GATEIO = "gateio"
|
36
|
+
BITSTAMP = "bitstamp"
|
32
37
|
|
33
38
|
@classmethod
|
34
39
|
def from_json(cls, json_str: str) -> Self:
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
"""
|
4
|
+
Trading API
|
5
|
+
|
6
|
+
API for automated trading and exchange interface. This API is used to trade on the exchange and manage bots, API keys, orders, and more.
|
7
|
+
|
8
|
+
The version of the OpenAPI document: 1.0.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, StrictStr
|
21
|
+
from typing import Any, ClassVar, Dict, List
|
22
|
+
from crypticorn.trade.client.models.futures_balance import FuturesBalance
|
23
|
+
from crypticorn.trade.client.models.spot_balance import SpotBalance
|
24
|
+
from typing import Optional, Set
|
25
|
+
from typing_extensions import Self
|
26
|
+
|
27
|
+
|
28
|
+
class ExchangeKeyBalance(BaseModel):
|
29
|
+
"""
|
30
|
+
ExchangeKeyBalance
|
31
|
+
""" # noqa: E501
|
32
|
+
|
33
|
+
api_key_id: StrictStr = Field(description="API key ID.")
|
34
|
+
futures: FuturesBalance = Field(description="Futures balance information.")
|
35
|
+
spot: List[SpotBalance] = Field(description="Spot balance information.")
|
36
|
+
__properties: ClassVar[List[str]] = ["api_key_id", "futures", "spot"]
|
37
|
+
|
38
|
+
model_config = ConfigDict(
|
39
|
+
populate_by_name=True,
|
40
|
+
validate_assignment=True,
|
41
|
+
protected_namespaces=(),
|
42
|
+
)
|
43
|
+
|
44
|
+
def to_str(self) -> str:
|
45
|
+
"""Returns the string representation of the model using alias"""
|
46
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
47
|
+
|
48
|
+
def to_json(self) -> str:
|
49
|
+
"""Returns the JSON representation of the model using alias"""
|
50
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
51
|
+
return json.dumps(self.to_dict())
|
52
|
+
|
53
|
+
@classmethod
|
54
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
55
|
+
"""Create an instance of ExchangeKeyBalance from a JSON string"""
|
56
|
+
return cls.from_dict(json.loads(json_str))
|
57
|
+
|
58
|
+
def to_dict(self) -> Dict[str, Any]:
|
59
|
+
"""Return the dictionary representation of the model using alias.
|
60
|
+
|
61
|
+
This has the following differences from calling pydantic's
|
62
|
+
`self.model_dump(by_alias=True)`:
|
63
|
+
|
64
|
+
* `None` is only added to the output dict for nullable fields that
|
65
|
+
were set at model initialization. Other fields with value `None`
|
66
|
+
are ignored.
|
67
|
+
"""
|
68
|
+
excluded_fields: Set[str] = set([])
|
69
|
+
|
70
|
+
_dict = self.model_dump(
|
71
|
+
by_alias=True,
|
72
|
+
exclude=excluded_fields,
|
73
|
+
exclude_none=True,
|
74
|
+
)
|
75
|
+
# override the default output from pydantic by calling `to_dict()` of futures
|
76
|
+
if self.futures:
|
77
|
+
_dict["futures"] = self.futures.to_dict()
|
78
|
+
# override the default output from pydantic by calling `to_dict()` of each item in spot (list)
|
79
|
+
_items = []
|
80
|
+
if self.spot:
|
81
|
+
for _item_spot in self.spot:
|
82
|
+
if _item_spot:
|
83
|
+
_items.append(_item_spot.to_dict())
|
84
|
+
_dict["spot"] = _items
|
85
|
+
return _dict
|
86
|
+
|
87
|
+
@classmethod
|
88
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
89
|
+
"""Create an instance of ExchangeKeyBalance from a dict"""
|
90
|
+
if obj is None:
|
91
|
+
return None
|
92
|
+
|
93
|
+
if not isinstance(obj, dict):
|
94
|
+
return cls.model_validate(obj)
|
95
|
+
|
96
|
+
_obj = cls.model_validate(
|
97
|
+
{
|
98
|
+
"api_key_id": obj.get("api_key_id"),
|
99
|
+
"futures": (
|
100
|
+
FuturesBalance.from_dict(obj["futures"])
|
101
|
+
if obj.get("futures") is not None
|
102
|
+
else None
|
103
|
+
),
|
104
|
+
"spot": (
|
105
|
+
[SpotBalance.from_dict(_item) for _item in obj["spot"]]
|
106
|
+
if obj.get("spot") is not None
|
107
|
+
else None
|
108
|
+
),
|
109
|
+
}
|
110
|
+
)
|
111
|
+
return _obj
|
@@ -28,29 +28,35 @@ class FuturesBalance(BaseModel):
|
|
28
28
|
Model for futures balance
|
29
29
|
""" # noqa: E501
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
asset: StrictStr = Field(description="Asset the balance values are in")
|
32
|
+
equity: Union[StrictFloat, StrictInt] = Field(
|
33
|
+
description="Net asset value including unrealized profit and loss"
|
34
|
+
)
|
35
|
+
balance: Union[StrictFloat, StrictInt] = Field(
|
36
|
+
description="Actual account balance (equity - unrealized)"
|
37
|
+
)
|
34
38
|
available: Union[StrictFloat, StrictInt] = Field(
|
35
39
|
description="Available balance for trading/withdrawal"
|
36
40
|
)
|
37
|
-
|
38
|
-
description="Unrealized profit and loss"
|
41
|
+
unrealized: Union[StrictFloat, StrictInt] = Field(
|
42
|
+
description="Unrealized profit and loss"
|
39
43
|
)
|
40
|
-
|
41
|
-
|
44
|
+
used: Union[StrictFloat, StrictInt] = Field(
|
45
|
+
description="Margin used in open positions"
|
42
46
|
)
|
43
|
-
|
44
|
-
|
47
|
+
frozen: Union[StrictFloat, StrictInt] = Field(
|
48
|
+
description="Frozen funds not available for use"
|
45
49
|
)
|
50
|
+
allocated: Optional[Union[StrictFloat, StrictInt]] = None
|
46
51
|
__properties: ClassVar[List[str]] = [
|
47
|
-
"apiKeyId",
|
48
52
|
"asset",
|
53
|
+
"equity",
|
49
54
|
"balance",
|
50
55
|
"available",
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
56
|
+
"unrealized",
|
57
|
+
"used",
|
58
|
+
"frozen",
|
59
|
+
"allocated",
|
54
60
|
]
|
55
61
|
|
56
62
|
model_config = ConfigDict(
|
@@ -90,15 +96,10 @@ class FuturesBalance(BaseModel):
|
|
90
96
|
exclude=excluded_fields,
|
91
97
|
exclude_none=True,
|
92
98
|
)
|
93
|
-
# set to None if
|
94
|
-
# and model_fields_set contains the field
|
95
|
-
if self.used_margin is None and "used_margin" in self.model_fields_set:
|
96
|
-
_dict["usedMargin"] = None
|
97
|
-
|
98
|
-
# set to None if frozen_amount (nullable) is None
|
99
|
+
# set to None if allocated (nullable) is None
|
99
100
|
# and model_fields_set contains the field
|
100
|
-
if self.
|
101
|
-
_dict["
|
101
|
+
if self.allocated is None and "allocated" in self.model_fields_set:
|
102
|
+
_dict["allocated"] = None
|
102
103
|
|
103
104
|
return _dict
|
104
105
|
|
@@ -113,13 +114,14 @@ class FuturesBalance(BaseModel):
|
|
113
114
|
|
114
115
|
_obj = cls.model_validate(
|
115
116
|
{
|
116
|
-
"apiKeyId": obj.get("apiKeyId"),
|
117
117
|
"asset": obj.get("asset"),
|
118
|
+
"equity": obj.get("equity"),
|
118
119
|
"balance": obj.get("balance"),
|
119
120
|
"available": obj.get("available"),
|
120
|
-
"
|
121
|
-
"
|
122
|
-
"
|
121
|
+
"unrealized": obj.get("unrealized"),
|
122
|
+
"used": obj.get("used"),
|
123
|
+
"frozen": obj.get("frozen"),
|
124
|
+
"allocated": obj.get("allocated"),
|
123
125
|
}
|
124
126
|
)
|
125
127
|
return _obj
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
"""
|
4
|
+
Trading API
|
5
|
+
|
6
|
+
API for automated trading and exchange interface. This API is used to trade on the exchange and manage bots, API keys, orders, and more.
|
7
|
+
|
8
|
+
The version of the OpenAPI document: 1.0.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, StrictFloat, StrictInt, StrictStr
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional, Union
|
22
|
+
from typing import Optional, Set
|
23
|
+
from typing_extensions import Self
|
24
|
+
|
25
|
+
|
26
|
+
class SpotBalance(BaseModel):
|
27
|
+
"""
|
28
|
+
Model for spot balance
|
29
|
+
""" # noqa: E501
|
30
|
+
|
31
|
+
asset: StrictStr = Field(description="Asset/Currency code")
|
32
|
+
balance: Union[StrictFloat, StrictInt] = Field(description="Balance of the asset")
|
33
|
+
available: Union[StrictFloat, StrictInt] = Field(
|
34
|
+
description="Available balance for trading/withdrawal"
|
35
|
+
)
|
36
|
+
frozen: Union[StrictFloat, StrictInt] = Field(
|
37
|
+
description="Frozen funds not available for use"
|
38
|
+
)
|
39
|
+
allocated: Optional[Union[StrictFloat, StrictInt]] = None
|
40
|
+
__properties: ClassVar[List[str]] = [
|
41
|
+
"asset",
|
42
|
+
"balance",
|
43
|
+
"available",
|
44
|
+
"frozen",
|
45
|
+
"allocated",
|
46
|
+
]
|
47
|
+
|
48
|
+
model_config = ConfigDict(
|
49
|
+
populate_by_name=True,
|
50
|
+
validate_assignment=True,
|
51
|
+
protected_namespaces=(),
|
52
|
+
)
|
53
|
+
|
54
|
+
def to_str(self) -> str:
|
55
|
+
"""Returns the string representation of the model using alias"""
|
56
|
+
return pprint.pformat(self.model_dump(by_alias=True))
|
57
|
+
|
58
|
+
def to_json(self) -> str:
|
59
|
+
"""Returns the JSON representation of the model using alias"""
|
60
|
+
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
61
|
+
return json.dumps(self.to_dict())
|
62
|
+
|
63
|
+
@classmethod
|
64
|
+
def from_json(cls, json_str: str) -> Optional[Self]:
|
65
|
+
"""Create an instance of SpotBalance from a JSON string"""
|
66
|
+
return cls.from_dict(json.loads(json_str))
|
67
|
+
|
68
|
+
def to_dict(self) -> Dict[str, Any]:
|
69
|
+
"""Return the dictionary representation of the model using alias.
|
70
|
+
|
71
|
+
This has the following differences from calling pydantic's
|
72
|
+
`self.model_dump(by_alias=True)`:
|
73
|
+
|
74
|
+
* `None` is only added to the output dict for nullable fields that
|
75
|
+
were set at model initialization. Other fields with value `None`
|
76
|
+
are ignored.
|
77
|
+
"""
|
78
|
+
excluded_fields: Set[str] = set([])
|
79
|
+
|
80
|
+
_dict = self.model_dump(
|
81
|
+
by_alias=True,
|
82
|
+
exclude=excluded_fields,
|
83
|
+
exclude_none=True,
|
84
|
+
)
|
85
|
+
# set to None if allocated (nullable) is None
|
86
|
+
# and model_fields_set contains the field
|
87
|
+
if self.allocated is None and "allocated" in self.model_fields_set:
|
88
|
+
_dict["allocated"] = None
|
89
|
+
|
90
|
+
return _dict
|
91
|
+
|
92
|
+
@classmethod
|
93
|
+
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
94
|
+
"""Create an instance of SpotBalance from a dict"""
|
95
|
+
if obj is None:
|
96
|
+
return None
|
97
|
+
|
98
|
+
if not isinstance(obj, dict):
|
99
|
+
return cls.model_validate(obj)
|
100
|
+
|
101
|
+
_obj = cls.model_validate(
|
102
|
+
{
|
103
|
+
"asset": obj.get("asset"),
|
104
|
+
"balance": obj.get("balance"),
|
105
|
+
"available": obj.get("available"),
|
106
|
+
"frozen": obj.get("frozen"),
|
107
|
+
"allocated": obj.get("allocated"),
|
108
|
+
}
|
109
|
+
)
|
110
|
+
return _obj
|
@@ -50,14 +50,16 @@ class Strategy(BaseModel):
|
|
50
50
|
description="Whether the strategy is enabled. If false, no bots will be created or updated for this strategy, open trades will be rejected. Existing bots will be marked as stopping."
|
51
51
|
)
|
52
52
|
performance_fee: Union[
|
53
|
-
Annotated[float, Field(le=1.0, strict=True)],
|
54
|
-
Annotated[int, Field(le=1, strict=True)],
|
53
|
+
Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
|
54
|
+
Annotated[int, Field(le=1, strict=True, ge=0)],
|
55
55
|
] = Field(description="Performance fee for the strategy")
|
56
56
|
identifier: StrictStr = Field(
|
57
57
|
description="Unique human readable identifier for the strategy e.g. 'daily_trend_momentum'"
|
58
58
|
)
|
59
59
|
margin_mode: Optional[MarginMode] = None
|
60
|
-
leverage:
|
60
|
+
leverage: Annotated[int, Field(strict=True, ge=1)] = Field(
|
61
|
+
description="Leverage for the strategy"
|
62
|
+
)
|
61
63
|
market_type: MarketType = Field(description="Market of operation of the strategy")
|
62
64
|
__properties: ClassVar[List[str]] = [
|
63
65
|
"created_at",
|
@@ -17,7 +17,7 @@ import pprint
|
|
17
17
|
import re # noqa: F401
|
18
18
|
import json
|
19
19
|
|
20
|
-
from pydantic import BaseModel, ConfigDict, Field, StrictBool,
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
|
21
21
|
from typing import Any, ClassVar, Dict, List, Optional, Union
|
22
22
|
from typing_extensions import Annotated
|
23
23
|
from crypticorn.trade.client.models.margin_mode import MarginMode
|
@@ -41,14 +41,16 @@ class StrategyCreate(BaseModel):
|
|
41
41
|
description="Whether the strategy is enabled. If false, no bots will be created or updated for this strategy, open trades will be rejected. Existing bots will be marked as stopping."
|
42
42
|
)
|
43
43
|
performance_fee: Union[
|
44
|
-
Annotated[float, Field(le=1.0, strict=True)],
|
45
|
-
Annotated[int, Field(le=1, strict=True)],
|
44
|
+
Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
|
45
|
+
Annotated[int, Field(le=1, strict=True, ge=0)],
|
46
46
|
] = Field(description="Performance fee for the strategy")
|
47
47
|
identifier: StrictStr = Field(
|
48
48
|
description="Unique human readable identifier for the strategy e.g. 'daily_trend_momentum'"
|
49
49
|
)
|
50
50
|
margin_mode: Optional[MarginMode] = None
|
51
|
-
leverage:
|
51
|
+
leverage: Annotated[int, Field(strict=True, ge=1)] = Field(
|
52
|
+
description="Leverage for the strategy"
|
53
|
+
)
|
52
54
|
market_type: MarketType = Field(description="Market of operation of the strategy")
|
53
55
|
__properties: ClassVar[List[str]] = [
|
54
56
|
"name",
|
@@ -17,8 +17,8 @@ import pprint
|
|
17
17
|
import re # noqa: F401
|
18
18
|
import json
|
19
19
|
|
20
|
-
from pydantic import BaseModel, ConfigDict, Field, StrictInt
|
21
|
-
from typing import Any, ClassVar, Dict, List
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr
|
21
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
22
22
|
from crypticorn.trade.client.models.exchange import Exchange
|
23
23
|
from typing import Optional, Set
|
24
24
|
from typing_extensions import Self
|
@@ -30,10 +30,14 @@ class StrategyExchangeInfo(BaseModel):
|
|
30
30
|
""" # noqa: E501
|
31
31
|
|
32
32
|
exchange: Exchange = Field(description="Exchange name. Of type Exchange")
|
33
|
+
base_asset: Optional[StrictStr] = Field(
|
34
|
+
default="USDT",
|
35
|
+
description="Base asset for the strategy. This is the asset that will be used to trade with. Default is USDT.",
|
36
|
+
)
|
33
37
|
min_amount: StrictInt = Field(
|
34
38
|
description="Minimum amount for the strategy on the exchange"
|
35
39
|
)
|
36
|
-
__properties: ClassVar[List[str]] = ["exchange", "min_amount"]
|
40
|
+
__properties: ClassVar[List[str]] = ["exchange", "base_asset", "min_amount"]
|
37
41
|
|
38
42
|
model_config = ConfigDict(
|
39
43
|
populate_by_name=True,
|
@@ -84,6 +88,14 @@ class StrategyExchangeInfo(BaseModel):
|
|
84
88
|
return cls.model_validate(obj)
|
85
89
|
|
86
90
|
_obj = cls.model_validate(
|
87
|
-
{
|
91
|
+
{
|
92
|
+
"exchange": obj.get("exchange"),
|
93
|
+
"base_asset": (
|
94
|
+
obj.get("base_asset")
|
95
|
+
if obj.get("base_asset") is not None
|
96
|
+
else "USDT"
|
97
|
+
),
|
98
|
+
"min_amount": obj.get("min_amount"),
|
99
|
+
}
|
88
100
|
)
|
89
101
|
return _obj
|
@@ -36,8 +36,8 @@ class StrategyUpdate(BaseModel):
|
|
36
36
|
enabled: Optional[StrictBool] = None
|
37
37
|
performance_fee: Optional[
|
38
38
|
Union[
|
39
|
-
Annotated[float, Field(le=1.0, strict=True)],
|
40
|
-
Annotated[int, Field(le=1, strict=True)],
|
39
|
+
Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
|
40
|
+
Annotated[int, Field(le=1, strict=True, ge=0)],
|
41
41
|
]
|
42
42
|
] = None
|
43
43
|
__properties: ClassVar[List[str]] = [
|
crypticorn/trade/client/rest.py
CHANGED
@@ -77,6 +77,7 @@ class RESTClientObject:
|
|
77
77
|
|
78
78
|
self.pool_manager: Optional[aiohttp.ClientSession] = None
|
79
79
|
self.retry_client: Optional[aiohttp_retry.RetryClient] = None
|
80
|
+
self.is_sync: bool = False # Track whether this is sync or async mode
|
80
81
|
|
81
82
|
async def close(self) -> None:
|
82
83
|
if self.pool_manager:
|
@@ -170,7 +171,9 @@ class RESTClientObject:
|
|
170
171
|
|
171
172
|
pool_manager: Union[aiohttp.ClientSession, aiohttp_retry.RetryClient]
|
172
173
|
|
173
|
-
#
|
174
|
+
# For sync operations, always use a fresh session
|
175
|
+
should_close_session = False
|
176
|
+
|
174
177
|
if self.pool_manager is None:
|
175
178
|
self.pool_manager = aiohttp.ClientSession(
|
176
179
|
connector=aiohttp.TCPConnector(
|
@@ -178,6 +181,9 @@ class RESTClientObject:
|
|
178
181
|
),
|
179
182
|
trust_env=True,
|
180
183
|
)
|
184
|
+
# Only close session automatically in sync mode
|
185
|
+
should_close_session = self.is_sync
|
186
|
+
|
181
187
|
pool_manager = self.pool_manager
|
182
188
|
|
183
189
|
if self.retries is not None and method in ALLOW_RETRY_METHODS:
|
@@ -193,6 +199,19 @@ class RESTClientObject:
|
|
193
199
|
)
|
194
200
|
pool_manager = self.retry_client
|
195
201
|
|
196
|
-
|
197
|
-
|
198
|
-
|
202
|
+
try:
|
203
|
+
r = await pool_manager.request(**args)
|
204
|
+
# For sessions we're about to close, read the data immediately
|
205
|
+
if should_close_session:
|
206
|
+
response = RESTResponse(r)
|
207
|
+
await response.read() # Read data before closing session
|
208
|
+
return response
|
209
|
+
else:
|
210
|
+
return RESTResponse(r)
|
211
|
+
finally:
|
212
|
+
if should_close_session:
|
213
|
+
if self.retry_client is not None:
|
214
|
+
await self.retry_client.close()
|
215
|
+
self.retry_client = None
|
216
|
+
await self.pool_manager.close()
|
217
|
+
self.pool_manager = None
|
crypticorn/trade/main.py
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from typing import TYPE_CHECKING, Optional
|
3
|
-
from crypticorn.trade import (
|
3
|
+
from crypticorn.trade.client import (
|
4
4
|
ApiClient,
|
5
5
|
APIKeysApi,
|
6
6
|
BotsApi,
|
7
7
|
Configuration,
|
8
8
|
ExchangesApi,
|
9
|
-
FuturesTradingPanelApi,
|
10
9
|
NotificationsApi,
|
11
10
|
OrdersApi,
|
12
11
|
StatusApi,
|
@@ -26,19 +25,23 @@ class TradeClient:
|
|
26
25
|
config_class = Configuration
|
27
26
|
|
28
27
|
def __init__(
|
29
|
-
self,
|
28
|
+
self,
|
29
|
+
config: Configuration,
|
30
|
+
http_client: Optional[ClientSession] = None,
|
31
|
+
is_sync: bool = False,
|
30
32
|
):
|
31
33
|
self.config = config
|
32
34
|
self.base_client = ApiClient(configuration=self.config)
|
33
35
|
if http_client is not None:
|
34
36
|
self.base_client.rest_client.pool_manager = http_client
|
37
|
+
# Pass sync context to REST client for proper session management
|
38
|
+
self.base_client.rest_client.is_sync = is_sync
|
35
39
|
# Instantiate all the endpoint clients
|
36
|
-
self.bots = BotsApi(self.base_client)
|
37
|
-
self.exchanges = ExchangesApi(self.base_client)
|
38
|
-
self.notifications = NotificationsApi(self.base_client)
|
39
|
-
self.orders = OrdersApi(self.base_client)
|
40
|
-
self.status = StatusApi(self.base_client)
|
41
|
-
self.strategies = StrategiesApi(self.base_client)
|
42
|
-
self.actions = TradingActionsApi(self.base_client)
|
43
|
-
self.
|
44
|
-
self.keys = APIKeysApi(self.base_client)
|
40
|
+
self.bots = BotsApi(self.base_client, is_sync=is_sync)
|
41
|
+
self.exchanges = ExchangesApi(self.base_client, is_sync=is_sync)
|
42
|
+
self.notifications = NotificationsApi(self.base_client, is_sync=is_sync)
|
43
|
+
self.orders = OrdersApi(self.base_client, is_sync=is_sync)
|
44
|
+
self.status = StatusApi(self.base_client, is_sync=is_sync)
|
45
|
+
self.strategies = StrategiesApi(self.base_client, is_sync=is_sync)
|
46
|
+
self.actions = TradingActionsApi(self.base_client, is_sync=is_sync)
|
47
|
+
self.keys = APIKeysApi(self.base_client, is_sync=is_sync)
|