Qubx 1.2.2.dev1__tar.gz → 1.2.2.dev3__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 (310) hide show
  1. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/PKG-INFO +1 -1
  2. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/_version.py +2 -2
  3. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/release.py +5 -0
  4. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/account.py +27 -1
  5. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py +13 -0
  6. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/okx/account.py +69 -3
  7. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/account.py +8 -2
  8. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/utils.pyx +6 -0
  9. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/.gitignore +0 -0
  10. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/LICENSE +0 -0
  11. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/README.md +0 -0
  12. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/pyproject.toml +0 -0
  13. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/scripts/build.py +0 -0
  14. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/__init__.py +0 -0
  15. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/_nb_magic.py +0 -0
  16. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/__init__.py +0 -0
  17. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/account.py +0 -0
  18. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/broker.py +0 -0
  19. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/data.py +0 -0
  20. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/iteratedstream.py +0 -0
  21. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/management.py +0 -0
  22. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/ome.py +0 -0
  23. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/optimization.py +0 -0
  24. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/runner.py +0 -0
  25. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/sentinels.py +0 -0
  26. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/simulated_data.py +0 -0
  27. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/simulated_exchange.py +0 -0
  28. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/simulator.py +0 -0
  29. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/transfers.py +0 -0
  30. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/backtester/utils.py +0 -0
  31. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/__init__.py +0 -0
  32. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/commands.py +0 -0
  33. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/deploy.py +0 -0
  34. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/misc.py +0 -0
  35. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/resolver.py +0 -0
  36. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/s3.py +0 -0
  37. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/theme.py +0 -0
  38. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/tui.py +0 -0
  39. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/cli/user_config.py +0 -0
  40. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/config.py +0 -0
  41. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/__init__.py +0 -0
  42. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/__init__.py +0 -0
  43. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  44. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  45. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/broker.py +0 -0
  46. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
  47. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/data.py +0 -0
  48. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  49. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  50. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  51. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  52. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  53. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  54. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  55. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  56. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
  57. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
  58. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  59. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +0 -0
  60. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  61. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  62. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/okx/__init__.py +0 -0
  63. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/okx/broker.py +0 -0
  64. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/exchanges/okx/okx.py +0 -0
  65. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/factory.py +0 -0
  66. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  67. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  68. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  69. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  70. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  71. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
  72. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  73. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  74. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  75. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  76. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/rate_limits.py +0 -0
  77. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  78. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  79. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  80. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/utils.py +0 -0
  81. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  82. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/registry.py +0 -0
  83. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/tardis/data.py +0 -0
  84. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/connectors/tardis/utils.py +0 -0
  85. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/__init__.py +0 -0
  86. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/builtin.py +0 -0
  87. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/decorator.py +0 -0
  88. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/executor.py +0 -0
  89. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/interfaces.py +0 -0
  90. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/server.py +0 -0
  91. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/control/types.py +0 -0
  92. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/__init__.py +0 -0
  93. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/basics.py +0 -0
  94. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/context.py +0 -0
  95. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/detectors/__init__.py +0 -0
  96. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/detectors/delisting.py +0 -0
  97. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/detectors/stale.py +0 -0
  98. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/errors.py +0 -0
  99. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/exceptions.py +0 -0
  100. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/helpers.py +0 -0
  101. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/initializer.py +0 -0
  102. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/interfaces.py +0 -0
  103. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/loggers.py +0 -0
  104. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/lookups.py +0 -0
  105. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/metrics.py +0 -0
  106. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/__init__.py +0 -0
  107. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/market.py +0 -0
  108. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/processing.py +0 -0
  109. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/subscription.py +0 -0
  110. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/trading.py +0 -0
  111. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/universe.py +0 -0
  112. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/mixins/utils.py +0 -0
  113. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/series.pxd +0 -0
  114. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/series.pyi +0 -0
  115. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/series.pyx +0 -0
  116. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/core/utils.pyi +0 -0
  117. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/__init__.py +0 -0
  118. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/cache.py +0 -0
  119. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/containers.py +0 -0
  120. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/guards.py +0 -0
  121. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/registry.py +0 -0
  122. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storage.py +0 -0
  123. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/ccxt.py +0 -0
  124. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/csv.py +0 -0
  125. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/handy.py +0 -0
  126. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/multi.py +0 -0
  127. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/questdb.py +0 -0
  128. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/stub.py +0 -0
  129. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/storages/utils.py +0 -0
  130. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/data/transformers.py +0 -0
  131. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/__init__.py +0 -0
  132. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/base.py +0 -0
  133. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/composite.py +0 -0
  134. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/csv.py +0 -0
  135. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/indicator.py +0 -0
  136. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/inmemory.py +0 -0
  137. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/prometheus.py +0 -0
  138. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/emitters/questdb.py +0 -0
  139. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/__init__.py +0 -0
  140. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/composite.py +0 -0
  141. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/formatters/__init__.py +0 -0
  142. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/formatters/base.py +0 -0
  143. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/formatters/incremental.py +0 -0
  144. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/formatters/slack.py +0 -0
  145. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/formatters/target_position.py +0 -0
  146. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/redis_streams.py +0 -0
  147. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/exporters/slack.py +0 -0
  148. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/gathering/simplest.py +0 -0
  149. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/health/__init__.py +0 -0
  150. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/health/base.py +0 -0
  151. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/health/dummy.py +0 -0
  152. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/__init__.py +0 -0
  153. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/csv.py +0 -0
  154. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/factory.py +0 -0
  155. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/inmemory.py +0 -0
  156. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/mongo.py +0 -0
  157. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/loggers/postgres.py +0 -0
  158. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/notifications/__init__.py +0 -0
  159. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/notifications/composite.py +0 -0
  160. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/notifications/slack.py +0 -0
  161. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/notifications/throttler.py +0 -0
  162. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/pandaz/__init__.py +0 -0
  163. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/pandaz/stats.py +0 -0
  164. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/pandaz/ta.py +0 -0
  165. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/pandaz/utils.py +0 -0
  166. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/plugins/__init__.py +0 -0
  167. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/plugins/loader.py +0 -0
  168. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/__init__.py +0 -0
  169. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/backend.py +0 -0
  170. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/config.py +0 -0
  171. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/engine.py +0 -0
  172. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/ip_resolver.py +0 -0
  173. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/manager.py +0 -0
  174. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/pools.py +0 -0
  175. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/rate_limiting/redis_backend.py +0 -0
  176. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/_build.py +0 -0
  177. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/crypto-fees.ini +0 -0
  178. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  179. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  180. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  181. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  182. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  183. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  184. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  185. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  186. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  187. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  188. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  189. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restarts/__init__.py +0 -0
  190. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restarts/state_resolvers.py +0 -0
  191. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restarts/time_finders.py +0 -0
  192. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/__init__.py +0 -0
  193. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/balance.py +0 -0
  194. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/factory.py +0 -0
  195. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/interfaces.py +0 -0
  196. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/position.py +0 -0
  197. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/signal.py +0 -0
  198. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/state.py +0 -0
  199. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/restorers/utils.py +0 -0
  200. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/state/__init__.py +0 -0
  201. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/state/dummy.py +0 -0
  202. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/state/redis.py +0 -0
  203. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/ta/__init__.py +0 -0
  204. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/ta/indicators.pxd +0 -0
  205. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/ta/indicators.pyi +0 -0
  206. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/ta/indicators.pyx +0 -0
  207. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/__init__.py +0 -0
  208. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/base.py +0 -0
  209. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  210. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/config.yml.j2 +0 -0
  211. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  212. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  213. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  214. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  215. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  216. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/project/template.yml +0 -0
  217. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.claude/skills/qubx-cli/SKILL.md +0 -0
  218. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.claude/skills/qubx-indicators/SKILL.md +0 -0
  219. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.claude/skills/simulation-explorer/SKILL.md +0 -0
  220. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.claude/skills/strategy-release/SKILL.md +0 -0
  221. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.github/workflows/ci.yml.j2 +0 -0
  222. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.gitignore.j2 +0 -0
  223. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.python-version +0 -0
  224. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.vscode/launch.json +0 -0
  225. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.vscode/settings.json +0 -0
  226. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/.vscode/tasks.json +0 -0
  227. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/CLAUDE.md.j2 +0 -0
  228. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/README.md.j2 +0 -0
  229. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/configs/.gitkeep +0 -0
  230. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/justfile.j2 +0 -0
  231. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/pyproject.toml.j2 +0 -0
  232. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/research/.gitkeep +0 -0
  233. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  234. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/src/{{ strategy_name }}/cli.py.j2 +0 -0
  235. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  236. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/template.yml +0 -0
  237. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/repo/tests/test_strategy.py.j2 +0 -0
  238. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  239. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  240. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/config.yml.j2 +0 -0
  241. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  242. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  243. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  244. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/templates/simple/template.yml +0 -0
  245. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/__init__.py +0 -0
  246. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/advanced.py +0 -0
  247. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/composite.py +0 -0
  248. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/rebalancers.py +0 -0
  249. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/riskctrl.py +0 -0
  250. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/trackers/sizers.py +0 -0
  251. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/__init__.py +0 -0
  252. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/_pyxreloader.py +0 -0
  253. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/charting/lookinglass.py +0 -0
  254. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  255. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/charting/orderbook.py +0 -0
  256. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/collections.py +0 -0
  257. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/hft/__init__.py +0 -0
  258. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/hft/numba_utils.py +0 -0
  259. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/hft/orderbook.pyi +0 -0
  260. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/hft/orderbook.pyx +0 -0
  261. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/marketdata/binance.py +0 -0
  262. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/marketdata/ccxt.py +0 -0
  263. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/marketdata/dukas.py +0 -0
  264. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/misc.py +0 -0
  265. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/nonce.py +0 -0
  266. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/ntp.py +0 -0
  267. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/numbers_utils.py +0 -0
  268. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/orderbook.py +0 -0
  269. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/__init__.py +0 -0
  270. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/dashboard.py +0 -0
  271. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/data.py +0 -0
  272. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/interfaces.py +0 -0
  273. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  274. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  275. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/questdb.py +0 -0
  276. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/rate_limiter.py +0 -0
  277. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/results.py +0 -0
  278. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/ringbuffer.pxd +0 -0
  279. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/ringbuffer.pyi +0 -0
  280. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/ringbuffer.pyx +0 -0
  281. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/__init__.py +0 -0
  282. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  283. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/accounts.py +0 -0
  284. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/configs.py +0 -0
  285. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/factory.py +0 -0
  286. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/kernel_service.py +0 -0
  287. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/runner.py +0 -0
  288. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/__init__.py +0 -0
  289. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/app.py +0 -0
  290. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/handlers.py +0 -0
  291. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/init_code.py +0 -0
  292. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/kernel.py +0 -0
  293. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/styles.tcss +0 -0
  294. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
  295. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/account_summary.py +0 -0
  296. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
  297. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
  298. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
  299. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
  300. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
  301. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
  302. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/s3.py +0 -0
  303. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/slack.py +0 -0
  304. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/throttler.py +0 -0
  305. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/time.py +0 -0
  306. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/src/qubx/utils/websocket_manager.py +0 -0
  307. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
  308. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
  309. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
  310. {qubx-1.2.2.dev1 → qubx-1.2.2.dev3}/tests/strategies/obi_trader/src/obi_trader/models/obi_trader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Qubx
