crypticorn 2.5.1__py3-none-any.whl → 2.5.3__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 (191) hide show
  1. crypticorn/cli/init.py +3 -0
  2. crypticorn/common/__init__.py +1 -0
  3. crypticorn/common/enums.py +3 -1
  4. crypticorn/common/errors.py +42 -21
  5. crypticorn/common/mixins.py +20 -0
  6. crypticorn/common/scopes.py +4 -20
  7. crypticorn/common/status_router.py +44 -0
  8. crypticorn/common/utils.py +13 -14
  9. crypticorn/hive/client/__init__.py +1 -5
  10. crypticorn/hive/client/api/data_api.py +1 -33
  11. crypticorn/hive/client/api/models_api.py +8 -104
  12. crypticorn/hive/client/api/status_api.py +481 -9
  13. crypticorn/hive/client/configuration.py +12 -4
  14. crypticorn/hive/client/models/__init__.py +1 -5
  15. crypticorn/hive/client/models/coins.py +0 -1
  16. crypticorn/hive/client/models/data_version.py +0 -1
  17. crypticorn/{metrics/client/models/error_response.py → hive/client/models/exception_detail.py} +26 -21
  18. crypticorn/hive/client/rest.py +4 -1
  19. crypticorn/klines/client/__init__.py +0 -5
  20. crypticorn/klines/client/api/change_in_timeframe_api.py +8 -9
  21. crypticorn/klines/client/api/ohlcv_data_api.py +7 -8
  22. crypticorn/klines/client/api/status_api.py +481 -6
  23. crypticorn/klines/client/api/symbols_api.py +7 -8
  24. crypticorn/klines/client/api/udf_api.py +0 -227
  25. crypticorn/klines/client/models/__init__.py +0 -5
  26. crypticorn/klines/client/models/exception_detail.py +3 -6
  27. crypticorn/klines/client/models/search_symbol.py +4 -3
  28. crypticorn/klines/client/models/udf_config.py +1 -2
  29. crypticorn/metrics/client/__init__.py +1 -6
  30. crypticorn/metrics/client/api/exchanges_api.py +29 -31
  31. crypticorn/metrics/client/api/indicators_api.py +15 -16
  32. crypticorn/metrics/client/api/logs_api.py +1 -1
  33. crypticorn/metrics/client/api/marketcap_api.py +15 -16
  34. crypticorn/metrics/client/api/markets_api.py +15 -16
  35. crypticorn/metrics/client/api/status_api.py +477 -2
  36. crypticorn/metrics/client/api/tokens_api.py +1 -1
  37. crypticorn/metrics/client/api_client.py +1 -1
  38. crypticorn/metrics/client/configuration.py +3 -5
  39. crypticorn/metrics/client/exceptions.py +1 -1
  40. crypticorn/metrics/client/models/__init__.py +1 -6
  41. crypticorn/metrics/client/models/exception_detail.py +4 -7
  42. crypticorn/metrics/client/models/severity.py +1 -1
  43. crypticorn/metrics/client/models/time_interval.py +1 -1
  44. crypticorn/metrics/client/models/trading_status.py +1 -1
  45. crypticorn/metrics/client/rest.py +1 -1
  46. crypticorn/pay/client/__init__.py +3 -8
  47. crypticorn/pay/client/api/now_payments_api.py +14 -17
  48. crypticorn/pay/client/api/payments_api.py +2 -11
  49. crypticorn/pay/client/api/products_api.py +2 -11
  50. crypticorn/pay/client/api/status_api.py +483 -8
  51. crypticorn/pay/client/api_client.py +2 -2
  52. crypticorn/pay/client/configuration.py +3 -3
  53. crypticorn/pay/client/exceptions.py +2 -2
  54. crypticorn/pay/client/models/__init__.py +3 -8
  55. crypticorn/{metrics/client/models/base_response_dict.py → pay/client/models/exception_detail.py} +28 -20
  56. crypticorn/pay/client/models/now_create_invoice_req.py +2 -2
  57. crypticorn/pay/client/models/now_create_invoice_res.py +2 -2
  58. crypticorn/pay/client/models/payment.py +2 -2
  59. crypticorn/pay/client/models/payment_status.py +2 -2
  60. crypticorn/pay/client/models/product_create.py +2 -2
  61. crypticorn/pay/client/models/product_read.py +2 -2
  62. crypticorn/pay/client/models/product_sub_read.py +2 -2
  63. crypticorn/pay/client/models/product_update.py +2 -2
  64. crypticorn/pay/client/models/scope.py +2 -2
  65. crypticorn/pay/client/models/services.py +2 -2
  66. crypticorn/pay/client/rest.py +2 -2
  67. crypticorn/trade/client/__init__.py +4 -9
  68. crypticorn/trade/client/api/api_keys_api.py +5 -20
  69. crypticorn/trade/client/api/bots_api.py +7 -19
  70. crypticorn/trade/client/api/exchanges_api.py +8 -8
  71. crypticorn/trade/client/api/futures_trading_panel_api.py +10 -22
  72. crypticorn/trade/client/api/notifications_api.py +10 -25
  73. crypticorn/trade/client/api/orders_api.py +2 -5
  74. crypticorn/trade/client/api/status_api.py +483 -8
  75. crypticorn/trade/client/api/strategies_api.py +5 -17
  76. crypticorn/trade/client/api/trading_actions_api.py +18 -26
  77. crypticorn/trade/client/api_client.py +2 -2
  78. crypticorn/trade/client/configuration.py +5 -5
  79. crypticorn/trade/client/exceptions.py +2 -2
  80. crypticorn/trade/client/models/__init__.py +4 -9
  81. crypticorn/trade/client/models/action_model.py +3 -4
  82. crypticorn/trade/client/models/bot_model.py +2 -2
  83. crypticorn/trade/client/models/bot_status.py +2 -2
  84. crypticorn/{klines/client/models/error_response.py → trade/client/models/exception_detail.py} +26 -21
  85. crypticorn/trade/client/models/exchange_key_model.py +4 -13
  86. crypticorn/trade/client/models/execution_ids.py +2 -2
  87. crypticorn/trade/client/models/futures_balance.py +2 -2
  88. crypticorn/trade/client/models/futures_trading_action.py +3 -4
  89. crypticorn/trade/client/models/margin_mode.py +2 -2
  90. crypticorn/trade/client/models/notification_model.py +2 -2
  91. crypticorn/trade/client/models/order_model.py +6 -16
  92. crypticorn/trade/client/models/order_status.py +2 -2
  93. crypticorn/trade/client/models/post_futures_action.py +2 -2
  94. crypticorn/trade/client/models/spot_trading_action.py +3 -4
  95. crypticorn/trade/client/models/strategy_exchange_info.py +4 -5
  96. crypticorn/trade/client/models/strategy_model_input.py +3 -4
  97. crypticorn/trade/client/models/strategy_model_output.py +3 -4
  98. crypticorn/trade/client/models/tpsl.py +5 -3
  99. crypticorn/trade/client/models/trading_action_type.py +2 -2
  100. crypticorn/trade/client/rest.py +2 -2
  101. {crypticorn-2.5.1.dist-info → crypticorn-2.5.3.dist-info}/METADATA +1 -1
  102. crypticorn-2.5.3.dist-info/RECORD +223 -0
  103. crypticorn/hive/client/models/http_validation_error.py +0 -99
  104. crypticorn/hive/client/models/validation_error.py +0 -105
  105. crypticorn/hive/client/models/validation_error_loc_inner.py +0 -159
  106. crypticorn/klines/client/api/health_check_api.py +0 -265
  107. crypticorn/klines/client/models/api_error_identifier.py +0 -108
  108. crypticorn/klines/client/models/api_error_level.py +0 -37
  109. crypticorn/klines/client/models/api_error_type.py +0 -37
  110. crypticorn/klines/client/models/base_response_health_check_response.py +0 -114
  111. crypticorn/klines/client/models/base_response_list_change_in_timeframe_response.py +0 -123
  112. crypticorn/klines/client/models/base_response_list_funding_rate_response.py +0 -118
  113. crypticorn/klines/client/models/base_response_list_str.py +0 -106
  114. crypticorn/klines/client/models/base_response_ohlcv_response.py +0 -114
  115. crypticorn/klines/client/models/change_in_timeframe_response.py +0 -86
  116. crypticorn/klines/client/models/exchange.py +0 -91
  117. crypticorn/klines/client/models/funding_rate_response.py +0 -92
  118. crypticorn/klines/client/models/health_check_response.py +0 -91
  119. crypticorn/klines/client/models/history_error_response.py +0 -89
  120. crypticorn/klines/client/models/history_no_data_response.py +0 -99
  121. crypticorn/klines/client/models/history_success_response.py +0 -99
  122. crypticorn/klines/client/models/http_validation_error.py +0 -99
  123. crypticorn/klines/client/models/internal_exchange.py +0 -39
  124. crypticorn/klines/client/models/market.py +0 -35
  125. crypticorn/klines/client/models/market_type.py +0 -35
  126. crypticorn/klines/client/models/ohlcv_response.py +0 -105
  127. crypticorn/klines/client/models/response_get_history_udf_history_get.py +0 -198
  128. crypticorn/klines/client/models/response_get_udf_history.py +0 -198
  129. crypticorn/klines/client/models/search_symbol_response.py +0 -104
  130. crypticorn/klines/client/models/symbol_group_response.py +0 -83
  131. crypticorn/klines/client/models/symbol_info_response.py +0 -131
  132. crypticorn/klines/client/models/udf_config_response.py +0 -160
  133. crypticorn/klines/client/models/validation_error.py +0 -105
  134. crypticorn/klines/client/models/validation_error_loc_inner.py +0 -159
  135. crypticorn/metrics/client/api/health_check_api.py +0 -265
  136. crypticorn/metrics/client/models/api_error_identifier.py +0 -108
  137. crypticorn/metrics/client/models/api_error_level.py +0 -37
  138. crypticorn/metrics/client/models/api_error_type.py +0 -37
  139. crypticorn/metrics/client/models/base_response_health_check_response.py +0 -114
  140. crypticorn/metrics/client/models/base_response_list_dict.py +0 -106
  141. crypticorn/metrics/client/models/base_response_list_exchange_mapping.py +0 -118
  142. crypticorn/metrics/client/models/base_response_list_str.py +0 -106
  143. crypticorn/metrics/client/models/exchange_mapping.py +0 -134
  144. crypticorn/metrics/client/models/health_check_response.py +0 -91
  145. crypticorn/metrics/client/models/http_validation_error.py +0 -99
  146. crypticorn/metrics/client/models/internal_exchange.py +0 -39
  147. crypticorn/metrics/client/models/market.py +0 -35
  148. crypticorn/metrics/client/models/market_type.py +0 -35
  149. crypticorn/metrics/client/models/validation_error.py +0 -105
  150. crypticorn/metrics/client/models/validation_error_loc_inner.py +0 -159
  151. crypticorn/pay/client/models/api_status_res.py +0 -83
  152. crypticorn/pay/client/models/body_create_now_invoice.py +0 -98
  153. crypticorn/pay/client/models/body_create_product.py +0 -98
  154. crypticorn/pay/client/models/body_get_products.py +0 -87
  155. crypticorn/pay/client/models/body_handle_now_webhook.py +0 -98
  156. crypticorn/pay/client/models/body_update_product.py +0 -98
  157. crypticorn/pay/client/models/combined_payment_history.py +0 -101
  158. crypticorn/pay/client/models/create_invoice_req.py +0 -188
  159. crypticorn/pay/client/models/create_invoice_res.py +0 -188
  160. crypticorn/pay/client/models/currency.py +0 -165
  161. crypticorn/pay/client/models/estimate_price_req.py +0 -91
  162. crypticorn/pay/client/models/estimate_price_res.py +0 -102
  163. crypticorn/pay/client/models/get_currencies_res.py +0 -99
  164. crypticorn/pay/client/models/get_payment_status_res.py +0 -222
  165. crypticorn/pay/client/models/get_payments_list_res.py +0 -109
  166. crypticorn/pay/client/models/http_validation_error.py +0 -99
  167. crypticorn/pay/client/models/min_amount_req.py +0 -124
  168. crypticorn/pay/client/models/min_amount_res.py +0 -105
  169. crypticorn/pay/client/models/now_api_status_res.py +0 -83
  170. crypticorn/pay/client/models/now_fee_structure.py +0 -104
  171. crypticorn/pay/client/models/now_payment_model.py +0 -124
  172. crypticorn/pay/client/models/now_payment_status.py +0 -42
  173. crypticorn/pay/client/models/now_webhook_payload.py +0 -181
  174. crypticorn/pay/client/models/partial_product_update_model.py +0 -150
  175. crypticorn/pay/client/models/product.py +0 -87
  176. crypticorn/pay/client/models/product_model.py +0 -128
  177. crypticorn/pay/client/models/product_subs_model.py +0 -108
  178. crypticorn/pay/client/models/product_update_model.py +0 -150
  179. crypticorn/pay/client/models/unified_payment_model.py +0 -112
  180. crypticorn/pay/client/models/validation_error.py +0 -105
  181. crypticorn/pay/client/models/validation_error_loc_inner.py +0 -159
  182. crypticorn/trade/client/models/api_key_model.py +0 -156
  183. crypticorn/trade/client/models/exchange.py +0 -35
  184. crypticorn/trade/client/models/http_validation_error.py +0 -99
  185. crypticorn/trade/client/models/market_type.py +0 -35
  186. crypticorn/trade/client/models/validation_error.py +0 -105
  187. crypticorn/trade/client/models/validation_error_loc_inner.py +0 -159
  188. crypticorn-2.5.1.dist-info/RECORD +0 -307
  189. {crypticorn-2.5.1.dist-info → crypticorn-2.5.3.dist-info}/WHEEL +0 -0
  190. {crypticorn-2.5.1.dist-info → crypticorn-2.5.3.dist-info}/entry_points.txt +0 -0
  191. {crypticorn-2.5.1.dist-info → crypticorn-2.5.3.dist-info}/top_level.txt +0 -0
