crypticorn 2.15.0__tar.gz → 2.17.0rc1__tar.gz

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 (311) hide show
  1. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/CHANGELOG.md +26 -0
  2. {crypticorn-2.15.0/crypticorn.egg-info → crypticorn-2.17.0rc1}/PKG-INFO +2 -1
  3. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/__init__.py +2 -0
  4. crypticorn-2.17.0rc1/crypticorn/common/metrics.py +20 -0
  5. crypticorn-2.17.0rc1/crypticorn/common/middleware.py +69 -0
  6. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/pagination.py +7 -5
  7. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/router/admin_router.py +12 -2
  8. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/scopes.py +2 -0
  9. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/warnings.py +7 -0
  10. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/api_error_identifier.py +7 -7
  11. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/futures_trading_action.py +6 -28
  12. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/futures_trading_action_create.py +10 -13
  13. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/order.py +2 -14
  14. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/spot_trading_action_create.py +4 -1
  15. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/tpsl.py +0 -8
  16. {crypticorn-2.15.0 → crypticorn-2.17.0rc1/crypticorn.egg-info}/PKG-INFO +2 -1
  17. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn.egg-info/SOURCES.txt +1 -0
  18. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn.egg-info/requires.txt +1 -0
  19. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/pyproject.toml +1 -1
  20. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/requirements/main.txt +1 -0
  21. crypticorn-2.17.0rc1/tests/test_pagination.py +62 -0
  22. crypticorn-2.15.0/crypticorn/common/middleware.py +0 -28
  23. crypticorn-2.15.0/tests/test_pagination.py +0 -19
  24. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/LICENSE +0 -0
  25. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/MANIFEST.in +0 -0
  26. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/README.md +0 -0
  27. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/__init__.py +0 -0
  28. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/__init__.py +0 -0
  29. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/__init__.py +0 -0
  30. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/__init__.py +0 -0
  31. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/admin_api.py +0 -0
  32. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/auth_api.py +0 -0
  33. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/service_api.py +0 -0
  34. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/user_api.py +0 -0
  35. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api/wallet_api.py +0 -0
  36. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api_client.py +0 -0
  37. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/api_response.py +0 -0
  38. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/configuration.py +0 -0
  39. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/exceptions.py +0 -0
  40. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/__init__.py +0 -0
  41. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/add_wallet200_response.py +0 -0
  42. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/add_wallet_request.py +0 -0
  43. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/authorize_user200_response.py +0 -0
  44. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/authorize_user200_response_auth.py +0 -0
  45. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/authorize_user_request.py +0 -0
  46. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/create_api_key200_response.py +0 -0
  47. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/create_api_key_request.py +0 -0
  48. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/create_user_request.py +0 -0
  49. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/get_api_keys200_response_inner.py +0 -0
  50. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response.py +0 -0
  51. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_balances_inner.py +0 -0
  52. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py +0 -0
  53. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet.py +0 -0
  54. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet_vesting_wallets_inner.py +0 -0
  55. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_data_inner.py +0 -0
  56. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/list_wallets200_response_user_value.py +0 -0
  57. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/logout_default_response.py +0 -0
  58. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/logout_default_response_issues_inner.py +0 -0
  59. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/oauth_callback200_response.py +0 -0
  60. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/oauth_callback200_response_user.py +0 -0
  61. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/refresh_token_info200_response.py +0 -0
  62. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/refresh_token_info200_response_user_session.py +0 -0
  63. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/resend_verification_email_request.py +0 -0
  64. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/revoke_user_tokens_request.py +0 -0
  65. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/rotate_tokens200_response.py +0 -0
  66. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/token_info200_response.py +0 -0
  67. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/unlink_wallet_request.py +0 -0
  68. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/update_user_request.py +0 -0
  69. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/user_by_username200_response.py +0 -0
  70. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/user_reset_password_request.py +0 -0
  71. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/user_set_password_request.py +0 -0
  72. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify200_response.py +0 -0
  73. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify_email200_response.py +0 -0
  74. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify_email200_response_auth.py +0 -0
  75. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify_email200_response_auth_auth.py +0 -0
  76. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify_email_request.py +0 -0
  77. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/verify_wallet_request.py +0 -0
  78. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/wallet_verified200_response.py +0 -0
  79. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/models/whoami200_response.py +0 -0
  80. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/py.typed +0 -0
  81. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/client/rest.py +0 -0
  82. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/auth/main.py +0 -0
  83. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/__init__.py +0 -0
  84. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/__main__.py +0 -0
  85. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/init.py +0 -0
  86. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/Dockerfile +0 -0
  87. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/__init__.py +0 -0
  88. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/auth.py +0 -0
  89. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/dependabot.yml +0 -0
  90. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/merge-env.sh +0 -0
  91. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/templates/ruff.yml +0 -0
  92. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/cli/version.py +0 -0
  93. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/client.py +0 -0
  94. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/ansi_colors.py +0 -0
  95. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/auth.py +0 -0
  96. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/decorators.py +0 -0
  97. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/enums.py +0 -0
  98. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/errors.py +0 -0
  99. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/exceptions.py +0 -0
  100. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/logging.py +0 -0
  101. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/mixins.py +0 -0
  102. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/openapi.py +0 -0
  103. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/router/status_router.py +0 -0
  104. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/urls.py +0 -0
  105. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/common/utils.py +0 -0
  106. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/__init__.py +0 -0
  107. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/__init__.py +0 -0
  108. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api/__init__.py +0 -0
  109. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api/admin_api.py +0 -0
  110. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api/data_api.py +0 -0
  111. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api/models_api.py +0 -0
  112. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api/status_api.py +0 -0
  113. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api_client.py +0 -0
  114. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/api_response.py +0 -0
  115. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/configuration.py +0 -0
  116. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/exceptions.py +0 -0
  117. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/__init__.py +0 -0
  118. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/api_error_identifier.py +0 -0
  119. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/api_error_level.py +0 -0
  120. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/api_error_type.py +0 -0
  121. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/coin_info.py +0 -0
  122. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/coins.py +0 -0
  123. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/data_download_response.py +0 -0
  124. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/data_info.py +0 -0
  125. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/data_options.py +0 -0
  126. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/data_version.py +0 -0
  127. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/data_version_info.py +0 -0
  128. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/download_links.py +0 -0
  129. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/evaluation.py +0 -0
  130. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/evaluation_response.py +0 -0
  131. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/exception_detail.py +0 -0
  132. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/feature_size.py +0 -0
  133. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/log_level.py +0 -0
  134. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/model_create.py +0 -0
  135. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/model_read.py +0 -0
  136. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/model_status.py +0 -0
  137. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/model_update.py +0 -0
  138. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/target.py +0 -0
  139. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/target_info.py +0 -0
  140. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/models/target_type.py +0 -0
  141. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/py.typed +0 -0
  142. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/client/rest.py +0 -0
  143. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/main.py +0 -0
  144. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/hive/utils.py +0 -0
  145. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/__init__.py +0 -0
  146. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/__init__.py +0 -0
  147. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/__init__.py +0 -0
  148. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/admin_api.py +0 -0
  149. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/change_in_timeframe_api.py +0 -0
  150. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/funding_rates_api.py +0 -0
  151. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/ohlcv_data_api.py +0 -0
  152. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/status_api.py +0 -0
  153. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/symbols_api.py +0 -0
  154. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api/udf_api.py +0 -0
  155. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api_client.py +0 -0
  156. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/api_response.py +0 -0
  157. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/configuration.py +0 -0
  158. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/exceptions.py +0 -0
  159. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/__init__.py +0 -0
  160. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/api_error_identifier.py +0 -0
  161. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/api_error_level.py +0 -0
  162. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/api_error_type.py +0 -0
  163. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/change_in_timeframe.py +0 -0
  164. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/exception_detail.py +0 -0
  165. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/funding_rate.py +0 -0
  166. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/funding_rate_response.py +0 -0
  167. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/internal_exchange.py +0 -0
  168. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/log_level.py +0 -0
  169. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/market_type.py +0 -0
  170. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/ohlcv.py +0 -0
  171. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/resolution.py +0 -0
  172. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/search_symbol.py +0 -0
  173. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/sort_direction.py +0 -0
  174. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/symbol_group.py +0 -0
  175. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/symbol_info.py +0 -0
  176. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/symbol_type.py +0 -0
  177. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/timeframe.py +0 -0
  178. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/models/udf_config.py +0 -0
  179. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/py.typed +0 -0
  180. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/client/rest.py +0 -0
  181. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/klines/main.py +0 -0
  182. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/__init__.py +0 -0
  183. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/__init__.py +0 -0
  184. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/__init__.py +0 -0
  185. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/admin_api.py +0 -0
  186. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/exchanges_api.py +0 -0
  187. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/indicators_api.py +0 -0
  188. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/logs_api.py +0 -0
  189. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/marketcap_api.py +0 -0
  190. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/markets_api.py +0 -0
  191. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/quote_currencies_api.py +0 -0
  192. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/status_api.py +0 -0
  193. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api/tokens_api.py +0 -0
  194. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api_client.py +0 -0
  195. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/api_response.py +0 -0
  196. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/configuration.py +0 -0
  197. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/exceptions.py +0 -0
  198. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/__init__.py +0 -0
  199. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/api_error_identifier.py +0 -0
  200. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/api_error_level.py +0 -0
  201. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/api_error_type.py +0 -0
  202. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/exception_detail.py +0 -0
  203. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/exchange_availability.py +0 -0
  204. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/exchange_mapping.py +0 -0
  205. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/internal_exchange.py +0 -0
  206. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/log_level.py +0 -0
  207. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/market_type.py +0 -0
  208. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/marketcap_ranking.py +0 -0
  209. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/marketcap_symbol_ranking.py +0 -0
  210. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/ohlcv.py +0 -0
  211. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/severity.py +0 -0
  212. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/time_interval.py +0 -0
  213. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/models/trading_status.py +0 -0
  214. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/py.typed +0 -0
  215. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/client/rest.py +0 -0
  216. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/metrics/main.py +0 -0
  217. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/__init__.py +0 -0
  218. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/__init__.py +0 -0
  219. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/__init__.py +0 -0
  220. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/admin_api.py +0 -0
  221. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/now_payments_api.py +0 -0
  222. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/payments_api.py +0 -0
  223. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/products_api.py +0 -0
  224. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api/status_api.py +0 -0
  225. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api_client.py +0 -0
  226. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/api_response.py +0 -0
  227. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/configuration.py +0 -0
  228. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/exceptions.py +0 -0
  229. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/__init__.py +0 -0
  230. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/api_error_identifier.py +0 -0
  231. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/api_error_level.py +0 -0
  232. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/api_error_type.py +0 -0
  233. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/exception_detail.py +0 -0
  234. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/log_level.py +0 -0
  235. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/now_create_invoice_req.py +0 -0
  236. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/now_create_invoice_res.py +0 -0
  237. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/payment.py +0 -0
  238. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/payment_status.py +0 -0
  239. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/product.py +0 -0
  240. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/product_create.py +0 -0
  241. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/product_update.py +0 -0
  242. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/provider.py +0 -0
  243. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/scope.py +0 -0
  244. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/models/subscription.py +0 -0
  245. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/py.typed +0 -0
  246. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/client/rest.py +0 -0
  247. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/pay/main.py +0 -0
  248. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/__init__.py +0 -0
  249. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/__init__.py +0 -0
  250. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/__init__.py +0 -0
  251. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/admin_api.py +0 -0
  252. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/api_keys_api.py +0 -0
  253. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/bots_api.py +0 -0
  254. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/exchanges_api.py +0 -0
  255. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/futures_trading_panel_api.py +0 -0
  256. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/notifications_api.py +0 -0
  257. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/orders_api.py +0 -0
  258. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/status_api.py +0 -0
  259. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/strategies_api.py +0 -0
  260. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api/trading_actions_api.py +0 -0
  261. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api_client.py +0 -0
  262. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/api_response.py +0 -0
  263. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/configuration.py +0 -0
  264. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/exceptions.py +0 -0
  265. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/__init__.py +0 -0
  266. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/api_error_level.py +0 -0
  267. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/api_error_type.py +0 -0
  268. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/bot.py +0 -0
  269. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/bot_create.py +0 -0
  270. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/bot_status.py +0 -0
  271. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/bot_update.py +0 -0
  272. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/exception_detail.py +0 -0
  273. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/exchange.py +0 -0
  274. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/exchange_key.py +0 -0
  275. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/exchange_key_create.py +0 -0
  276. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/exchange_key_update.py +0 -0
  277. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/execution_ids.py +0 -0
  278. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/futures_balance.py +0 -0
  279. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/log_level.py +0 -0
  280. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/margin_mode.py +0 -0
  281. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/market_type.py +0 -0
  282. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/notification.py +0 -0
  283. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/notification_create.py +0 -0
  284. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/notification_update.py +0 -0
  285. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/order_status.py +0 -0
  286. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/post_futures_action.py +0 -0
  287. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/strategy.py +0 -0
  288. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/strategy_create.py +0 -0
  289. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/strategy_exchange_info.py +0 -0
  290. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/strategy_update.py +0 -0
  291. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/tpsl_create.py +0 -0
  292. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/models/trading_action_type.py +0 -0
  293. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/py.typed +0 -0
  294. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/client/rest.py +0 -0
  295. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn/trade/main.py +0 -0
  296. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn.egg-info/dependency_links.txt +0 -0
  297. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn.egg-info/entry_points.txt +0 -0
  298. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/crypticorn.egg-info/top_level.txt +0 -0
  299. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/requirements/dev.txt +0 -0
  300. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/requirements/extra.txt +0 -0
  301. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/requirements/test.txt +0 -0
  302. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/setup.cfg +0 -0
  303. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/static/favicon.svg +0 -0
  304. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/static/logo.svg +0 -0
  305. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/static/pip-structure.drawio +0 -0
  306. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/static/pip-structure.svg +0 -0
  307. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/tests/test_auth_client.py +0 -0
  308. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/tests/test_config.py +0 -0
  309. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/tests/test_custom_session.py +0 -0
  310. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/tests/test_enums.py +0 -0
  311. {crypticorn-2.15.0 → crypticorn-2.17.0rc1}/tests/test_errors.py +0 -0
@@ -1,6 +1,32 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v2.17.0-rc.1 (2025-06-01)
5
+
6
+ ### Features
7
+
8
+ - Add metrics router
9
+ ([`9b4a9bd`](https://github.com/crypticorn-ai/api-client/commit/9b4a9bd33e16d70d4338f7d458e2d405cb1d22dd))
10
+
11
+
12
+ ## v2.16.0 (2025-05-31)
13
+
14
+ ### Features
15
+
16
+ - Add new scope for DEX AI Signals
17
+ ([`8b566f1`](https://github.com/crypticorn-ai/api-client/commit/8b566f1203268bfa898e9b03e32468f4611ebccc))
18
+
19
+ ### Refactoring
20
+
21
+ - Make order field in pagination model optional and improve the data validation
22
+ ([`d3e3a6f`](https://github.com/crypticorn-ai/api-client/commit/d3e3a6f8e1752f38ab51d1fbc74d976968ef3c1c))
23
+
24
+ ### Testing
25
+
26
+ - Update pagination tests
27
+ ([`1692b8d`](https://github.com/crypticorn-ai/api-client/commit/1692b8d02c99c9592c19e612c82ed128de95213d))
28
+
29
+
4
30
  ## v2.15.0 (2025-05-27)
5
31
 
6
32
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.15.0
3
+ Version: 2.17.0rc1
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -25,6 +25,7 @@ Requires-Dist: click<9.0.0,>=8.0.0
25
25
  Requires-Dist: psutil<8.0.0,>=7.0.0
26
26
  Requires-Dist: setuptools<81.0.0,>=80.0.0
27
27
  Requires-Dist: strenum
28
+ Requires-Dist: prometheus-client<1.0.0,>=0.22.0
28
29
  Requires-Dist: urllib3<3.0.0,>=1.25.3
29
30
  Requires-Dist: python_dateutil<3.0.0,>=2.8.2
30
31
  Requires-Dist: aiohttp<4.0.0,>=3.8.4
@@ -13,5 +13,7 @@ from crypticorn.common.ansi_colors import *
13
13
  from crypticorn.common.middleware import *
14
14
  from crypticorn.common.warnings import *
15
15
  from crypticorn.common.openapi import *
16
+ from crypticorn.common.metrics import *
16
17
  from crypticorn.common.router.status_router import router as status_router
17
18
  from crypticorn.common.router.admin_router import router as admin_router
19
+
@@ -0,0 +1,20 @@
1
+ # metrics/registry.py
2
+ from prometheus_client import (
3
+ Counter, Gauge, Histogram, Summary, CollectorRegistry
4
+ )
5
+
6
+ registry = CollectorRegistry()
7
+
8
+ http_requests_total = Counter(
9
+ "http_requests_total",
10
+ "Total HTTP requests",
11
+ ["method", "endpoint", "status_code"],
12
+ registry=registry
13
+ )
14
+
15
+ http_request_duration_seconds = Histogram(
16
+ "http_request_duration_seconds",
17
+ "HTTP request duration in seconds",
18
+ ["endpoint"],
19
+ registry=registry
20
+ )
@@ -0,0 +1,69 @@
1
+ import time
2
+ from fastapi import FastAPI
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from starlette.middleware.base import BaseHTTPMiddleware
5
+ from starlette.requests import Request
6
+ from crypticorn.common.logging import configure_logging
7
+ from contextlib import asynccontextmanager
8
+ from typing_extensions import deprecated
9
+ import warnings
10
+ from crypticorn.common.warnings import CrypticornDeprecatedSince217
11
+ from crypticorn.common.metrics import http_requests_total, http_request_duration_seconds
12
+
13
+ class PrometheusMiddleware(BaseHTTPMiddleware):
14
+ async def dispatch(self, request, call_next):
15
+ start = time.perf_counter()
16
+ response = await call_next(request)
17
+ duration = time.perf_counter() - start
18
+
19
+ http_requests_total.labels(
20
+ method=request.method,
21
+ endpoint=request.url.path,
22
+ status_code=response.status_code
23
+ ).inc()
24
+
25
+ http_request_duration_seconds.labels(
26
+ endpoint=request.url.path
27
+ ).observe(duration)
28
+
29
+ return response
30
+
31
+
32
+ @deprecated("Use add_middleware instead", category=None)
33
+ def add_cors_middleware(app: "FastAPI"):
34
+ warnings.warn("add_cors_middleware is deprecated. Use add_middleware instead.", CrypticornDeprecatedSince217)
35
+ app.add_middleware(
36
+ CORSMiddleware,
37
+ allow_origins=[
38
+ "http://localhost:5173", # vite dev server
39
+ "http://localhost:4173", # vite preview server
40
+ ],
41
+ allow_origin_regex="^https://([a-zA-Z0-9-]+.)*crypticorn.(dev|com)/?$", # matches (multiple or no) subdomains of crypticorn.dev and crypticorn.com
42
+ allow_credentials=True,
43
+ allow_methods=["*"],
44
+ allow_headers=["*"],
45
+ )
46
+
47
+ def add_middleware(app: "FastAPI"):
48
+ app.add_middleware(
49
+ CORSMiddleware,
50
+ allow_origins=[
51
+ "http://localhost:5173", # vite dev server
52
+ "http://localhost:4173", # vite preview server
53
+ ],
54
+ allow_origin_regex="^https://([a-zA-Z0-9-]+.)*crypticorn.(dev|com)/?$", # matches (multiple or no) subdomains of crypticorn.dev and crypticorn.com
55
+ allow_credentials=True,
56
+ allow_methods=["*"],
57
+ allow_headers=["*"],
58
+ )
59
+ app.add_middleware(PrometheusMiddleware)
60
+
61
+
62
+ @asynccontextmanager
63
+ async def default_lifespan(app: FastAPI):
64
+ """Default lifespan for the applications.
65
+ This is used to configure the logging for the application.
66
+ To override this, pass a different lifespan to the FastAPI constructor or call this lifespan within a custom lifespan.
67
+ """
68
+ configure_logging()
69
+ yield
@@ -1,6 +1,6 @@
1
1
  """Utilities for handling paginated API responses and cursor-based pagination."""
2
2
 
3
- from typing import Generic, Type, TypeVar, List, Optional, Literal
3
+ from typing import Generic, Type, TypeVar, Optional, Literal
4
4
  from pydantic import BaseModel, Field, model_validator
5
5
 
6
6
  T = TypeVar("T")
@@ -11,7 +11,7 @@ class PaginatedResponse(BaseModel, Generic[T]):
11
11
  >>> PaginatedResponse[ItemModel](data=items, total=total_items, page=1, size=10, prev=None, next=2)
12
12
  """
13
13
 
14
- data: List[T]
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
17
  size: int = Field(description="The number of items per page")
@@ -28,9 +28,7 @@ class PaginationParams(BaseModel, Generic[T]):
28
28
 
29
29
  page: int = Field(default=1, description="The current page number")
30
30
  size: int = Field(default=10, description="The number of items per page")
31
- order: Literal["asc", "desc"] = Field(
32
- default="asc", description="The order to sort by"
33
- )
31
+ order: Optional[Literal["asc", "desc"]] = Field(None, description="The order to sort by")
34
32
  sort: Optional[str] = Field(None, description="The field to sort by")
35
33
 
36
34
  @model_validator(mode="after")
@@ -48,4 +46,8 @@ class PaginationParams(BaseModel, Generic[T]):
48
46
  raise ValueError(
49
47
  f"Invalid sort field: '{self.sort}' — must be one of: {list(model.model_fields)}"
50
48
  )
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")
51
53
  return self
@@ -11,10 +11,12 @@ import threading
11
11
  import time
12
12
  import psutil
13
13
  import re
14
- from fastapi import APIRouter, Query
14
+ import logging
15
15
  from typing import Literal
16
+ from fastapi import APIRouter, Query, Response
17
+ from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
16
18
  from crypticorn.common.logging import LogLevel
17
- import logging
19
+ from crypticorn.common.metrics import registry
18
20
 
19
21
  router = APIRouter(tags=["Admin"], prefix="/admin")
20
22
 
@@ -104,3 +106,11 @@ def list_installed_packages(
104
106
  or any(re.match(pattern, dist.metadata["Name"]) for pattern in include)
105
107
  }
106
108
  return dict(sorted(packages.items()))
109
+
110
+
111
+ @router.get("/metrics", operation_id="getMetrics")
112
+ def metrics():
113
+ """
114
+ Get Prometheus metrics for the application. Returns plain text.
115
+ """
116
+ return Response(generate_latest(registry), media_type=CONTENT_TYPE_LATEST)
@@ -16,6 +16,7 @@ class Scope(StrEnum):
16
16
 
17
17
  # Scopes that can be purchased - these actually exist in the jwt token
18
18
  READ_PREDICTIONS = "read:predictions"
19
+ READ_DEXSIGNALS = "read:dexsignals"
19
20
 
20
21
  # Hive scopes
21
22
  READ_HIVE_MODEL = "read:hive:model"
@@ -87,4 +88,5 @@ class Scope(StrEnum):
87
88
  cls.READ_METRICS_MARKETS,
88
89
  cls.READ_KLINES,
89
90
  cls.READ_SENTIMENT,
91
+ cls.READ_DEXSIGNALS,
90
92
  ]
@@ -55,12 +55,19 @@ class CrypticornDeprecatedSince28(CrypticornDeprecationWarning):
55
55
  def __init__(self, message: str, *args: object) -> None:
56
56
  super().__init__(message, *args, since=(2, 8), expected_removal=(3, 0))
57
57
 
58
+
58
59
  class CrypticornDeprecatedSince215(CrypticornDeprecationWarning):
59
60
  """A specific `CrypticornDeprecationWarning` subclass defining functionality deprecated since Crypticorn 2.15."""
60
61
 
61
62
  def __init__(self, message: str, *args: object) -> None:
62
63
  super().__init__(message, *args, since=(2, 15), expected_removal=(3, 0))
63
64
 
65
+ class CrypticornDeprecatedSince217(CrypticornDeprecationWarning):
66
+ """A specific `CrypticornDeprecationWarning` subclass defining functionality deprecated since Crypticorn 2.17."""
67
+
68
+ def __init__(self, message: str, *args: object) -> None:
69
+ super().__init__(message, *args, since=(2, 17), expected_removal=(3, 0))
70
+
64
71
 
65
72
  class CrypticornExperimentalWarning(Warning):
66
73
  """A Crypticorn specific experimental functionality warning.
@@ -28,15 +28,17 @@ class ApiErrorIdentifier(str, Enum):
28
28
  """
29
29
  ALLOCATION_BELOW_CURRENT_EXPOSURE = "allocation_below_current_exposure"
30
30
  ALLOCATION_BELOW_MIN_AMOUNT = "allocation_below_min_amount"
31
+ ALLOCATION_LIMIT_EXCEEDED = "allocation_limit_exceeded"
31
32
  BLACK_SWAN = "black_swan"
32
33
  BOT_ALREADY_DELETED = "bot_already_deleted"
33
- BOT_DISABLED = "bot_disabled"
34
34
  BOT_STOPPING_COMPLETED = "bot_stopping_completed"
35
35
  BOT_STOPPING_STARTED = "bot_stopping_started"
36
36
  CANCELLED_OPEN_ORDER = "cancelled_open_order"
37
37
  CLIENT_ORDER_ID_ALREADY_EXISTS = "client_order_id_already_exists"
38
38
  INVALID_CONTENT_TYPE = "invalid_content_type"
39
39
  DELETE_BOT_ERROR = "delete_bot_error"
40
+ EXCHANGE_HTTP_REQUEST_ERROR = "exchange_http_request_error"
41
+ EXCHANGE_INVALID_PARAMETER = "exchange_invalid_parameter"
40
42
  EXCHANGE_INVALID_SIGNATURE = "exchange_invalid_signature"
41
43
  EXCHANGE_INVALID_TIMESTAMP = "exchange_invalid_timestamp"
42
44
  EXCHANGE_IP_ADDRESS_IS_NOT_AUTHORIZED = "exchange_ip_address_is_not_authorized"
@@ -56,10 +58,9 @@ class ApiErrorIdentifier(str, Enum):
56
58
  EXCHANGE_USER_ACCOUNT_IS_FROZEN = "exchange_user_account_is_frozen"
57
59
  API_KEY_EXPIRED = "api_key_expired"
58
60
  BEARER_TOKEN_EXPIRED = "bearer_token_expired"
59
- OPEN_ORDER_EXPIRED = "open_order_expired"
61
+ FAILED_OPEN_ORDER = "failed_open_order"
60
62
  FORBIDDEN = "forbidden"
61
63
  HEDGE_MODE_NOT_ACTIVE = "hedge_mode_not_active"
62
- HTTP_REQUEST_ERROR = "http_request_error"
63
64
  INSUFFICIENT_BALANCE = "insufficient_balance"
64
65
  INSUFFICIENT_MARGIN = "insufficient_margin"
65
66
  INSUFFICIENT_SCOPES = "insufficient_scopes"
@@ -68,15 +69,15 @@ class ApiErrorIdentifier(str, Enum):
68
69
  INVALID_DATA = "invalid_data"
69
70
  INVALID_DATA_RESPONSE = "invalid_data_response"
70
71
  INVALID_EXCHANGE_KEY = "invalid_exchange_key"
71
- INVALID_MARGIN_MODE = "invalid_margin_mode"
72
72
  INVALID_MODEL_NAME = "invalid_model_name"
73
- INVALID_PARAMETER_PROVIDED = "exchange_invalid_parameter"
74
73
  LEVERAGE_LIMIT_EXCEEDED = "leverage_limit_exceeded"
75
74
  ORDER_VIOLATES_LIQUIDATION_PRICE_CONSTRAINTS = (
76
75
  "order_violates_liquidation_price_constraints"
77
76
  )
78
77
  MARGIN_MODE_CLASH = "margin_mode_clash"
79
78
  NAME_NOT_UNIQUE = "name_not_unique"
79
+ NO_API_KEY = "no_api_key"
80
+ NO_BEARER = "no_bearer"
80
81
  NO_CREDENTIALS = "no_credentials"
81
82
  NOW_API_DOWN = "now_api_down"
82
83
  OBJECT_ALREADY_EXISTS = "object_already_exists"
@@ -102,14 +103,13 @@ class ApiErrorIdentifier(str, Enum):
102
103
  RISK_LIMIT_EXCEEDED = "risk_limit_exceeded"
103
104
  RPC_TIMEOUT = "rpc_timeout"
104
105
  SYSTEM_SETTLEMENT_IN_PROCESS = "system_settlement_in_process"
105
- STRATEGY_ALREADY_EXISTS = "strategy_already_exists"
106
106
  STRATEGY_DISABLED = "strategy_disabled"
107
107
  STRATEGY_LEVERAGE_MISMATCH = "strategy_leverage_mismatch"
108
108
  STRATEGY_NOT_SUPPORTING_EXCHANGE = "strategy_not_supporting_exchange"
109
109
  SUCCESS = "success"
110
110
  SYMBOL_DOES_NOT_EXIST = "symbol_does_not_exist"
111
111
  TRADING_ACTION_EXPIRED = "trading_action_expired"
112
- TRADING_ACTION_SKIPPED_BOT_STOPPING = "TRADING_ACTION_SKIPPED_BOT_STOPPING"
112
+ TRADING_ACTION_SKIPPED_BOT_STOPPING = "trading_action_skipped_bot_stopping"
113
113
  TRADING_HAS_BEEN_LOCKED = "trading_has_been_locked"
114
114
  TRADING_IS_SUSPENDED = "trading_is_suspended"
115
115
  UNKNOWN_ERROR_OCCURRED = "unknown_error_occurred"
@@ -33,8 +33,12 @@ class FuturesTradingAction(BaseModel):
33
33
  Model for futures trading actions
34
34
  """ # noqa: E501
35
35
 
36
- leverage: Optional[Annotated[int, Field(strict=True, ge=1)]]
37
- margin_mode: Optional[MarginMode] = None
36
+ leverage: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(
37
+ default=1, description="Leverage to use for futures trades. Default is 1."
38
+ )
39
+ margin_mode: Optional[MarginMode] = Field(
40
+ default=None, description="Margin mode for futures trades. Default is isolated."
41
+ )
38
42
  created_at: Optional[StrictInt] = Field(
39
43
  default=None, description="Timestamp of creation"
40
44
  )
@@ -60,8 +64,6 @@ class FuturesTradingAction(BaseModel):
60
64
  take_profit: Optional[List[TPSL]] = None
61
65
  stop_loss: Optional[List[TPSL]] = None
62
66
  expiry_timestamp: Optional[StrictInt] = None
63
- client_order_id: Optional[StrictStr] = None
64
- position_id: Optional[StrictStr] = None
65
67
  __properties: ClassVar[List[str]] = [
66
68
  "leverage",
67
69
  "margin_mode",
@@ -80,8 +82,6 @@ class FuturesTradingAction(BaseModel):
80
82
  "take_profit",
81
83
  "stop_loss",
82
84
  "expiry_timestamp",
83
- "client_order_id",
84
- "position_id",
85
85
  ]
86
86
 
87
87
  model_config = ConfigDict(
@@ -135,16 +135,6 @@ class FuturesTradingAction(BaseModel):
135
135
  if _item_stop_loss:
136
136
  _items.append(_item_stop_loss.to_dict())
137
137
  _dict["stop_loss"] = _items
138
- # set to None if leverage (nullable) is None
139
- # and model_fields_set contains the field
140
- if self.leverage is None and "leverage" in self.model_fields_set:
141
- _dict["leverage"] = None
142
-
143
- # set to None if margin_mode (nullable) is None
144
- # and model_fields_set contains the field
145
- if self.margin_mode is None and "margin_mode" in self.model_fields_set:
146
- _dict["margin_mode"] = None
147
-
148
138
  # set to None if execution_id (nullable) is None
149
139
  # and model_fields_set contains the field
150
140
  if self.execution_id is None and "execution_id" in self.model_fields_set:
@@ -186,16 +176,6 @@ class FuturesTradingAction(BaseModel):
186
176
  ):
187
177
  _dict["expiry_timestamp"] = None
188
178
 
189
- # set to None if client_order_id (nullable) is None
190
- # and model_fields_set contains the field
191
- if self.client_order_id is None and "client_order_id" in self.model_fields_set:
192
- _dict["client_order_id"] = None
193
-
194
- # set to None if position_id (nullable) is None
195
- # and model_fields_set contains the field
196
- if self.position_id is None and "position_id" in self.model_fields_set:
197
- _dict["position_id"] = None
198
-
199
179
  return _dict
200
180
 
201
181
  @classmethod
@@ -236,8 +216,6 @@ class FuturesTradingAction(BaseModel):
236
216
  else None
237
217
  ),
238
218
  "expiry_timestamp": obj.get("expiry_timestamp"),
239
- "client_order_id": obj.get("client_order_id"),
240
- "position_id": obj.get("position_id"),
241
219
  }
242
220
  )
243
221
  return _obj
@@ -33,12 +33,19 @@ class FuturesTradingActionCreate(BaseModel):
33
33
  Model for sending futures trading actions
34
34
  """ # noqa: E501
35
35
 
36
- leverage: Optional[Annotated[int, Field(strict=True, ge=1)]]
37
- margin_mode: Optional[MarginMode] = None
36
+ leverage: Optional[Annotated[int, Field(strict=True, ge=1)]] = Field(
37
+ default=1, description="Leverage to use for futures trades. Default is 1."
38
+ )
39
+ margin_mode: Optional[MarginMode] = Field(
40
+ default=None, description="Margin mode for futures trades. Default is isolated."
41
+ )
38
42
  execution_id: Optional[StrictStr] = None
39
43
  open_order_execution_id: Optional[StrictStr] = None
40
44
  action_type: TradingActionType = Field(description="The type of action.")
41
- market_type: MarketType = Field(description="The type of market the action is for.")
45
+ market_type: Optional[MarketType] = Field(
46
+ default=None,
47
+ description="The type of market the action is for. Must be set to futures.",
48
+ )
42
49
  strategy_id: StrictStr = Field(description="UID for the strategy.")
43
50
  symbol: StrictStr = Field(
44
51
  description="Trading symbol or asset pair in format: 'symbol/quote_currency' (see market service for valid symbols)"
@@ -119,16 +126,6 @@ class FuturesTradingActionCreate(BaseModel):
119
126
  if _item_stop_loss:
120
127
  _items.append(_item_stop_loss.to_dict())
121
128
  _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
-
132
129
  # set to None if execution_id (nullable) is None
133
130
  # and model_fields_set contains the field
134
131
  if self.execution_id is None and "execution_id" in self.model_fields_set:
@@ -65,7 +65,7 @@ class Order(BaseModel):
65
65
  sent_qty: Optional[StrictStr] = None
66
66
  fee: Optional[StrictStr] = None
67
67
  leverage: Optional[StrictInt] = None
68
- order_details: Optional[Any] = Field(
68
+ order_details: Optional[Dict[str, Any]] = Field(
69
69
  default=None, description="Exchange specific details of the order"
70
70
  )
71
71
  pnl: Optional[StrictStr] = None
@@ -138,9 +138,6 @@ class Order(BaseModel):
138
138
  exclude=excluded_fields,
139
139
  exclude_none=True,
140
140
  )
141
- # override the default output from pydantic by calling `to_dict()` of order_details
142
- if self.order_details:
143
- _dict["order_details"] = self.order_details.to_dict()
144
141
  # set to None if trading_action_id (nullable) is None
145
142
  # and model_fields_set contains the field
146
143
  if (
@@ -257,11 +254,6 @@ class Order(BaseModel):
257
254
  if self.leverage is None and "leverage" in self.model_fields_set:
258
255
  _dict["leverage"] = None
259
256
 
260
- # set to None if order_details (nullable) is None
261
- # and model_fields_set contains the field
262
- if self.order_details is None and "order_details" in self.model_fields_set:
263
- _dict["order_details"] = None
264
-
265
257
  # set to None if pnl (nullable) is None
266
258
  # and model_fields_set contains the field
267
259
  if self.pnl is None and "pnl" in self.model_fields_set:
@@ -310,11 +302,7 @@ class Order(BaseModel):
310
302
  "sent_qty": obj.get("sent_qty"),
311
303
  "fee": obj.get("fee"),
312
304
  "leverage": obj.get("leverage"),
313
- "order_details": (
314
- AnyOf.from_dict(obj["order_details"])
315
- if obj.get("order_details") is not None
316
- else None
317
- ),
305
+ "order_details": obj.get("order_details"),
318
306
  "pnl": obj.get("pnl"),
319
307
  "order_time": obj.get("order_time"),
320
308
  }
@@ -34,7 +34,10 @@ class SpotTradingActionCreate(BaseModel):
34
34
  execution_id: Optional[StrictStr] = None
35
35
  open_order_execution_id: Optional[StrictStr] = None
36
36
  action_type: TradingActionType = Field(description="The type of action.")
37
- market_type: MarketType = Field(description="The type of market the action is for.")
37
+ market_type: Optional[MarketType] = Field(
38
+ default=None,
39
+ description="The type of market the action is for. Must be set to spot.",
40
+ )
38
41
  strategy_id: StrictStr = Field(description="UID for the strategy.")
39
42
  symbol: StrictStr = Field(
40
43
  description="Trading symbol or asset pair in format: 'symbol/quote_currency' (see market service for valid symbols)"
@@ -34,13 +34,11 @@ class TPSL(BaseModel):
34
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
35
  )
36
36
  execution_id: Optional[StrictStr] = None
37
- client_order_id: Optional[StrictStr] = None
38
37
  __properties: ClassVar[List[str]] = [
39
38
  "price_delta",
40
39
  "price",
41
40
  "allocation",
42
41
  "execution_id",
43
- "client_order_id",
44
42
  ]
45
43
 
46
44
  model_config = ConfigDict(
@@ -95,11 +93,6 @@ class TPSL(BaseModel):
95
93
  if self.execution_id is None and "execution_id" in self.model_fields_set:
96
94
  _dict["execution_id"] = None
97
95
 
98
- # set to None if client_order_id (nullable) is None
99
- # and model_fields_set contains the field
100
- if self.client_order_id is None and "client_order_id" in self.model_fields_set:
101
- _dict["client_order_id"] = None
102
-
103
96
  return _dict
104
97
 
105
98
  @classmethod
@@ -117,7 +110,6 @@ class TPSL(BaseModel):
117
110
  "price": obj.get("price"),
118
111
  "allocation": obj.get("allocation"),
119
112
  "execution_id": obj.get("execution_id"),
120
- "client_order_id": obj.get("client_order_id"),
121
113
  }
122
114
  )
123
115
  return _obj
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crypticorn
3
- Version: 2.15.0
3
+ Version: 2.17.0rc1
4
4
  Summary: Maximise Your Crypto Trading Profits with Machine Learning
5
5
  Author-email: Crypticorn <timon@crypticorn.com>
6
6
  License-Expression: MIT
@@ -25,6 +25,7 @@ Requires-Dist: click<9.0.0,>=8.0.0
25
25
  Requires-Dist: psutil<8.0.0,>=7.0.0
26
26
  Requires-Dist: setuptools<81.0.0,>=80.0.0
27
27
  Requires-Dist: strenum
28
+ Requires-Dist: prometheus-client<1.0.0,>=0.22.0
28
29
  Requires-Dist: urllib3<3.0.0,>=1.25.3
29
30
  Requires-Dist: python_dateutil<3.0.0,>=2.8.2
30
31
  Requires-Dist: aiohttp<4.0.0,>=3.8.4
@@ -84,6 +84,7 @@ crypticorn/common/enums.py
84
84
  crypticorn/common/errors.py
85
85
  crypticorn/common/exceptions.py
86
86
  crypticorn/common/logging.py
87
+ crypticorn/common/metrics.py
87
88
  crypticorn/common/middleware.py
88
89
  crypticorn/common/mixins.py
89
90
  crypticorn/common/openapi.py
@@ -3,6 +3,7 @@ click<9.0.0,>=8.0.0
3
3
  psutil<8.0.0,>=7.0.0
4
4
  setuptools<81.0.0,>=80.0.0
5
5
  strenum
6
+ prometheus-client<1.0.0,>=0.22.0
6
7
  urllib3<3.0.0,>=1.25.3
7
8
  python_dateutil<3.0.0,>=2.8.2
8
9
  aiohttp<4.0.0,>=3.8.4
@@ -5,7 +5,7 @@ readme = "README.md"
5
5
  license = "MIT"
6
6
  requires-python = ">=3.9"
7
7
  authors = [{name = "Crypticorn", email = "timon@crypticorn.com"}]
8
- version = "2.15.0"
8
+ version = "2.17.0-rc.1"
9
9
  keywords = ["machine learning", "data science", "crypto", "modelling"]
10
10
  dynamic = ["dependencies", "optional-dependencies"]
11
11
 
@@ -4,6 +4,7 @@ click >= 8.0.0, < 9.0.0
4
4
  psutil >= 7.0.0, < 8.0.0
5
5
  setuptools >= 80.0.0, < 81.0.0
6
6
  strenum # drop this once we drop python 3.10, StrEnum is available in stdlib (enum) in 3.11+
7
+ prometheus-client >= 0.22.0, < 1.0.0
7
8
 
8
9
  # crypticorn/trade/requirements.txt
9
10
  urllib3 >= 1.25.3, < 3.0.0
@@ -0,0 +1,62 @@
1
+ import pytest
2
+ from pydantic import BaseModel, ValidationError
3
+ from crypticorn.common import PaginationParams
4
+
5
+
6
+ class Item(BaseModel):
7
+ name: str
8
+ value: int
9
+
10
+
11
+ @pytest.mark.asyncio
12
+ async def test_pagination():
13
+ with pytest.raises(TypeError, match="PaginationParams must be used with a Pydantic BaseModel as a generic parameter"):
14
+ PaginationParams[int]()
15
+ with pytest.raises(ValueError, match="Invalid sort field: 'foo' — must be one of: \\['name', 'value'\\]"):
16
+ PaginationParams[Item](sort="foo")
17
+
18
+ pagination_params = PaginationParams[Item](sort="name", order="asc")
19
+ assert pagination_params.sort == "name"
20
+ assert pagination_params.order == "asc"
21
+ assert pagination_params.page == 1
22
+ assert pagination_params.size == 10
23
+
24
+
25
+ @pytest.mark.asyncio
26
+ async def test_pagination_order_validation():
27
+ # Test invalid order values
28
+ with pytest.raises(ValidationError):
29
+ PaginationParams[Item](order="invalid")
30
+
31
+
32
+ @pytest.mark.asyncio
33
+ async def test_pagination_sort_order_interaction():
34
+ # Test that sort and order must be provided together
35
+ with pytest.raises(ValueError, match="Sort and order must be provided together"):
36
+ PaginationParams[Item](sort="name")
37
+
38
+ with pytest.raises(ValueError, match="Sort and order must be provided together"):
39
+ PaginationParams[Item](order="asc")
40
+
41
+ # Test valid combination
42
+ params = PaginationParams[Item](sort="name", order="asc")
43
+ assert params.sort == "name"
44
+ assert params.order == "asc"
45
+
46
+
47
+ @pytest.mark.asyncio
48
+ async def test_pagination_default_values():
49
+ params = PaginationParams[Item]()
50
+ assert params.page == 1
51
+ assert params.size == 10
52
+ assert params.sort is None
53
+ assert params.order is None
54
+
55
+
56
+ @pytest.mark.asyncio
57
+ async def test_pagination_custom_values():
58
+ params = PaginationParams[Item](page=2, size=20, sort="value", order="desc")
59
+ assert params.page == 2
60
+ assert params.size == 20
61
+ assert params.sort == "value"
62
+ assert params.order == "desc"