crypticorn 2.12.1__py3-none-any.whl → 2.13.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.
Files changed (37) hide show
  1. crypticorn/auth/client/models/create_user_request.py +4 -16
  2. crypticorn/auth/main.py +8 -0
  3. crypticorn/client.py +26 -22
  4. crypticorn/common/auth.py +44 -12
  5. crypticorn/common/errors.py +79 -76
  6. crypticorn/hive/client/configuration.py +2 -2
  7. crypticorn/hive/client/models/api_error_identifier.py +2 -2
  8. crypticorn/hive/main.py +9 -5
  9. crypticorn/klines/client/models/api_error_identifier.py +1 -1
  10. crypticorn/klines/main.py +7 -0
  11. crypticorn/metrics/client/api/exchanges_api.py +343 -0
  12. crypticorn/metrics/client/configuration.py +4 -2
  13. crypticorn/metrics/client/models/api_error_identifier.py +9 -3
  14. crypticorn/metrics/main.py +8 -3
  15. crypticorn/pay/client/api/products_api.py +228 -1
  16. crypticorn/pay/client/configuration.py +2 -2
  17. crypticorn/pay/client/models/api_error_identifier.py +7 -3
  18. crypticorn/pay/main.py +7 -0
  19. crypticorn/trade/client/__init__.py +1 -0
  20. crypticorn/trade/client/api/strategies_api.py +296 -26
  21. crypticorn/trade/client/api/trading_actions_api.py +4 -4
  22. crypticorn/trade/client/models/__init__.py +1 -0
  23. crypticorn/trade/client/models/api_error_identifier.py +6 -2
  24. crypticorn/trade/client/models/futures_trading_action.py +23 -37
  25. crypticorn/trade/client/models/futures_trading_action_create.py +28 -42
  26. crypticorn/trade/client/models/order.py +40 -34
  27. crypticorn/trade/client/models/spot_trading_action_create.py +10 -25
  28. crypticorn/trade/client/models/strategy_exchange_info.py +3 -3
  29. crypticorn/trade/client/models/tpsl.py +7 -16
  30. crypticorn/trade/client/models/tpsl_create.py +103 -0
  31. crypticorn/trade/main.py +8 -2
  32. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/METADATA +30 -3
  33. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/RECORD +37 -36
  34. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/WHEEL +0 -0
  35. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/entry_points.txt +0 -0
  36. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/licenses/LICENSE +0 -0
  37. {crypticorn-2.12.1.dist-info → crypticorn-2.13.1.dist-info}/top_level.txt +0 -0
@@ -17,20 +17,12 @@ import pprint
17
17
  import re # noqa: F401
18
18
  import json
19
19
 
20
- from pydantic import (
21
- BaseModel,
22
- ConfigDict,
23
- Field,
24
- StrictBool,
25
- StrictFloat,
26
- StrictInt,
27
- StrictStr,
28
- )
29
- from typing import Any, ClassVar, Dict, List, Optional, Union
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
30
22
  from typing_extensions import Annotated
31
23
  from crypticorn.trade.client.models.margin_mode import MarginMode
32
24
  from crypticorn.trade.client.models.market_type import MarketType
33
- from crypticorn.trade.client.models.tpsl import TPSL
25
+ from crypticorn.trade.client.models.tpsl_create import TPSLCreate
34
26
  from crypticorn.trade.client.models.trading_action_type import TradingActionType
35
27
  from typing import Optional, Set
36
28
  from typing_extensions import Self
@@ -41,6 +33,8 @@ class FuturesTradingActionCreate(BaseModel):
41
33
  Model for sending futures trading actions