crypticorn/cli/init.py CHANGED
@@ -92,6 +92,9 @@ def init_auth(output, force):
92
92
  and the docker-compose.yml file with:
93
93
  environment:
94
94
  - IS_DOCKER=1
95
+ and the .github/workflows/main.yaml file with:
96
+ env:
97
+ API_ENV: ${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}
95
98
  """,
96
99
  fg="yellow",
97
100
  )
@@ -7,3 +7,4 @@ from crypticorn.common.auth import *
7
7
  from crypticorn.common.enums import *
8
8
  from crypticorn.common.utils import *
9
9
  from crypticorn.common.exceptions import *
10
+ from crypticorn.common.status_router import router as status_router
@@ -1,5 +1,7 @@
1
1
  from enum import StrEnum
2
2
  from crypticorn.common.mixins import ValidateEnumMixin, ExcludeEnumMixin
3
+
4
+
3
5
  class Exchange(ValidateEnumMixin, ExcludeEnumMixin, StrEnum):
4
6
  """Supported exchanges for trading"""
5
7
 
@@ -24,4 +26,4 @@ class MarketType(ValidateEnumMixin, ExcludeEnumMixin, StrEnum):
24
26
  """
25
27
 
26
28
  SPOT = "spot"
27
- FUTURES = "futures"
29
+ FUTURES = "futures"
@@ -1,22 +1,7 @@
1
1
  from enum import Enum, EnumMeta, StrEnum
