crypticorn 2.17.0rc1__py3-none-any.whl → 2.17.0rc3__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 (87) hide show
  1. crypticorn/__init__.py +2 -2
  2. crypticorn/auth/client/api/admin_api.py +415 -13
  3. crypticorn/auth/client/api/auth_api.py +2622 -113
  4. crypticorn/auth/client/api/service_api.py +258 -7
  5. crypticorn/auth/client/api/user_api.py +2485 -270
  6. crypticorn/auth/client/api/wallet_api.py +1518 -77
  7. crypticorn/auth/client/models/create_api_key_request.py +2 -1
  8. crypticorn/auth/client/models/get_api_keys200_response_inner.py +2 -1
  9. crypticorn/auth/client/rest.py +23 -4
  10. crypticorn/auth/main.py +8 -5
  11. crypticorn/client.py +227 -59
  12. crypticorn/common/__init__.py +0 -1
  13. crypticorn/common/auth.py +2 -1
  14. crypticorn/common/metrics.py +4 -6
  15. crypticorn/common/middleware.py +10 -5
  16. crypticorn/common/pagination.py +137 -18
  17. crypticorn/common/router/admin_router.py +1 -1
  18. crypticorn/common/utils.py +2 -1
  19. crypticorn/common/warnings.py +1 -0
  20. crypticorn/hive/client/api/admin_api.py +1234 -51
  21. crypticorn/hive/client/api/data_api.py +517 -13
  22. crypticorn/hive/client/api/models_api.py +1657 -83
  23. crypticorn/hive/client/api/status_api.py +415 -13
  24. crypticorn/hive/client/models/api_error_identifier.py +1 -1
  25. crypticorn/hive/client/rest.py +23 -4
  26. crypticorn/hive/main.py +99 -25
  27. crypticorn/klines/client/api/admin_api.py +1234 -51
  28. crypticorn/klines/client/api/change_in_timeframe_api.py +278 -7
  29. crypticorn/klines/client/api/funding_rates_api.py +324 -7
  30. crypticorn/klines/client/api/ohlcv_data_api.py +399 -7
  31. crypticorn/klines/client/api/status_api.py +415 -13
  32. crypticorn/klines/client/api/symbols_api.py +225 -7
  33. crypticorn/klines/client/api/udf_api.py +1393 -120
  34. crypticorn/klines/client/models/api_error_identifier.py +3 -1
  35. crypticorn/klines/client/rest.py +23 -4
  36. crypticorn/klines/main.py +89 -12
  37. crypticorn/metrics/client/api/admin_api.py +1234 -51
  38. crypticorn/metrics/client/api/exchanges_api.py +1405 -140
  39. crypticorn/metrics/client/api/indicators_api.py +640 -13
  40. crypticorn/metrics/client/api/logs_api.py +305 -7
  41. crypticorn/metrics/client/api/marketcap_api.py +1240 -60
  42. crypticorn/metrics/client/api/markets_api.py +352 -7
  43. crypticorn/metrics/client/api/quote_currencies_api.py +237 -7
  44. crypticorn/metrics/client/api/status_api.py +415 -13
  45. crypticorn/metrics/client/api/tokens_api.py +400 -13
  46. crypticorn/metrics/client/configuration.py +4 -2
  47. crypticorn/metrics/client/rest.py +23 -4
  48. crypticorn/metrics/main.py +113 -19
  49. crypticorn/pay/client/api/admin_api.py +1720 -126
  50. crypticorn/pay/client/api/now_payments_api.py +1013 -42
  51. crypticorn/pay/client/api/payments_api.py +580 -13
  52. crypticorn/pay/client/api/products_api.py +915 -25
  53. crypticorn/pay/client/api/status_api.py +415 -13
  54. crypticorn/pay/client/configuration.py +2 -2
  55. crypticorn/pay/client/models/api_error_identifier.py +7 -7
  56. crypticorn/pay/client/models/scope.py +1 -0
  57. crypticorn/pay/client/rest.py +23 -4
  58. crypticorn/pay/main.py +10 -6
  59. crypticorn/trade/client/__init__.py +2 -1
  60. crypticorn/trade/client/api/__init__.py +0 -1
  61. crypticorn/trade/client/api/admin_api.py +1718 -123
  62. crypticorn/trade/client/api/api_keys_api.py +1596 -103
  63. crypticorn/trade/client/api/bots_api.py +1106 -47
  64. crypticorn/trade/client/api/exchanges_api.py +592 -19
  65. crypticorn/trade/client/api/notifications_api.py +1340 -112
  66. crypticorn/trade/client/api/orders_api.py +240 -7
  67. crypticorn/trade/client/api/status_api.py +415 -13
  68. crypticorn/trade/client/api/strategies_api.py +1170 -69
  69. crypticorn/trade/client/api/trading_actions_api.py +650 -19
  70. crypticorn/trade/client/models/__init__.py +2 -0
  71. crypticorn/trade/client/models/exchange.py +6 -1
  72. crypticorn/trade/client/models/exchange_key_balance.py +111 -0
  73. crypticorn/trade/client/models/futures_balance.py +27 -25
  74. crypticorn/trade/client/models/spot_balance.py +110 -0
  75. crypticorn/trade/client/models/strategy.py +5 -3
  76. crypticorn/trade/client/models/strategy_create.py +6 -4
  77. crypticorn/trade/client/models/strategy_exchange_info.py +16 -4
  78. crypticorn/trade/client/models/strategy_update.py +2 -2
  79. crypticorn/trade/client/rest.py +23 -4
  80. crypticorn/trade/main.py +15 -12
  81. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/METADATA +64 -20
  82. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/RECORD +86 -85
  83. crypticorn/trade/client/api/futures_trading_panel_api.py +0 -1285
  84. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/WHEEL +0 -0
  85. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/entry_points.txt +0 -0
  86. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/licenses/LICENSE +0 -0
  87. {crypticorn-2.17.0rc1.dist-info → crypticorn-2.17.0rc3.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- """Utilities for handling paginated API responses and cursor-based pagination."""
1
+ """Utilities for handling paginated API responses, cursor-based pagination, filtering, sorting, etc."""
2
2
 
3
- from typing import Generic, Type, TypeVar, Optional, Literal
3
+ from typing import Annotated, Any, Generic, Type, TypeVar, Optional, Literal
4
4
  from pydantic import BaseModel, Field, model_validator
5
5
 
6
6
  T = TypeVar("T")
@@ -14,40 +14,159 @@ class PaginatedResponse(BaseModel, Generic[T]):
14
14
  data: list[T]
15
15
  total: int = Field(description="The total number of items")
16
16
  page: int = Field(description="The current page number")
17
- size: int = Field(description="The number of items per page")
17
+ page_size: int = Field(description="The number of items per page")
18
18
  prev: Optional[int] = Field(None, description="The previous page number")
19
19
  next: Optional[int] = Field(None, description="The next page number")
20
20
 
21
21
 
22
22
  class PaginationParams(BaseModel, Generic[T]):
23
23
  """Standard pagination parameters for usage in API endpoints. Check the [fastapi docs](https://fastapi.tiangolo.com/tutorial/query-param-models/?h=qu#query-parameters-with-a-pydantic-model) for usage examples.
24
- The default size is 10 items per page, but can be overridden:
25
- >>> class HeavyPaginationParams(PaginationParams[T]):
26
- >>> size: int = Field(default=100, description="The number of items per page")
24
+ Can only be used isolated, not in combination with other parameters. If you need to combine with other parameters, use `FilterComboParams` or refer to this [workaround](https://github.com/fastapi/fastapi/discussions/13448#discussioncomment-12440374).
25
+ Usage:
26
+ >>> @router.get("", operation_id="getOrders")
27
+ >>> async def get_orders(
28
+ >>> paginate: Annotated[PaginationParams[Order], Query()],
29
+ >>> ) -> PaginatedResponse[Order]:
30
+ >>> ...
31
+
32
+ The default size is 10 items per page and there is a `HeavyPaginationParams` class with 100 items per page. You can override this default:
33
+ >>> class LightPaginationParams(PaginationParams[T]):
34
+ >>> page_size: int = Field(default=5, description="The number of items per page")
35
+ """
36
+
37
+ page: Optional[int] = Field(default=1, description="The current page number")
38
+ page_size: Annotated[int, Field(ge=1, le=100)] = Field(
39
+ 10, description="The number of items per page. Default is 10, max is 100."
40
+ )
41
+
42
+
43
+ class HeavyPaginationParams(PaginationParams[T]):
44
+ """Pagination parameters with a higher default size. Refer to `PaginationParams` for usage examples."""
45
+
46
+ page_size: Annotated[int, Field(ge=1, le=1000)] = Field(
47
+ 100, description="The number of items per page. Default is 100, max is 1000."
48
+ )
49
+
50
+
51
+ class SortParams(BaseModel, Generic[T]):
52
+ """Standard sort parameters for usage in API endpoints. Check the [fastapi docs](https://fastapi.tiangolo.com/tutorial/query-param-models/?h=qu#query-parameters-with-a-pydantic-model) for usage examples.
53
+ Can only be used isolated, not in combination with other parameters. If you need to combine with other parameters, use `FilterComboParams` or refer to this [workaround](https://github.com/fastapi/fastapi/discussions/13448#discussioncomment-12440374).
54
+ Usage:
55
+ >>> @router.get("", operation_id="getOrders")
56
+ >>> async def get_orders(
57
+ >>> sort: Annotated[SortParams[Order], Query()],
58
+ >>> ) -> PaginatedResponse[Order]:
59
+ >>> ...
27
60
  """
28
61
 
29
- page: int = Field(default=1, description="The current page number")
30
- size: int = Field(default=10, description="The number of items per page")
31
- order: Optional[Literal["asc", "desc"]] = Field(None, description="The order to sort by")
32
- sort: Optional[str] = Field(None, description="The field to sort by")
62
+ sort_order: Optional[Literal["asc", "desc"]] = Field(
63
+ None, description="The order to sort by"
64
+ )
65
+ sort_by: Optional[str] = Field(None, description="The field to sort by")
33
66
 
34
67
  @model_validator(mode="after")
35
- def validate(self):
68
+ def validate_sort(self):
36
69
  # Extract the generic argument type
37
70
  args: tuple = self.__pydantic_generic_metadata__.get("args")
38
71
  if not args or not issubclass(args[0], BaseModel):
39
72
  raise TypeError(
40
73
  "PaginationParams must be used with a Pydantic BaseModel as a generic parameter"
41
74
  )
42
- if self.sort:
75
+ if self.sort_by:
43
76
  # check if the sort field is valid
44
77
  model: Type[BaseModel] = args[0]
45
- if self.sort and self.sort not in model.model_fields:
78
+ if self.sort_by not in model.model_fields:
46
79
  raise ValueError(
47
- f"Invalid sort field: '{self.sort}' must be one of: {list(model.model_fields)}"
80
+ f"Invalid field: '{self.sort_by}'. Must be one of: {list(model.model_fields)}"
48
81
  )
49
- if self.order and self.order not in ["asc", "desc"]:
50
- raise ValueError(f"Invalid order: '{self.order}' — must be one of: ['asc', 'desc']")
51
- if self.order and not self.sort or self.sort and not self.order:
52
- raise ValueError("Sort and order must be provided together")
82
+ if self.sort_order and self.sort_order not in ["asc", "desc"]:
83
+ raise ValueError(
84
+ f"Invalid order: '{self.sort_order}' must be one of: ['asc', 'desc']"
85
+ )
86
+ if self.sort_order and self.sort_by is None or self.sort_by and self.sort_order is None:
87
+ raise ValueError("sort_order and sort_by must be provided together")
53
88
  return self
89
+
90
+
91
+ class FilterParams(BaseModel, Generic[T]):
92
+ """Standard filter parameters for usage in API endpoints. Check the [fastapi docs](https://fastapi.tiangolo.com/tutorial/query-param-models/?h=qu#query-parameters-with-a-pydantic-model) for usage examples.
93
+ Can only be used isolated, not in combination with other parameters. If you need to combine with other parameters, use `FilterComboParams` or refer to this [workaround](https://github.com/fastapi/fastapi/discussions/13448#discussioncomment-12440374).
94
+ Usage:
95
+ >>> @router.get("", operation_id="getOrders")
96
+ >>> async def get_orders(
97
+ >>> filter: Annotated[FilterParams[Order], Query()],
98
+ >>> ) -> PaginatedResponse[Order]:
99
+ >>> ...
100
+ """
101
+
102
+ filter_by: Optional[str] = Field(None, description="The field to filter by")
103
+ filter_value: Optional[Any] = Field(None, description="The value to filter with")
104
+
105
+ @model_validator(mode="after")
106
+ def validate_filter(self):
107
+ if self.filter_by and not self.filter_value:
108
+ raise ValueError("filter_by and filter_value must be provided together")
109
+ if self.filter_by:
110
+ # Extract the generic argument type
111
+ args: tuple = self.__pydantic_generic_metadata__.get("args")
112
+ if not args or not issubclass(args[0], BaseModel):
113
+ raise TypeError(
114
+ "FilterParams must be used with a Pydantic BaseModel as a generic parameter"
115
+ )
116
+ # check if the filter field is valid
117
+ model: Type[BaseModel] = args[0]
118
+ if self.filter_by not in model.model_fields:
119
+ raise ValueError(
120
+ f"Invalid field: '{self.filter_by}'. Must be one of: {list(model.model_fields)}"
121
+ )
122
+ self.filter_value = _enforce_field_type(model, self.filter_by, self.filter_value)
123
+ return self
124
+
125
+
126
+ class FilterComboParams(PaginationParams[T], SortParams[T], FilterParams[T], ):
127
+ """Combines pagination, filter, and sort parameters.
128
+ Usage:
129
+ >>> @router.get("", operation_id="getOrders")
130
+ >>> async def get_orders(
131
+ >>> filter_combo: Annotated[FilterComboParams[Order], Query()],
132
+ >>> ) -> PaginatedResponse[Order]:
133
+ >>> ...
134
+ """
135
+
136
+ pass
137
+
138
+
139
+ class HeavyFilterComboParams(HeavyPaginationParams[T], FilterParams[T], SortParams[T]):
140
+ """Combines pagination, filter, and sort parameters.
141
+ Usage:
142
+ >>> @router.get("", operation_id="getOrders")
143
+ >>> async def get_orders(
144
+ >>> filter_combo: Annotated[HeavyFilterComboParams[Order], Query()],
145
+ >>> ) -> PaginatedResponse[Order]:
146
+ >>> ...
147
+ """
148
+
149
+ pass
150
+
151
+
152
+ def _enforce_field_type(model: Type[BaseModel], field_name: str, value: Any) -> Any:
153
+ """
154
+ Coerce or validate `value` to match the type of `field_name` on the given `model`. Should be used after checking that the field is valid.
155
+
156
+ :param model: The Pydantic model.
157
+ :param field_name: The name of the field to match.
158
+ :param value: The value to validate or coerce.
159
+
160
+ :return: The value cast to the expected type.
161
+
162
+ :raises: ValueError: If the field doesn't exist or coercion fails.
163
+ """
164
+ expected_type = model.model_fields[field_name].annotation
165
+
166
+ if isinstance(value, expected_type):
167
+ return value
168
+
169
+ try:
170
+ return expected_type(value)
171
+ except Exception as e:
172
+ raise ValueError(f"Expected {expected_type} for field {field_name}, got {type(value)}")
@@ -113,4 +113,4 @@ def metrics():
113
113
  """
114
114
  Get Prometheus metrics for the application. Returns plain text.
115
115
  """
116
- return Response(generate_latest(registry), media_type=CONTENT_TYPE_LATEST)
116
+ return Response(generate_latest(registry), media_type=CONTENT_TYPE_LATEST)
@@ -1,10 +1,11 @@
1
1
  """General utility functions and helper methods used across the codebase."""
2
2
 
3
3
  from datetime import datetime
4
- from typing import Any, Union
4
+ from typing import Any, Type, Union
5
5
  from decimal import Decimal
6
6
  import string
7
7
  import random
8
+ from pydantic import BaseModel
8
9
  import typing_extensions
9
10
  import warnings
10
11
 
@@ -62,6 +62,7 @@ class CrypticornDeprecatedSince215(CrypticornDeprecationWarning):
62
62
  def __init__(self, message: str, *args: object) -> None:
63
63
  super().__init__(message, *args, since=(2, 15), expected_removal=(3, 0))
64
64
 
65
+
65
66
  class CrypticornDeprecatedSince217(CrypticornDeprecationWarning):
66
67
  """A specific `CrypticornDeprecationWarning` subclass defining functionality deprecated since Crypticorn 2.17."""
67
68