42
34
  """ # noqa: E501
43
35
 
36
+ leverage: Optional[Annotated[int, Field(strict=True, ge=1)]]
37
+ margin_mode: Optional[MarginMode] = None
44
38
  execution_id: Optional[StrictStr] = None
45
39
  open_order_execution_id: Optional[StrictStr] = None
46
40
  action_type: TradingActionType = Field(description="The type of action.")
@@ -50,22 +44,16 @@ class FuturesTradingActionCreate(BaseModel):
50
44
  description="Trading symbol or asset pair in format: 'symbol/quote_currency' (see market service for valid symbols)"
51
45
  )
52
46
  is_limit: Optional[StrictBool] = None
53
- limit_price: Optional[Union[StrictFloat, StrictInt]] = None
54
- allocation: Optional[
55
- Union[
56
- Annotated[float, Field(le=1.0, strict=True)],
57
- Annotated[int, Field(le=1, strict=True)],
58
- ]
59
- ] = Field(
60
- default=None,
61
- description="How much of bot's balance to use for the order (for open actions). How much of the reference open order (open_order_execution_id) to close (for close actions). 0=0%, 1=100%.",
47
+ limit_price: Optional[StrictStr] = None
48
+ allocation: StrictStr = Field(
49
+ description="How much of bot's balance to use for the order (for open actions). How much of the reference open order (open_order_execution_id) to close (for close actions). 0=0%, 1=100%."
62
50
  )
63
- take_profit: Optional[List[TPSL]] = None
64
- stop_loss: Optional[List[TPSL]] = None
51
+ take_profit: Optional[List[TPSLCreate]] = None
52
+ stop_loss: Optional[List[TPSLCreate]] = None
65
53
  expiry_timestamp: Optional[StrictInt] = None
66
- leverage: Optional[Annotated[int, Field(strict=True, ge=1)]]
67
- margin_mode: Optional[MarginMode] = None
68
54
  __properties: ClassVar[List[str]] = [
55
+ "leverage",
56
+ "margin_mode",
69
57
  "execution_id",
70
58
  "open_order_execution_id",
71
59
  "action_type",
@@ -78,8 +66,6 @@ class FuturesTradingActionCreate(BaseModel):
78
66
  "take_profit",
79
67
  "stop_loss",
80
68
  "expiry_timestamp",
81
- "leverage",
82
- "margin_mode",
83
69
  ]
84
70
 
85
71
  model_config = ConfigDict(
@@ -133,6 +119,16 @@ class FuturesTradingActionCreate(BaseModel):
133
119
  if _item_stop_loss:
134
120
  _items.append(_item_stop_loss.to_dict())
135
121
  _dict["stop_loss"] = _items
122
+ # set to None if leverage (nullable) is None
123
+ # and model_fields_set contains the field
124
+ if self.leverage is None and "leverage" in self.model_fields_set:
125
+ _dict["leverage"] = None
126
+
127
+ # set to None if margin_mode (nullable) is None
128
+ # and model_fields_set contains the field
129
+ if self.margin_mode is None and "margin_mode" in self.model_fields_set:
130
+ _dict["margin_mode"] = None
131
+
136
132
  # set to None if execution_id (nullable) is None
137
133
  # and model_fields_set contains the field
138
134
  if self.execution_id is None and "execution_id" in self.model_fields_set:
@@ -174,16 +170,6 @@ class FuturesTradingActionCreate(BaseModel):
174
170
  ):
175
171
  _dict["expiry_timestamp"] = None
176
172
 
177
- # set to None if leverage (nullable) is None
178
- # and model_fields_set contains the field
179
- if self.leverage is None and "leverage" in self.model_fields_set:
180
- _dict["leverage"] = None
181
-
182
- # set to None if margin_mode (nullable) is None
183
- # and model_fields_set contains the field
184
- if self.margin_mode is None and "margin_mode" in self.model_fields_set:
185
- _dict["margin_mode"] = None
186
-
187
173
  return _dict
188
174
 
189
175
  @classmethod
@@ -197,6 +183,10 @@ class FuturesTradingActionCreate(BaseModel):
197
183
 
198
184
  _obj = cls.model_validate(
199
185
  {
186
+ "leverage": (
187
+ obj.get("leverage") if obj.get("leverage") is not None else 1
188
+ ),
189
+ "margin_mode": obj.get("margin_mode"),
200
190
  "execution_id": obj.get("execution_id"),
201
191
  "open_order_execution_id": obj.get("open_order_execution_id"),
202
192
  "action_type": obj.get("action_type"),
@@ -207,20 +197,16 @@ class FuturesTradingActionCreate(BaseModel):
207
197
  "limit_price": obj.get("limit_price"),
208
198
  "allocation": obj.get("allocation"),
209
199
  "take_profit": (
210
- [TPSL.from_dict(_item) for _item in obj["take_profit"]]
200
+ [TPSLCreate.from_dict(_item) for _item in obj["take_profit"]]
211
201
  if obj.get("take_profit") is not None
212
202
  else None
213
203
  ),
214
204
  "stop_loss": (
215
- [TPSL.from_dict(_item) for _item in obj["stop_loss"]]
205
+ [TPSLCreate.from_dict(_item) for _item in obj["stop_loss"]]
216
206
  if obj.get("stop_loss") is not None
217
207
  else None
218
208
  ),
219
209
  "expiry_timestamp": obj.get("expiry_timestamp"),
220
- "leverage": (
221
- obj.get("leverage") if obj.get("leverage") is not None else 1
222
- ),
223
- "margin_mode": obj.get("margin_mode"),
224
210
  }
225
211
  )
226
212
  return _obj
@@ -17,9 +17,8 @@ import pprint
17
17
  import re # noqa: F401
18
18
  import json
19
19
 
20
- from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
21
- from typing import Any, ClassVar, Dict, List, Optional, Union
22
- from typing_extensions import Annotated
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
23
22
  from crypticorn.trade.client.models.api_error_identifier import ApiErrorIdentifier
24
23
  from crypticorn.trade.client.models.exchange import Exchange
25
24
  from crypticorn.trade.client.models.margin_mode import MarginMode
@@ -55,37 +54,21 @@ class Order(BaseModel):
55
54
  exchange: Optional[Exchange] = None
56
55
  symbol: Optional[StrictStr] = None
57
56
  common_symbol: Optional[StrictStr] = None
58
- price: Optional[Union[StrictFloat, StrictInt]] = None
57
+ price: Optional[StrictStr] = None
59
58
  action_type: Optional[TradingActionType] = None
60
59
  market_type: Optional[MarketType] = None
61
60
  margin_mode: Optional[MarginMode] = None
62
61
  status_code: Optional[ApiErrorIdentifier] = None
63
62
  status: Optional[OrderStatus] = None
64
- filled_perc: Optional[
65
- Union[
66
- Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
67
- Annotated[int, Field(le=1, strict=True, ge=0)],
68
- ]
69
- ] = Field(default=0, description="Percentage of the order filled")
70
- filled_qty: Optional[
71
- Union[
72
- Annotated[float, Field(strict=True, ge=0.0)],
73
- Annotated[int, Field(strict=True, ge=0)],
74
- ]
75
- ] = Field(
76
- default=0,
77
- description="Quantity filled. Needed for pnl calculation. In the symbol's base currency.",
78
- )
79
- fee: Optional[Union[StrictFloat, StrictInt]] = Field(
80
- default=0, description="Fees for the order"
81
- )
82
- leverage: Optional[Union[StrictFloat, StrictInt]] = None
63
+ filled_perc: Optional[StrictStr] = None
64
+ filled_qty: Optional[StrictStr] = None
65
+ sent_qty: Optional[StrictStr] = None
66
+ fee: Optional[StrictStr] = None
67
+ leverage: Optional[StrictInt] = None
83
68
  order_details: Optional[Any] = Field(
84
69
  default=None, description="Exchange specific details of the order"
85
70
  )
86
- pnl: Optional[Union[StrictFloat, StrictInt]] = Field(
87
- default=0, description="Profit and loss for the order"
88
- )
71
+ pnl: Optional[StrictStr] = None
89
72
  order_time: Optional[StrictInt] = None
90
73
  __properties: ClassVar[List[str]] = [
91
74
  "created_at",
@@ -110,6 +93,7 @@ class Order(BaseModel):
110
93
  "status",
111
94
  "filled_perc",
112
95
  "filled_qty",
96
+ "sent_qty",
113
97
  "fee",
114
98
  "leverage",
115
99
  "order_details",
@@ -248,6 +232,26 @@ class Order(BaseModel):
248
232
  if self.status is None and "status" in self.model_fields_set:
249
233
  _dict["status"] = None
250
234
 
235
+ # set to None if filled_perc (nullable) is None
236
+ # and model_fields_set contains the field
237
+ if self.filled_perc is None and "filled_perc" in self.model_fields_set:
238
+ _dict["filled_perc"] = None
239
+
240
+ # set to None if filled_qty (nullable) is None
241
+ # and model_fields_set contains the field
242
+ if self.filled_qty is None and "filled_qty" in self.model_fields_set:
243
+ _dict["filled_qty"] = None
244
+
245
+ # set to None if sent_qty (nullable) is None
246
+ # and model_fields_set contains the field
247
+ if self.sent_qty is None and "sent_qty" in self.model_fields_set:
248
+ _dict["sent_qty"] = None
249
+
250
+ # set to None if fee (nullable) is None
251
+ # and model_fields_set contains the field
252
+ if self.fee is None and "fee" in self.model_fields_set:
253
+ _dict["fee"] = None
254
+
251
255
  # set to None if leverage (nullable) is None
252
256
  # and model_fields_set contains the field
253
257
  if self.leverage is None and "leverage" in self.model_fields_set:
@@ -258,6 +262,11 @@ class Order(BaseModel):
258
262
  if self.order_details is None and "order_details" in self.model_fields_set:
259
263
  _dict["order_details"] = None
260
264
 
265
+ # set to None if pnl (nullable) is None
266
+ # and model_fields_set contains the field
267
+ if self.pnl is None and "pnl" in self.model_fields_set:
268
+ _dict["pnl"] = None
269
+
261
270
  # set to None if order_time (nullable) is None
262
271
  # and model_fields_set contains the field
263
272
  if self.order_time is None and "order_time" in self.model_fields_set:
@@ -296,20 +305,17 @@ class Order(BaseModel):
296
305
  "margin_mode": obj.get("margin_mode"),
297
306
  "status_code": obj.get("status_code"),
298
307
  "status": obj.get("status"),
299
- "filled_perc": (
300
- obj.get("filled_perc") if obj.get("filled_perc") is not None else 0
301
- ),
302
- "filled_qty": (
303
- obj.get("filled_qty") if obj.get("filled_qty") is not None else 0
304
- ),
305
- "fee": obj.get("fee") if obj.get("fee") is not None else 0,
308
+ "filled_perc": obj.get("filled_perc"),
309
+ "filled_qty": obj.get("filled_qty"),
310
+ "sent_qty": obj.get("sent_qty"),
311
+ "fee": obj.get("fee"),
306
312
  "leverage": obj.get("leverage"),
307
313
  "order_details": (
308
314
  AnyOf.from_dict(obj["order_details"])
309
315
  if obj.get("order_details") is not None
310
316
  else None
311
317
  ),
312
- "pnl": obj.get("pnl") if obj.get("pnl") is not None else 0,
318
+ "pnl": obj.get("pnl"),
313
319
  "order_time": obj.get("order_time"),
314
320
  }
315
321
  )
@@ -17,19 +17,10 @@ import pprint
17
17
  import re # noqa: F401
18
18
  import json
19
19
 
20
- from pydantic import (
21
- BaseModel,
22
- ConfigDict,
23
- Field,
24
- StrictBool,
25
- StrictFloat,
26
- StrictInt,
27
- StrictStr,
28
- )
29
- from typing import Any, ClassVar, Dict, List, Optional, Union
30
- from typing_extensions import Annotated
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
31
22
  from crypticorn.trade.client.models.market_type import MarketType
32
- from crypticorn.trade.client.models.tpsl import TPSL
23
+ from crypticorn.trade.client.models.tpsl_create import TPSLCreate
33
24
  from crypticorn.trade.client.models.trading_action_type import TradingActionType
34
25
  from typing import Optional, Set
35
26
  from typing_extensions import Self
@@ -49,18 +40,12 @@ class SpotTradingActionCreate(BaseModel):
49
40
  description="Trading symbol or asset pair in format: 'symbol/quote_currency' (see market service for valid symbols)"
50
41
  )
51
42
  is_limit: Optional[StrictBool] = None
52
- limit_price: Optional[Union[StrictFloat, StrictInt]] = None
53
- allocation: Optional[
54
- Union[
55
- Annotated[float, Field(le=1.0, strict=True)],
56
- Annotated[int, Field(le=1, strict=True)],
57
- ]
58
- ] = Field(
59
- default=None,
60
- description="How much of bot's balance to use for the order (for open actions). How much of the reference open order (open_order_execution_id) to close (for close actions). 0=0%, 1=100%.",
43
+ limit_price: Optional[StrictStr] = None
44
+ allocation: StrictStr = Field(
45
+ description="How much of bot's balance to use for the order (for open actions). How much of the reference open order (open_order_execution_id) to close (for close actions). 0=0%, 1=100%."
61
46
  )
62
- take_profit: Optional[List[TPSL]] = None
63
- stop_loss: Optional[List[TPSL]] = None
47
+ take_profit: Optional[List[TPSLCreate]] = None
48
+ stop_loss: Optional[List[TPSLCreate]] = None
64
49
  expiry_timestamp: Optional[StrictInt] = None
65
50
  __properties: ClassVar[List[str]] = [
66
51
  "execution_id",
@@ -192,12 +177,12 @@ class SpotTradingActionCreate(BaseModel):
192
177
  "limit_price": obj.get("limit_price"),
193
178
  "allocation": obj.get("allocation"),
194
179
  "take_profit": (
195
- [TPSL.from_dict(_item) for _item in obj["take_profit"]]
180
+ [TPSLCreate.from_dict(_item) for _item in obj["take_profit"]]
196
181
  if obj.get("take_profit") is not None
197
182
  else None
198
183
  ),
199
184
  "stop_loss": (
200
- [TPSL.from_dict(_item) for _item in obj["stop_loss"]]
185
+ [TPSLCreate.from_dict(_item) for _item in obj["stop_loss"]]
201
186
  if obj.get("stop_loss") is not None
202
187
  else None
203
188
  ),
@@ -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, StrictFloat, StrictInt
21
- from typing import Any, ClassVar, Dict, List, Union
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictInt
21
+ from typing import Any, ClassVar, Dict, List
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,7 +30,7 @@ class StrategyExchangeInfo(BaseModel):
30
30
  """ # noqa: E501