2
2
  import logging
3
3
  from fastapi import status
4
- from crypticorn.common.mixins import ExcludeEnumMixin
5
-
6
- logger = logging.getLogger(__name__)
7
-
8
-
9
- class Fallback(EnumMeta):
10
- """Fallback to UNKNOWN_ERROR for error codes not yet published to PyPI."""
11
-
12
- def __getattr__(cls, name):
13
- # Let Pydantic/internal stuff pass silently ! fragile
14
- if name.startswith("__"):
15
- raise AttributeError(name)
16
- logger.warning(
17
- f"Unknown error code '{name}' - update crypticorn package or check for typos"
18
- )
19
- return cls.UNKNOWN_ERROR
4
+ from crypticorn.common.mixins import ExcludeEnumMixin, ApiErrorFallback
20
5
 
21
6
 
22
7
  class ApiErrorType(ExcludeEnumMixin, StrEnum):
@@ -42,6 +27,7 @@ class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
42
27
  BOT_ALREADY_DELETED = "bot_already_deleted"
43
28
  BOT_DISABLED = "bot_disabled"
44
29
  BOT_STOPPING_COMPLETED = "bot_stopping_completed"
30
+ BOT_STOPPING_STARTED = "bot_stopping_started"
45
31
  CLIENT_ORDER_ID_REPEATED = "client_order_id_already_exists"
46
32
  CONTENT_TYPE_ERROR = "invalid_content_type"
47
33
  DELETE_BOT_ERROR = "delete_bot_error"
@@ -77,8 +63,11 @@ class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
77
63
  LIQUIDATION_PRICE_VIOLATION = "order_violates_liquidation_price_constraints"
78
64
  NO_CREDENTIALS = "no_credentials"
79
65
  NOW_API_DOWN = "now_api_down"
80
- OBJECT_NOT_FOUND = "object_not_found"
81
66
  OBJECT_ALREADY_EXISTS = "object_already_exists"
67
+ OBJECT_CREATED = "object_created"
68
+ OBJECT_DELETED = "object_deleted"
69
+ OBJECT_NOT_FOUND = "object_not_found"
70
+ OBJECT_UPDATED = "object_updated"
82
71
  ORDER_ALREADY_FILLED = "order_is_already_filled"
83
72
  ORDER_IN_PROCESS = "order_is_being_processed"
84
73
  ORDER_LIMIT_EXCEEDED = "order_quantity_limit_exceeded"
@@ -94,6 +83,7 @@ class ApiErrorIdentifier(ExcludeEnumMixin, StrEnum):
94
83
  RISK_LIMIT_EXCEEDED = "risk_limit_exceeded"
95
84
  RPC_TIMEOUT = "rpc_timeout"
96
85
  SETTLEMENT_IN_PROGRESS = "system_settlement_in_process"
86
+ STRATEGY_ALREADY_EXISTS = "strategy_already_exists"
97
87
  STRATEGY_DISABLED = "strategy_disabled"
98
88
  STRATEGY_LEVERAGE_MISMATCH = "strategy_leverage_mismatch"
99
89
  STRATEGY_NOT_SUPPORTING_EXCHANGE = "strategy_not_supporting_exchange"
@@ -121,7 +111,7 @@ class ApiErrorLevel(ExcludeEnumMixin, StrEnum):
121
111
  WARNING = "warning"
122
112
 
123
113
 
124
- class ApiError(ExcludeEnumMixin, Enum, metaclass=Fallback):
114
+ class ApiError(ExcludeEnumMixin, Enum, metaclass=ApiErrorFallback):
125
115
  """API error codes. Fallback to UNKNOWN_ERROR for error codes not yet published to PyPI."""
126
116
 
127
117
  ALLOCATION_BELOW_EXPOSURE = (
@@ -159,6 +149,11 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=Fallback):
159
149
  ApiErrorType.NO_ERROR,
160
150
  ApiErrorLevel.INFO,
161
151
  )
152
+ BOT_STOPPING_STARTED = (
153
+ ApiErrorIdentifier.BOT_STOPPING_STARTED,
154
+ ApiErrorType.NO_ERROR,
155
+ ApiErrorLevel.INFO,
156
+ )
162
157
  CLIENT_ORDER_ID_REPEATED = (
163
158
  ApiErrorIdentifier.CLIENT_ORDER_ID_REPEATED,
164
159
  ApiErrorType.SERVER_ERROR,
@@ -334,15 +329,30 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=Fallback):
334
329
  ApiErrorType.SERVER_ERROR,
335
330
  ApiErrorLevel.ERROR,
336
331
  )