3
- Version: 1.2.2.dev1
3
+ Version: 1.2.2.dev3
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Project-URL: homepage, https://xlydian.com
6
6
  Project-URL: repository, https://github.com/xLydianSoftware/Qubx
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.2.2.dev1'
22
- __version_tuple__ = version_tuple = (1, 2, 2, 'dev1')
21
+ __version__ = version = '1.2.2.dev3'
22
+ __version_tuple__ = version_tuple = (1, 2, 2, 'dev3')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1432,12 +1432,14 @@ def _bundle_source_overrides(
1432
1432
  continue
1433
1433
 
1434
1434
  checkout_dir = _find_uv_git_checkout(commit_sha)
1435
+ cloned_locally = False
1435
1436
  if not checkout_dir:
1436
1437
  # Cache miss — clone the repo at the exact commit
1437
1438
  git_url = source["git"]
1438
1439
  git_ref = source.get("tag") or source.get("branch") or commit_sha
1439
1440
  logger.info(f" {pkg_name}: cache miss, cloning {git_url} at {git_ref} ...")
1440
1441
  checkout_dir = os.path.join(os.path.dirname(wheels_dir), f".git-clone-{pkg_norm}")
1442
+ cloned_locally = True
1441
1443
  try:
1442
1444
  subprocess.run(
1443
1445
  ["git", "clone", "--depth", "1", "--branch", git_ref, git_url, checkout_dir],
@@ -1473,6 +1475,9 @@ def _bundle_source_overrides(
1473
1475
  logger.info(f" Bundled {pkg_name}=={pkg_ver} from git")
1474
1476
  except subprocess.CalledProcessError as e:
1475
1477
  logger.opt(colors=False).warning(f" Failed to build wheel for {pkg_name}: {e.stderr or e}")
1478
+ finally:
1479
+ if cloned_locally and os.path.isdir(checkout_dir):
1480
+ shutil.rmtree(checkout_dir, ignore_errors=True)
1476
1481
 
1477
1482
  return bundled
1478
1483
 
@@ -222,7 +222,10 @@ class CcxtAccountProcessor(BasicAccountProcessor):
222
222
  except Exception as e:
223
223
  logger.warning(f"Failed to fetch balance data before polling started: {e}")
224
224
 
225
- # sum of balances + market value of all positions on non spot/margin
225
+ if self._exchange_total_capital is not None:
226
+ return self._exchange_total_capital
227
+
228
+ # fallback: sum of balances + market value of all positions on non spot/margin
226
229
  _currency_to_value = {c: self._get_currency_value(b.total, c) for c, b in self._balances.items()}
227
230
  _positions_value = sum([p.market_value_funds for p in self._positions.values() if p.instrument.is_futures()])
228
231
  return sum(_currency_to_value.values()) + _positions_value
@@ -316,9 +319,32 @@ class CcxtAccountProcessor(BasicAccountProcessor):
316
319
  await self._subscribe_instruments(list(self._required_instruments))
317
320
  self._latest_instruments.update(self._required_instruments)
318
321
 
322
+ def _extract_portfolio_value(self, balances_raw: dict) -> float | None:
323
+ """Extract exchange-reported portfolio value (equity) from raw balance response.
324
+
325
+ Override in exchange-specific processors for non-standard responses.
326
+ Base implementation handles Binance futures (totalMarginBalance).
327
+
328
+ Returns:
329
+ Total equity as float, or None to fall back to computed value.
330
+ """
331
+ info = balances_raw.get("info", {})
332
+ val = info.get("totalMarginBalance")
333
+ if val is not None:
334
+ try:
335
+ return float(val)
336
+ except (ValueError, TypeError):
337
+ pass
338
+ return None
339
+
319
340
  async def _update_balance(self) -> None:
320
341
  """Fetch and update balances from exchange"""
321
342
  balances_raw = await self.exchange_manager.exchange.fetch_balance()
343
+
344
+ equity = self._extract_portfolio_value(balances_raw)
345
+ if equity is not None:
346
+ self._exchange_total_capital = equity
347
+
322
348
  balances = ccxt_convert_balance(balances_raw, self.exchange)
323
349
  current_balances = self.get_balances()
324
350
 
@@ -23,6 +23,19 @@ class HyperliquidAccountProcessor(CcxtAccountProcessor):
23
23
  so we must subscribe to both channels separately.
24
24
  """
25
25
 
26
+ def _extract_portfolio_value(self, balances_raw: dict) -> float | None:
27
+ """Extract Hyperliquid account value from raw balance response."""
28
+ info = balances_raw.get("info", {})
29
+ for key in ("marginSummary", "crossMarginSummary"):
30
+ summary = info.get(key, {})
31
+ val = summary.get("accountValue")
32
+ if val is not None:
33
+ try:
34
+ return float(val)
35
+ except (ValueError, TypeError):
36
+ pass
37
+ return None
38
+
26
39
  async def _subscribe_instruments(self, instruments: list[Instrument]):
27
40
  """Override to filter out instruments from other exchanges (e.g., spot vs futures)."""
28
41
  # Filter instruments to only those belonging to this exchange
@@ -18,8 +18,35 @@ class OkxAccountProcessor(CcxtAccountProcessor):
18
18
  so we must subscribe to both channels separately:
19
19
  - orders channel: for order status updates (watch_orders)
20
20
  - trades channel: for trade/fill updates (watch_my_trades)
21
+
22
+ Balance streaming: uses watch_balance WS to get real-time totalEq updates
23
+ instead of relying solely on 30s polling.
21
24
  """
22
25
 
26
+ def start(self):
27
+ super().start()
28
+ if self._is_running and not self.exchange_manager.exchange.isSandboxModeEnabled:
29
+ self._polling_tasks["balance_ws"] = self._loop.submit(self._watch_balance_stream())
30
+
31
+ async def _watch_balance_stream(self):
32
+ """Stream balance updates via WS to get real-time totalEq."""
33
+
34
+ async def _watch():
35
+ balances_raw = await self.exchange_manager.exchange.watch_balance()
36
+ equity = self._extract_portfolio_value(balances_raw)
37
+ if equity is not None:
38
+ self._exchange_total_capital = equity
39
+ margin_ratio = self._extract_margin_ratio(balances_raw)
40
+ if margin_ratio is not None:
41
+ self._exchange_margin_ratio = margin_ratio
42
+
43
+ await self._listen_to_stream(
44
+ subscriber=_watch,
45
+ exchange=self.exchange_manager.exchange,
46
+ channel=self.channel,
47
+ name="okx_balance_ws",
48
+ )
49
+
23
50
  async def _subscribe_executions(self, name: str, channel: CtrlChannel):
24
51
  logger.info("<yellow>[OKX]</yellow> Subscribing to executions (orders + trades)")
25
52
  _symbol_to_instrument = {}
@@ -57,15 +84,54 @@ class OkxAccountProcessor(CcxtAccountProcessor):
57
84
  ),
58
85
  )
59
86
 
87
+ def _get_account_data(self, balances_raw: dict) -> dict:
88
+ """Get the OKX account data dict from info.data[0]."""
89
+ return balances_raw.get("info", {}).get("data", [{}])[0]
90
+
91
+ def _extract_margin_ratio(self, balances_raw: dict) -> float | None:
92
+ """Extract OKX margin ratio from the base currency detail entry.
93
+
94
+ The account-level mgnRatio is empty; the real value is per-currency in details.
95
+ We use the base currency's mgnRatio as the account margin ratio.
96
+ """
97
+ details = self._get_account_data(balances_raw).get("details", [])
98
+ for detail in details:
99
+ if detail.get("ccy", "").upper() == self.base_currency.upper():
100
+ val = detail.get("mgnRatio")
101
+ if val is not None and val != "":
102
+ try:
103
+ return float(val)
104
+ except (ValueError, TypeError):
105
+ pass
106
+ return None
107
+
108
+ def _extract_portfolio_value(self, balances_raw: dict) -> float | None:
109
+ """Extract OKX total equity from info.data[0].totalEq."""
110
+ total_eq = self._get_account_data(balances_raw).get("totalEq")
111
+ if total_eq is not None and total_eq != "":
112
+ try:
113
+ return float(total_eq)
114
+ except (ValueError, TypeError):
115
+ pass
116
+ return None
117
+
60
118
  async def _update_balance(self) -> None:
61
- """OKX balance override: use cashBal instead of eq (equity) to avoid double-counting unrealized PnL.
119
+ """OKX balance override: use cashBal for per-currency balances.
62
120
 
63
121
  CCXT maps OKX's `eq` (equity = cashBal + unrealizedPnL) to balance `total`.
64
- Since get_total_capital() adds position market values (= unrealized PnL) on top,
65
- using `eq` would double-count unrealized PnL. We use `cashBal` instead.
122
+ We use `cashBal` for individual currency balances, and extract `totalEq`
123
+ as the authoritative portfolio value via _extract_portfolio_value().
66
124
  """
67
125
  balances_raw = await self.exchange_manager.exchange.fetch_balance()
68
126
 
127
+ equity = self._extract_portfolio_value(balances_raw)
128
+ if equity is not None:
129
+ self._exchange_total_capital = equity
130
+
131
+ margin_ratio = self._extract_margin_ratio(balances_raw)
132
+ if margin_ratio is not None:
133
+ self._exchange_margin_ratio = margin_ratio
134
+
69
135
  # Extract cashBal from raw OKX response instead of CCXT-parsed eq
70
136
  balances: list[AssetBalance] = []
71
137
  raw_details = balances_raw.get("info", {}).get("data", [{}])[0].get("details", [])
@@ -65,6 +65,8 @@ class BasicAccountProcessor(IAccountProcessor):
65
65
  self._locked_capital_by_order = dict()
66
66
  self._pending_order_requests = {}
67
67
  self._balances = {}
68
+ self._exchange_total_capital: float | None = None
69
+ self._exchange_margin_ratio: float | None = None
68
70
  # Initialize with base currency balance
69
71
  self._balances[self.base_currency] = AssetBalance(
70
72
  exchange=self.exchange, currency=self.base_currency, free=initial_capital, locked=0.0, total=initial_capital
@@ -90,7 +92,9 @@ class BasicAccountProcessor(IAccountProcessor):
90
92
  return self.get_available_margin(exchange)
91
93
 
92
94
  def get_total_capital(self, exchange: str | None = None) -> float:
93
- # sum of cash + market value of all positions
95
+ if self._exchange_total_capital is not None:
96
+ return self._exchange_total_capital
97
+ # fallback: sum of cash + market value of all positions
94
98
  _cash_amount = self._balances[self.base_currency].total
95
99
  _positions_value = sum([p.market_value_funds for p in self._positions.values()])
96
100
  return _cash_amount + _positions_value
@@ -180,7 +184,9 @@ class BasicAccountProcessor(IAccountProcessor):
180
184
  return self.get_total_capital(exchange) - self.get_total_required_margin(exchange)
181
185
 
182
186
  def get_margin_ratio(self, exchange: str | None = None) -> float:
183
- # total capital / total required margin
187
+ if self._exchange_margin_ratio is not None:
188
+ return self._exchange_margin_ratio
189
+ # fallback: total capital / total required margin
184
190
  required_margin = self.get_total_required_margin(exchange)
185
191
  if required_margin == 0:
186
192
  return 100.0
@@ -8,6 +8,12 @@ NS = 1_000_000_000
8
8
 
9
9
  cpdef recognize_time(time):
10
10
  if isinstance(time, str):
11
+ # Strip timezone suffix (e.g. 'Z', '+00:00') — np.datetime64 expects tz-naive ISO strings.
12
+ # All incoming timestamps are assumed UTC.
13
+ if time.endswith('Z') or time.endswith('z'):
14
+ time = time[:-1]
15
+ elif '+' in time[10:]:
16
+ time = time[:time.rindex('+')]
11
17
  return np.datetime64(time, 'ns')
12
18
  elif isinstance(time, np.datetime64):
13
19
  return time
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes