crypticorn 2.13.2__py3-none-any.whl → 2.14.0__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/client.py CHANGED
@@ -24,6 +24,8 @@ class ApiClient:
24
24
  api_key: Optional[str] = None,
25
25
  jwt: Optional[str] = None,
26
26
  base_url: BaseUrl = BaseUrl.PROD,
27
+ *,
28
+ http_client: Optional[ClientSession] = None,
27
29
  ):
28
30
  self.base_url = base_url
29
31
  """The base URL the client will use to connect to the API."""
@@ -34,13 +36,8 @@ class ApiClient:
34
36
  self.version = version("crypticorn")
35
37
  """The version of the client."""
36
38
 
37
- # self._http_client = ClientSession(
38
- # timeout=ClientTimeout(total=30.0),
39
- # connector=TCPConnector(limit=100, limit_per_host=20),
40
- # headers={"User-Agent": f"crypticorn/python/{self.version}"},
41
- # )
42
- self._http_client = None # temporary fix for the issue with the event loop
43
-
39
+ self._http_client = http_client
40
+ self._owns_http_client = http_client is None # whether we own the http client
44
41
  self._service_classes: dict[Service, type[SubClient]] = {
45
42
  Service.HIVE: HiveClient,
46
43
  Service.TRADE: TradeClient,
@@ -99,9 +96,28 @@ class ApiClient:
99
96
  return self._services[Service.AUTH]
100
97
 
101
98
  async def close(self):
99
+ # close each in sync
102
100
  for service in self._services.values():
103
- if hasattr(service.base_client, "close"):
101
+ if hasattr(service.base_client, "close") and self._owns_http_client:
104
102
  await service.base_client.close()
103
+ # close shared in async
104
+ if self._http_client and self._owns_http_client:
105
+ await self._http_client.close()
106
+ self._http_client = None
107
+
108
+ async def _ensure_session(self) -> None:
109
+ """
110
+ Lazily create the shared HTTP client when first needed and pass it to all subclients.
111
+ """
112
+ if self._http_client is None:
113
+ self._http_client = ClientSession(
114
+ timeout=ClientTimeout(total=30.0),
115
+ connector=TCPConnector(limit=100, limit_per_host=20),
116
+ headers={"User-Agent": f"crypticorn/python/{self.version}"},
117
+ )
118
+ for service in self._services.values():
119
+ if hasattr(service, 'base_client') and hasattr(service.base_client, 'rest_client'):
120
+ service.base_client.rest_client.pool_manager = self._http_client
105
121
 
106
122
  def _get_default_config(self, service, version=None):
107
123
  if version is None:
@@ -137,6 +153,7 @@ class ApiClient:
137
153
  )
138
154
 
139
155
  async def __aenter__(self):
156
+ await self._ensure_session()
140
157
  return self
141
158
 
142
159
  async def __aexit__(self, exc_type, exc_val, exc_tb):
@@ -63,7 +63,7 @@ class ApiErrorIdentifier(StrEnum):
63
63
  EXCHANGE_USER_FROZEN = "exchange_user_account_is_frozen"
64
64
  EXPIRED_API_KEY = "api_key_expired"
65
65
  EXPIRED_BEARER = "bearer_token_expired"
66
- FAILED_OPEN_ORDER = "open_order_expired"
66
+ FAILED_OPEN_ORDER = "failed_open_order"
67
67
  FORBIDDEN = "forbidden"
68
68
  HEDGE_MODE_NOT_ACTIVE = "hedge_mode_not_active"
69
69
  INSUFFICIENT_BALANCE = "insufficient_balance"
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ from logging.handlers import RotatingFileHandler
4
5
  import sys
5
6
  from crypticorn.common.mixins import ValidateEnumMixin
6
7
  from crypticorn.common.ansi_colors import AnsiColors as C