332
+ OBJECT_ALREADY_EXISTS = (
333
+ ApiErrorIdentifier.OBJECT_ALREADY_EXISTS,
334
+ ApiErrorType.SERVER_ERROR,
335
+ ApiErrorLevel.ERROR,
336
+ )
337
+ OBJECT_CREATED = (
338
+ ApiErrorIdentifier.OBJECT_CREATED,
339
+ ApiErrorType.SERVER_ERROR,
340
+ ApiErrorLevel.INFO,
341
+ )
342
+ OBJECT_DELETED = (
343
+ ApiErrorIdentifier.OBJECT_DELETED,
344
+ ApiErrorType.SERVER_ERROR,
345
+ ApiErrorLevel.INFO,
346
+ )
337
347
  OBJECT_NOT_FOUND = (
338
348
  ApiErrorIdentifier.OBJECT_NOT_FOUND,
339
349
  ApiErrorType.SERVER_ERROR,
340
350
  ApiErrorLevel.ERROR,
341
351
  )
342
- OBJECT_ALREADY_EXISTS = (
343
- ApiErrorIdentifier.OBJECT_ALREADY_EXISTS,
352
+ OBJECT_UPDATED = (
353
+ ApiErrorIdentifier.OBJECT_UPDATED,
344
354
  ApiErrorType.SERVER_ERROR,
345
- ApiErrorLevel.ERROR,
355
+ ApiErrorLevel.INFO,
346
356
  )
347
357
  ORDER_ALREADY_FILLED = (
348
358
  ApiErrorIdentifier.ORDER_ALREADY_FILLED,
@@ -419,6 +429,11 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=Fallback):
419
429
  ApiErrorType.EXCHANGE_ERROR,
420
430
  ApiErrorLevel.ERROR,
421
431
  )