31
31
 
32
32
  exchange: Exchange = Field(description="Exchange name. Of type Exchange")
33
- min_amount: Union[StrictFloat, StrictInt] = Field(
33
+ min_amount: StrictInt = Field(
34
34
  description="Minimum amount for the strategy on the exchange"
35
35
  )
36
36
  __properties: ClassVar[List[str]] = ["exchange", "min_amount"]
@@ -17,30 +17,21 @@ import pprint
17
17
  import re # noqa: F401
18
18
  import json
19
19
 
20
- from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
21
- from typing import Any, ClassVar, Dict, List, Optional, Union
22
- from typing_extensions import Annotated
20
+ from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
+ from typing import Any, ClassVar, Dict, List, Optional
23
22
  from typing import Optional, Set
24
23
  from typing_extensions import Self
25
24
 
26
25
 
27
26
  class TPSL(BaseModel):
28
27
  """
29
- Model for take profit and stop loss targets
28
+ Runtime fields for take profit and stop loss
30
29
  """ # noqa: E501
31
30
 
32
- price_delta: Optional[
33
- Union[
34
- Annotated[float, Field(strict=True, ge=0.0)],
35
- Annotated[int, Field(strict=True, ge=0)],
36
- ]
37
- ] = None
38
- price: Optional[Union[StrictFloat, StrictInt]] = None
39
- allocation: Union[
40
- Annotated[float, Field(le=1.0, strict=True, ge=0.0)],
41
- Annotated[int, Field(le=1, strict=True, ge=0)],
42
- ] = Field(
43
- description="Percentage of the open order to sell. All allocations must sum up to 1."
31
+ price_delta: Optional[StrictStr] = None
32
+ price: Optional[StrictStr] = None
33
+ allocation: StrictStr = Field(
34
+ description="Percentage of the open order to sell. All allocations must sum up to 1. Use this allocation again when closing the order."
44
35
  )
45
36
  execution_id: Optional[StrictStr] = None
46
37
  client_order_id: Optional[StrictStr] = None
@@ -0,0 +1,103 @@
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, Optional
22
+ from typing import Optional, Set
23
+ from typing_extensions import Self
24
+
25
+
26
+ class TPSLCreate(BaseModel):
27
+ """
28
+ Model for take profit and stop loss
29
+ """ # noqa: E501
30
+
31
+ price_delta: Optional[StrictStr] = None
32
+ price: Optional[StrictStr] = None
33
+ allocation: StrictStr = Field(
34
+ description="Percentage of the open order to sell. All allocations must sum up to 1. Use this allocation again when closing the order."
35
+ )
36
+ __properties: ClassVar[List[str]] = ["price_delta", "price", "allocation"]
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 TPSLCreate 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
+ # set to None if price_delta (nullable) is None
76
+ # and model_fields_set contains the field
77
+ if self.price_delta is None and "price_delta" in self.model_fields_set:
78
+ _dict["price_delta"] = None
79
+
80
+ # set to None if price (nullable) is None
81
+ # and model_fields_set contains the field
82
+ if self.price is None and "price" in self.model_fields_set:
83
+ _dict["price"] = None
84
+
85
+ return _dict
86
+
87
+ @classmethod
88
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
89
+ """Create an instance of TPSLCreate 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
+ "price_delta": obj.get("price_delta"),
99
+ "price": obj.get("price"),
100
+ "allocation": obj.get("allocation"),
101
+ }
102
+ )
103
+ return _obj
crypticorn/trade/main.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
1
3
  from crypticorn.trade import (
2
4
  ApiClient,
3
5
  APIKeysApi,
@@ -12,6 +14,9 @@ from crypticorn.trade import (
12
14
  TradingActionsApi,
13
15
  )
14
16
 
17
+ if TYPE_CHECKING:
18
+ from aiohttp import ClientSession
19
+
15
20
 
16
21
  class TradeClient:
17
22
  """
@@ -21,11 +26,12 @@ class TradeClient:
21
26
  config_class = Configuration
22
27
 
23
28
  def __init__(
24
- self,
25
- config: Configuration,
29
+ self, config: Configuration, http_client: Optional[ClientSession] = None
26
30
  ):
27
31
  self.config = config
28
32
  self.base_client = ApiClient(configuration=self.config)
33
+ if http_client is not None:
34
+ self.base_client.rest_client.pool_manager = http_client
29
35
  # Instantiate all the endpoint clients
30
36
  self.bots = BotsApi(self.base_client)
31
37
  self.exchanges = ExchangesApi(self.base_client)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.12.1
3
+ Version: 2.13.1
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -191,14 +191,41 @@ This utility allows direct data streaming to your local disk, instead of only re
191
191
 
192
192
  ## Advanced Usage
193
193
 
194
+ ### Sub Client Configuration
195
+
194
196
  You can override some configuration for specific services. If you just want to use the API as is, you don't need to configure anything.
195
197
  This might be of use if you are testing a specific API locally.
196
198
 
197
199
  To override e.g. the host for the Hive client to connect to localhost:8000 instead of the default proxy, you would do:
198
200
  ```python
199
- from crypticorn.hive import Configuration as Hiveconfig
201
+ from crypticorn.hive import Configuration as HiveConfig
200
202
  from crypticorn.common import Service
201
203
 
202
204
  async with ApiClient() as client:
203
- client.configure(config=HiveConfig(host="http://localhost:8000"), client=Service.HIVE)
205
+ client.configure(config=HiveConfig(host="http://localhost:8000"), service=Service.HIVE)
206
+ ```
207
+
208
+ ### Session Management
209
+
210
+ By default `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers. You can pass your own configured `aiohttp.ClientSession` for advanced use cases (for custom retry, logging, or mocking):
211
+
212
+ ```python
213
+ import aiohttp
214
+ from crypticorn import ApiClient
215
+
216
+ custom_http_client = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=10), headers={"X-Test": "1"})
217
+ api = ApiClient(api_key="your-key")
218
+ api._http_client = custom_http_client
219
+
220
+ for service in api._services.values():
221
+ service.base_client.rest_client.pool_manager = custom_http_client
222
+ ```
223
+
224
+ ### Disable Logging
225
+
226
+ In case you don't want any logging statements by the `crypticorn` logger to be logged to stdout, you can disable it with:
227
+
228
+ ```python
229
+ from crypticorn.common import disable_logging
230
+ disable_logging()
204
231
  ```