@@ -109,7 +110,7 @@ def configure_logging(
109
110
  # Configure file handler
110
111
  if log_file:
111
112
  os.makedirs(os.path.dirname(log_file), exist_ok=True)
112
- file_handler = logging.handlers.RotatingFileHandler(
113
+ file_handler = RotatingFileHandler(
113
114
  log_file, maxBytes=10 * 1024 * 1024, backupCount=5
114
115
  )
115
116
  file_handler.setLevel(file_level)
crypticorn/trade/main.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from __future__ import annotations
2
- from typing import TYPE_CHECKING
2
+ from typing import TYPE_CHECKING, Optional
3
3
  from crypticorn.trade import (
4
4
  ApiClient,
5
5
  APIKeysApi,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.13.2
3
+ Version: 2.14.0
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -207,19 +207,27 @@ async with ApiClient() as client:
207
207
 
208
208
  ### Session Management
209
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):
210
+ By default, `ApiClient` manages a single shared `aiohttp.ClientSession` for all service wrappers.
211
+ However, you can pass your own pre-configured `aiohttp.ClientSession` if you need advanced control — for example, to add retries, custom headers, logging, or mocking behavior.
212
+
213
+ When you inject a custom session, you are responsible for managing its lifecycle, including closing when you're done.
211
214
 
212
215
  ```python
213
216
  import aiohttp
214
217
  from crypticorn import ApiClient
215
218
 
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
- ```
219
+ async def main():
220
+ custom_session = aiohttp.ClientSession()
221
+ async with ApiClient(api_key="your-key", http_client=custom_session) as client:
222
+ await client.trade.status.ping()
223
+ await custom_session.close()
224
+ # or
225
+ custom_session = aiohttp.ClientSession()
226
+ client = ApiClient(api_key="your-key", http_client=custom_session)
227
+ await client.trade.status.ping()
228
+ await custom_session.close()
229
+ ```
230
+ If you don’t pass a session, `ApiClient` will create and manage one internally. In that case, it will be automatically closed when using `async with` or when calling `await client.close()` manually.
223
231
 
224
232
  ### Disable Logging
225
233
 
@@ -1,5 +1,5 @@
1
1
  crypticorn/__init__.py,sha256=ctrwe5CQtYhnetHYPgSmC0CIHa4xbDsLZvpY38tfEow,423
2
- crypticorn/client.py,sha256=hIX_9RroQXQ_xW0t9H6XYjt7OI_sqX4kw4fRWJXlXos,5205
2
+ crypticorn/client.py,sha256=JoS1cTA9cKo_7zgmSdjy3GbjEUxE8pYWN4XAXtujX1M,6023
3
3
  crypticorn/auth/__init__.py,sha256=JAl1tBLK9pYLr_-YKaj581c-c94PWLoqnatTIVAVvMM,81
4
4
  crypticorn/auth/main.py,sha256=FHLsAbp2mXDlmcPmLKc29qaD1dBev65V3DNKLyfz4Tw,1012
5
5
  crypticorn/auth/client/__init__.py,sha256=do16xS84uXvVoJuWERjb9RwlOaLy4UF4uKBZWczFC3c,5291
@@ -70,9 +70,9 @@ crypticorn/common/ansi_colors.py,sha256=-tMlUTE8NI7TPv7uj0kGRe-SI2hGaUNPKBFI_dfi
70
70
  crypticorn/common/auth.py,sha256=b7jhR8k7bQFfgokI_Eqji0MpfiyD4EhCoddefUSqs6Y,9925
71
71
  crypticorn/common/decorators.py,sha256=t5Y3vSJ-gt0n2vOYYjYN0dtzNXvZxrJs2SEItpzG8oo,1127
72
72
  crypticorn/common/enums.py,sha256=YE7ObydyWAKO8MOSQBwk9M1PzzaPvlnxc6Dbpu78QMk,787
73
- crypticorn/common/errors.py,sha256=VZlZ_vA_9MhNhz8vURUiwHMoF9EjteqIYWHtSLLYRVM,30130
73
+ crypticorn/common/errors.py,sha256=qPCYpmxw0uZNmQw9RYj9vUsg-_R5aRn7fYE8qxTAnyA,30129
74
74
  crypticorn/common/exceptions.py,sha256=4oT58wcL9zQuqYU8op_36uZ1Kzt7JRCccu-o_usgqtU,6392
75
- crypticorn/common/logging.py,sha256=3ZTFB9j8Mqy_AlNYABUFQ_134OH0YtophJkP4_GDJ9w,4408
75
+ crypticorn/common/logging.py,sha256=n-qaYreRNFVAFRUd91hzYoaTExNLysd9cgEXm-v6eJY,4440
76
76
  crypticorn/common/middleware.py,sha256=O7XiXPimNYUhF9QTv6yFUTVlb91-SK-3CfTrWMNP6Ck,1011
77
77
  crypticorn/common/mixins.py,sha256=l7XQrBISaee6fDZXy96k0HnQ18XYocjTUXlNpVxhaOY,2206
78
78
  crypticorn/common/openapi.py,sha256=D8bCpCVVzYQptHrJ7SYOgCxI3R_d0cjW9KMOBq-x0xk,279
@@ -226,7 +226,7 @@ crypticorn/pay/client/models/provider.py,sha256=w2gJkEoTBnW-VluQ3AYLouWelszdf8Y4
226
226
  crypticorn/pay/client/models/scope.py,sha256=tHhMZxKekwRw7--gljw5ocYXk7Sm1XyEJlaOQdiL-Y4,2457
227
227
  crypticorn/pay/client/models/subscription.py,sha256=mkSaNn4bXIGRPCsGxwDoPjvhXYhgCFaeZhmeAASNSf4,3140
228
228
  crypticorn/trade/__init__.py,sha256=QzScH9n-ly3QSaBSpPP7EqYwhdzDqYCZJs0-AhEhrsY,84
229
- crypticorn/trade/main.py,sha256=0OwqqB98nksnAq_HcsY0Z78DllXRFHvbBupAR5lRdIk,1339
229
+ crypticorn/trade/main.py,sha256=Uzbw9D7q8_sngIaSxv9EBqIEoz0lJI5yYVJdERju0R0,1349
230
230
  crypticorn/trade/client/__init__.py,sha256=JVxS3kclaAweWNybWSSxHA7J4LQYWL8gb95NDTj64Rw,4094
231
231
  crypticorn/trade/client/api_client.py,sha256=jcNo7CbwCmLd1whXXVnkH378MWnw_wlKzJ07L4RpCog,26966
232
232
  crypticorn/trade/client/api_response.py,sha256=WhxwYDSMm6wPixp9CegO8dJzjFxDz3JF1yCq9s0ZqKE,639
@@ -279,9 +279,9 @@ crypticorn/trade/client/models/strategy_update.py,sha256=f7UsKSlNardj5h6uqHYbacj
279
279
  crypticorn/trade/client/models/tpsl.py,sha256=lLPVSvLETgLMFqH9wEBUTQXY6aaydMifEt47mYbfw-A,4111
280
280
  crypticorn/trade/client/models/tpsl_create.py,sha256=nX4i2BGWv5rmu3SLgRngfvEMFOWa3CIy0G3fyoxI-e4,3351
281
281
  crypticorn/trade/client/models/trading_action_type.py,sha256=BysUEOl85zs79EA2zOcDN1EExcpQdABaJ4Jz08_z8VU,857
282
- crypticorn-2.13.2.dist-info/licenses/LICENSE,sha256=HonAVvzFXkP2C1d7D3ByIKPwjGH8NcHTAQvKH7uvOHQ,1856
283
- crypticorn-2.13.2.dist-info/METADATA,sha256=5ra60bQWOCW0s-2eHoL45FBF9ofioCEdyrjRfxCQJA0,9490
284
- crypticorn-2.13.2.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
285
- crypticorn-2.13.2.dist-info/entry_points.txt,sha256=d_xHsGvUTebPveVUK0SrpDFQ5ZRSjlI7lNCc11sn2PM,59
286
- crypticorn-2.13.2.dist-info/top_level.txt,sha256=EP3NY216qIBYfmvGl0L2Zc9ItP0DjGSkiYqd9xJwGcM,11
287
- crypticorn-2.13.2.dist-info/RECORD,,
282
+ crypticorn-2.14.0.dist-info/licenses/LICENSE,sha256=HonAVvzFXkP2C1d7D3ByIKPwjGH8NcHTAQvKH7uvOHQ,1856
283
+ crypticorn-2.14.0.dist-info/METADATA,sha256=h1yBg54-gCo7aHAwg7Tvp0O_dq0ZsaJ6Ipq2ZO3F0n0,9993
284
+ crypticorn-2.14.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
285
+ crypticorn-2.14.0.dist-info/entry_points.txt,sha256=d_xHsGvUTebPveVUK0SrpDFQ5ZRSjlI7lNCc11sn2PM,59
286
+ crypticorn-2.14.0.dist-info/top_level.txt,sha256=EP3NY216qIBYfmvGl0L2Zc9ItP0DjGSkiYqd9xJwGcM,11
287
+ crypticorn-2.14.0.dist-info/RECORD,,