432
+ STRATEGY_ALREADY_EXISTS = (
433
+ ApiErrorIdentifier.STRATEGY_ALREADY_EXISTS,
434
+ ApiErrorType.USER_ERROR,
435
+ ApiErrorLevel.ERROR,
436
+ )
422
437
  STRATEGY_DISABLED = (
423
438
  ApiErrorIdentifier.STRATEGY_DISABLED,
424
439
  ApiErrorType.USER_ERROR,
@@ -494,6 +509,7 @@ class ApiError(ExcludeEnumMixin, Enum, metaclass=Fallback):
494
509
 
495
510
  class HttpStatusMapper:
496
511
  """Map API errors to HTTP status codes."""
512
+
497
513
  _mapping = {
498
514
  # Authentication/Authorization
499
515
  ApiError.EXPIRED_BEARER: status.HTTP_401_UNAUTHORIZED,
@@ -517,6 +533,7 @@ class HttpStatusMapper:
517
533
  ApiError.OBJECT_ALREADY_EXISTS: status.HTTP_409_CONFLICT,
518
534
  ApiError.EXCHANGE_KEY_ALREADY_EXISTS: status.HTTP_409_CONFLICT,
519
535
  ApiError.BOT_ALREADY_DELETED: status.HTTP_409_CONFLICT,
536
+ ApiError.STRATEGY_ALREADY_EXISTS: status.HTTP_409_CONFLICT,
520
537
  # Invalid Content
521
538
  ApiError.CONTENT_TYPE_ERROR: status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
522
539
  ApiError.INVALID_DATA_REQUEST: status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -574,6 +591,10 @@ class HttpStatusMapper:
574
591
  # Success cases
575
592
  ApiError.SUCCESS: status.HTTP_200_OK,
576
593
  ApiError.BOT_STOPPING_COMPLETED: status.HTTP_200_OK,
594
+ ApiError.BOT_STOPPING_STARTED: status.HTTP_200_OK,
595
+ ApiError.OBJECT_CREATED: status.HTTP_201_CREATED,
596
+ ApiError.OBJECT_UPDATED: status.HTTP_200_OK,
597
+ ApiError.OBJECT_DELETED: status.HTTP_204_NO_CONTENT,
577
598
  }
578
599
 
579
600
  @classmethod
@@ -1,3 +1,9 @@
1
+ from enum import EnumMeta
2
+ import logging
3
+
4
+ logger = logging.getLogger("uvicorn")
5
+
6
+
1
7
  class ValidateEnumMixin:
2
8
  """
3
9
  Mixin for validating enum values manually.
@@ -26,6 +32,7 @@ class ValidateEnumMixin:
26
32
  except ValueError:
27
33
  return False
28
34
 
35
+
29
36
  class ExcludeEnumMixin:
30
37
  """Mixin to exclude enum from OpenAPI schema. We use this to avoid duplicating enums when generating client code from the openapi spec."""
31
38
 
@@ -34,3 +41,16 @@ class ExcludeEnumMixin:
34
41
  schema = handler(core_schema)
35
42
  schema.pop("enum", None)
36
43
  return schema
44
+
45
+
46
+ class ApiErrorFallback(EnumMeta):
47
+ """Fallback for enum members that are not yet published to PyPI."""
48
+
49
+ def __getattr__(cls, name):
50
+ # Let Pydantic/internal stuff pass silently ! fragile
51
+ if name.startswith("__"):
52
+ raise AttributeError(name)
53
+ logger.warning(
54
+ f"Unknown enum member '{name}' - update crypticorn package or check for typos"
55
+ )
56
+ return cls.UNKNOWN_ERROR
@@ -1,25 +1,6 @@
1
- from enum import StrEnum, EnumMeta
1
+ from enum import StrEnum
2
2
  import logging
3
3
 
4
- logger = logging.getLogger("uvicorn")
5
-
6
-
7
- class Fallback(EnumMeta):
8
- """Fallback to no scope for unknown scopes."""
9
-
10
- # Note: This is a workaround to avoid the AttributeError when an unknown scope is accessed.
11
- # As soon as we have stable scopes, we can remove this.
12
-
13
- def __getattr__(cls, name):
14
- # Let Pydantic/internal stuff pass silently ! fragile
15
- if name.startswith("__"):
16
- raise AttributeError(name)
17
- logger.warning(
18
- f"Unknown scope '{name}' - falling back to no scope - update crypticorn package or check for typos"
19
- )
20
- return None
21
-
22
-
23
4
  class Scope(StrEnum):
24
5
  """
25
6
  The permission scopes for the API.
@@ -68,3 +49,6 @@ class Scope(StrEnum):
68
49
  READ_METRICS_EXCHANGES = "read:metrics:exchanges"
69
50
  READ_METRICS_TOKENS = "read:metrics:tokens"
70
51
  READ_METRICS_MARKETS = "read:metrics:markets"
52
+
53
+ # Sentiment scopes
54
+ READ_SENTIMENT = "read:sentiment"
@@ -0,0 +1,44 @@
1
+ from datetime import datetime
2
+ from typing import Literal
3
+ from fastapi import APIRouter
4
+
5
+ router = APIRouter(tags=["Status"], prefix="")
6
+
7
+
8
+ @router.get("/", operation_id="ping")
9
+ async def ping() -> str:
10
+ """
11
+ Returns 'OK' if the API is running.
12
+ """
13
+ return "OK"
14
+
15
+
16
+ @router.get("/time", operation_id="getTime")
17
+ async def time(type: Literal["iso", "unix"] = "iso") -> str:
18
+ """
19
+ Returns the current time in the specified format.
20
+ """
21
+ if type == "iso":
22
+ return datetime.now().isoformat()
23
+ else:
24
+ return str(int(datetime.now().timestamp()))
25
+
26
+
27
+ @router.get("/config", operation_id="getConfig")
28
+ async def config() -> dict:
29
+ """
30
+ Returns the version of the crypticorn library and the environment.
31
+ """
32
+ import importlib.metadata
33
+ import os
34
+ from dotenv import load_dotenv
35
+
36
+ load_dotenv()
37
+ try:
38
+ crypticorn_version = importlib.metadata.version("crypticorn")
39
+ except importlib.metadata.PackageNotFoundError:
40
+ crypticorn_version = "not installed"
41
+ return {
42
+ "crypticorn": f"v{crypticorn_version}",
43
+ "environment": os.getenv("API_ENV", "not set"),
44
+ }
@@ -2,29 +2,28 @@ from typing import Any, Union
2
2
  from decimal import Decimal
3
3
  import string
4
4
  import random
5
- from fastapi import HTTPException
6
5
  from fastapi import status
7
6
  from typing_extensions import deprecated
8
7
 
9
- from crypticorn.common import ApiError
8
+ from crypticorn.common import ApiError, HTTPException, ExceptionContent
10
9
 
11
10
 
12
- def throw_if_none(value: Any, message: Union[ApiError, str]) -> None:
13
- """Throws an FastAPI HTTPException if the value is None."""
11
+ def throw_if_none(
12
+ value: Any,
13
+ exception: ExceptionContent = ExceptionContent(error=ApiError.OBJECT_NOT_FOUND),
14
+ ) -> None:
15
+ """Throws an FastAPI HTTPException if the value is None. https://docs.python.org/3/library/stdtypes.html#truth-value-testing"""
14
16
  if value is None:
15
- raise HTTPException(
16
- status_code=status.HTTP_404_NOT_FOUND,
17
- detail=message.identifier if isinstance(message, ApiError) else message,
18
- )
17
+ raise HTTPException(content=exception)
19
18
 
20
19
 
21
- def throw_if_falsy(value: Any, message: Union[ApiError, str]) -> None:
22
- """Throws an FastAPI HTTPException if the value is False."""
20
+ def throw_if_falsy(
21
+ value: Any,
22
+ exception: ExceptionContent = ExceptionContent(error=ApiError.OBJECT_NOT_FOUND),
23
+ ) -> None:
24
+ """Throws an FastAPI HTTPException if the value is False. https://docs.python.org/3/library/stdtypes.html#truth-value-testing"""
23
25
  if not value:
24
- raise HTTPException(
25
- status_code=status.HTTP_400_BAD_REQUEST,
26
- detail=message.identifier if isinstance(message, ApiError) else message,
27
- )
26
+ raise HTTPException(content=exception)
28
27
 
29
28
 
30
29
  def gen_random_id(length: int = 20) -> str:
@@ -43,15 +43,11 @@ from crypticorn.hive.client.models.data_version import DataVersion
43
43
  from crypticorn.hive.client.models.download_links import DownloadLinks
44
44
  from crypticorn.hive.client.models.evaluation import Evaluation
45
45
  from crypticorn.hive.client.models.evaluation_response import EvaluationResponse
46
+ from crypticorn.hive.client.models.exception_detail import ExceptionDetail
46
47
  from crypticorn.hive.client.models.feature_size import FeatureSize
47
- from crypticorn.hive.client.models.http_validation_error import HTTPValidationError
48
48
  from crypticorn.hive.client.models.model import Model
49
49
  from crypticorn.hive.client.models.model_create import ModelCreate
50
50
  from crypticorn.hive.client.models.model_status import ModelStatus
51
51
  from crypticorn.hive.client.models.model_update import ModelUpdate
52
52
  from crypticorn.hive.client.models.target import Target
53
53
  from crypticorn.hive.client.models.target_type import TargetType
54
- from crypticorn.hive.client.models.validation_error import ValidationError
55
- from crypticorn.hive.client.models.validation_error_loc_inner import (
56
- ValidationErrorLocInner,
57
- )
@@ -16,7 +16,7 @@ from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
16
16
  from typing import Any, Dict, List, Optional, Tuple, Union
17
17
  from typing_extensions import Annotated
18
18
 
19
- from pydantic import Field, StrictInt, StrictStr
19
+ from pydantic import Field, StrictInt
20
20
  from typing import Optional
21
21
  from typing_extensions import Annotated
22
22
  from crypticorn.hive.client.models.data_download_response import DataDownloadResponse
@@ -52,7 +52,6 @@ class DataApi:
52
52
  feature_size: Annotated[
53
53
  Optional[FeatureSize], Field(description="Feature size")
54
54
  ] = None,
55
- access_token: Optional[StrictStr] = None,
56
55
  _request_timeout: Union[
57
56
  None,
58
57
  Annotated[StrictFloat, Field(gt=0)],
@@ -75,8 +74,6 @@ class DataApi:
75
74
  :type version: DataVersion
76
75
  :param feature_size: Feature size
77
76
  :type feature_size: FeatureSize
78
- :param access_token:
79
- :type access_token: str
80
77
  :param _request_timeout: timeout setting for this request. If one
81
78
  number provided, it will be total request
82
79
  timeout. It can also be a pair (tuple) of
@@ -103,7 +100,6 @@ class DataApi:
103
100
  model_id=model_id,
104
101
  version=version,
105
102
  feature_size=feature_size,
106
- access_token=access_token,
107
103
  _request_auth=_request_auth,
108
104
  _content_type=_content_type,
109
105
  _headers=_headers,
@@ -112,7 +108,6 @@ class DataApi:
112
108
 
113
109
  _response_types_map: Dict[str, Optional[str]] = {
114
110
  "200": "DataDownloadResponse",
115
- "422": "HTTPValidationError",
116
111
  }
117
112
  response_data = await self.api_client.call_api(
118
113
  *_param, _request_timeout=_request_timeout
@@ -134,7 +129,6 @@ class DataApi:
134
129
  feature_size: Annotated[
135
130
  Optional[FeatureSize], Field(description="Feature size")
136
131
  ] = None,
137
- access_token: Optional[StrictStr] = None,
138
132
  _request_timeout: Union[
139
133
  None,
140
134
  Annotated[StrictFloat, Field(gt=0)],
@@ -157,8 +151,6 @@ class DataApi:
157
151
  :type version: DataVersion
158
152
  :param feature_size: Feature size
159
153
  :type feature_size: FeatureSize
160
- :param access_token:
161
- :type access_token: str
162
154
  :param _request_timeout: timeout setting for this request. If one
163
155
  number provided, it will be total request
164
156
  timeout. It can also be a pair (tuple) of
@@ -185,7 +177,6 @@ class DataApi:
185
177
  model_id=model_id,
186
178
  version=version,
187
179
  feature_size=feature_size,
188
- access_token=access_token,
189
180
  _request_auth=_request_auth,
190
181
  _content_type=_content_type,
191
182
  _headers=_headers,
@@ -194,7 +185,6 @@ class DataApi:
194
185
 
195
186
  _response_types_map: Dict[str, Optional[str]] = {
196
187
  "200": "DataDownloadResponse",
197
- "422": "HTTPValidationError",
198
188
  }
199
189
  response_data = await self.api_client.call_api(
200
190
  *_param, _request_timeout=_request_timeout
@@ -216,7 +206,6 @@ class DataApi:
216
206
  feature_size: Annotated[
217
207
  Optional[FeatureSize], Field(description="Feature size")
218
208
  ] = None,
219
- access_token: Optional[StrictStr] = None,
220
209
  _request_timeout: Union[
221
210
  None,
222
211
  Annotated[StrictFloat, Field(gt=0)],
@@ -239,8 +228,6 @@ class DataApi:
239
228
  :type version: DataVersion
240
229
  :param feature_size: Feature size
241
230
  :type feature_size: FeatureSize
242
- :param access_token:
243
- :type access_token: str
244
231
  :param _request_timeout: timeout setting for this request. If one
245
232
  number provided, it will be total request
246
233
  timeout. It can also be a pair (tuple) of
@@ -267,7 +254,6 @@ class DataApi:
267
254
  model_id=model_id,
268
255
  version=version,
269
256
  feature_size=feature_size,
270
- access_token=access_token,
271
257
  _request_auth=_request_auth,
272
258
  _content_type=_content_type,
273
259
  _headers=_headers,
@@ -276,7 +262,6 @@ class DataApi:
276
262
 
277
263
  _response_types_map: Dict[str, Optional[str]] = {
278
264
  "200": "DataDownloadResponse",
279
- "422": "HTTPValidationError",
280
265
  }
281
266
  response_data = await self.api_client.call_api(
282
267
  *_param, _request_timeout=_request_timeout
@@ -288,7 +273,6 @@ class DataApi:
288
273
  model_id,
289
274
  version,
290
275
  feature_size,
291
- access_token,
292
276
  _request_auth,
293
277
  _content_type,
294
278
  _headers,
@@ -353,7 +337,6 @@ class DataApi:
353
337
  @validate_call
354
338
  async def get_data_info(
355
339
  self,
356
- access_token: Optional[StrictStr] = None,
357
340
  _request_timeout: Union[
358
341
  None,
359
342
  Annotated[StrictFloat, Field(gt=0)],
@@ -370,8 +353,6 @@ class DataApi:
370
353
 
371
354
  Get information about available data and options for the latest data version
372
355
 
373
- :param access_token:
374
- :type access_token: str
375
356
  :param _request_timeout: timeout setting for this request. If one
376
357
  number provided, it will be total request
377
358
  timeout. It can also be a pair (tuple) of
@@ -395,7 +376,6 @@ class DataApi:
395
376
  """ # noqa: E501
396
377
 
397
378
  _param = self._get_data_info_serialize(
398
- access_token=access_token,
399
379
  _request_auth=_request_auth,
400
380
  _content_type=_content_type,
401
381
  _headers=_headers,
@@ -404,7 +384,6 @@ class DataApi:
404
384
 
405
385
  _response_types_map: Dict[str, Optional[str]] = {
406
386
  "200": "DataInfo",
407
- "422": "HTTPValidationError",
408
387
  }
409
388
  response_data = await self.api_client.call_api(
410
389
  *_param, _request_timeout=_request_timeout
@@ -418,7 +397,6 @@ class DataApi:
418
397
  @validate_call
419
398
  async def get_data_info_with_http_info(
420
399
  self,
421
- access_token: Optional[StrictStr] = None,
422
400
  _request_timeout: Union[
423
401
  None,
424
402
  Annotated[StrictFloat, Field(gt=0)],
@@ -435,8 +413,6 @@ class DataApi:
435
413
 
436
414
  Get information about available data and options for the latest data version
437
415
 
438
- :param access_token:
439
- :type access_token: str
440
416
  :param _request_timeout: timeout setting for this request. If one
441
417
  number provided, it will be total request
442
418
  timeout. It can also be a pair (tuple) of
@@ -460,7 +436,6 @@ class DataApi:
460
436
  """ # noqa: E501
461
437
 
462
438
  _param = self._get_data_info_serialize(
463
- access_token=access_token,
464
439
  _request_auth=_request_auth,
465
440
  _content_type=_content_type,
466
441
  _headers=_headers,
@@ -469,7 +444,6 @@ class DataApi:
469
444
 
470
445
  _response_types_map: Dict[str, Optional[str]] = {
471
446
  "200": "DataInfo",
472
- "422": "HTTPValidationError",
473
447
  }
474
448
  response_data = await self.api_client.call_api(
475
449
  *_param, _request_timeout=_request_timeout
@@ -483,7 +457,6 @@ class DataApi:
483
457
  @validate_call
484
458
  async def get_data_info_without_preload_content(
485
459
  self,
486
- access_token: Optional[StrictStr] = None,
487
460
  _request_timeout: Union[
488
461
  None,
489
462
  Annotated[StrictFloat, Field(gt=0)],
@@ -500,8 +473,6 @@ class DataApi:
500
473
 
501
474
  Get information about available data and options for the latest data version
502
475
 
503
- :param access_token:
504
- :type access_token: str
505
476
  :param _request_timeout: timeout setting for this request. If one
506
477
  number provided, it will be total request
507
478
  timeout. It can also be a pair (tuple) of
@@ -525,7 +496,6 @@ class DataApi:
525
496
  """ # noqa: E501
526
497
 
527
498
  _param = self._get_data_info_serialize(
528
- access_token=access_token,
529
499
  _request_auth=_request_auth,
530
500
  _content_type=_content_type,
531
501
  _headers=_headers,
@@ -534,7 +504,6 @@ class DataApi:
534
504
 
535
505
  _response_types_map: Dict[str, Optional[str]] = {
536
506
  "200": "DataInfo",
537
- "422": "HTTPValidationError",
538
507
  }
539
508
  response_data = await self.api_client.call_api(
540
509
  *_param, _request_timeout=_request_timeout
@@ -543,7 +512,6 @@ class DataApi:
543
512
 
544
513
  def _get_data_info_serialize(
545
514
  self,
546
- access_token,
547
515
  _request_auth,
548
516
  _content_type,
549
517
  _headers,