Qubx 3.22.1__tar.gz → 4.0.0.dev1__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 (339) hide show
  1. {qubx-3.22.1 → qubx-4.0.0.dev1}/PKG-INFO +1 -2
  2. {qubx-3.22.1 → qubx-4.0.0.dev1}/pyproject.toml +0 -2
  3. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/_version.py +2 -2
  4. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/simulator.py +5 -5
  5. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/config.py +13 -3
  6. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/utils.py +1 -2
  7. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/config.py +4 -0
  8. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/manager.py +1 -0
  9. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/state.py +22 -2
  10. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/basics.py +86 -40
  11. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/detectors/delisting.py +3 -3
  12. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/interfaces.py +4 -5
  13. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/lookups.py +216 -72
  14. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/universe.py +6 -6
  15. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/loggers/__init__.py +1 -3
  16. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/loggers/factory.py +0 -2
  17. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/balance.py +1 -83
  18. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/factory.py +4 -8
  19. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/position.py +1 -120
  20. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/signal.py +1 -153
  21. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/state.py +5 -124
  22. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/utils.py +4 -30
  23. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/marketdata/binance.py +0 -9
  24. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/marketdata/ccxt.py +16 -33
  25. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/marketdata/dukas.py +0 -21
  26. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/configs.py +2 -0
  27. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/runner.py +0 -10
  28. qubx-3.22.1/src/qubx/loggers/mongo.py +0 -76
  29. {qubx-3.22.1 → qubx-4.0.0.dev1}/.gitignore +0 -0
  30. {qubx-3.22.1 → qubx-4.0.0.dev1}/LICENSE +0 -0
  31. {qubx-3.22.1 → qubx-4.0.0.dev1}/README.md +0 -0
  32. {qubx-3.22.1 → qubx-4.0.0.dev1}/scripts/build.py +0 -0
  33. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/__init__.py +0 -0
  34. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/_nb_magic.py +0 -0
  35. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/__init__.py +0 -0
  36. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/connector.py +0 -0
  37. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/data.py +0 -0
  38. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/iteratedstream.py +0 -0
  39. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/management.py +0 -0
  40. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/ome.py +0 -0
  41. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/optimization.py +0 -0
  42. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/runner.py +0 -0
  43. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/sentinels.py +0 -0
  44. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/simulated_data.py +0 -0
  45. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/simulated_exchange.py +0 -0
  46. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/transfers.py +0 -0
  47. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/backtester/utils.py +0 -0
  48. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/__init__.py +0 -0
  49. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/commands.py +0 -0
  50. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/deploy.py +0 -0
  51. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/misc.py +0 -0
  52. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/release.py +0 -0
  53. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/resolver.py +0 -0
  54. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/s3.py +0 -0
  55. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/theme.py +0 -0
  56. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/tui.py +0 -0
  57. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/cli/user_config.py +0 -0
  58. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/__init__.py +0 -0
  59. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/__init__.py +0 -0
  60. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  61. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  62. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
  63. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/connector.py +0 -0
  64. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/data.py +0 -0
  65. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  66. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  67. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  68. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/_two_stream.py +0 -0
  69. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  70. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/binance/connector.py +0 -0
  71. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  72. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  73. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/bitfinex/connector.py +0 -0
  74. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/bybit/__init__.py +0 -0
  75. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/bybit/bybit.py +0 -0
  76. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/bybit/connector.py +0 -0
  77. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
  78. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
  79. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  80. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  81. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  82. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/okx/__init__.py +0 -0
  83. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/okx/connector.py +0 -0
  84. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/exchanges/okx/okx.py +0 -0
  85. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/factory.py +0 -0
  86. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  87. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  88. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  89. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  90. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  91. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
  92. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  93. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  94. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  95. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  96. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/plugin.py +0 -0
  97. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/rate_limits.py +0 -0
  98. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  99. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  100. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  101. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  102. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/plugin.py +0 -0
  103. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/registry.py +0 -0
  104. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/tardis/data.py +0 -0
  105. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/tardis/plugin.py +0 -0
  106. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/connectors/tardis/utils.py +0 -0
  107. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/__init__.py +0 -0
  108. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/builtin.py +0 -0
  109. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/decorator.py +0 -0
  110. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/executor.py +0 -0
  111. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/interfaces.py +0 -0
  112. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/server.py +0 -0
  113. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/control/types.py +0 -0
  114. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/__init__.py +0 -0
  115. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/__init__.py +0 -0
  116. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/diffs.py +0 -0
  117. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/reconciler.py +0 -0
  118. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/reducer.py +0 -0
  119. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/account_manager/state_machine.py +0 -0
  120. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/boot.py +0 -0
  121. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/connector.py +0 -0
  122. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/context.py +0 -0
  123. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/detectors/__init__.py +0 -0
  124. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/detectors/stale.py +0 -0
  125. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/errors.py +0 -0
  126. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/events.py +0 -0
  127. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/exceptions.py +0 -0
  128. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/fit_context.py +0 -0
  129. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/fit_executor.py +0 -0
  130. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/helpers.py +0 -0
  131. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/initializer.py +0 -0
  132. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/instrument_service.py +0 -0
  133. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/loggers.py +0 -0
  134. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/metrics.py +0 -0
  135. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/__init__.py +0 -0
  136. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/instrument_service.py +0 -0
  137. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/market.py +0 -0
  138. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/processing.py +0 -0
  139. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/subscription.py +0 -0
  140. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/trading.py +0 -0
  141. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/mixins/utils.py +0 -0
  142. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/series.pxd +0 -0
  143. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/series.pyi +0 -0
  144. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/series.pyx +0 -0
  145. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/state_snapshot.py +0 -0
  146. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/status.py +0 -0
  147. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/subscription_watchdog.py +0 -0
  148. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/utils.pyi +0 -0
  149. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/core/utils.pyx +0 -0
  150. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/__init__.py +0 -0
  151. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/cache.py +0 -0
  152. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/containers.py +0 -0
  153. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/guards.py +0 -0
  154. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/registry.py +0 -0
  155. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storage.py +0 -0
  156. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/_missing_extra.py +0 -0
  157. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/ccxt.py +0 -0
  158. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/csv.py +0 -0
  159. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/dukascopy.py +0 -0
  160. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/handy.py +0 -0
  161. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/iceberg.py +0 -0
  162. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/multi.py +0 -0
  163. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/questdb.py +0 -0
  164. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/stub.py +0 -0
  165. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/utils.py +0 -0
  166. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/storages/yahoo.py +0 -0
  167. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/data/transformers.py +0 -0
  168. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/__init__.py +0 -0
  169. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/base.py +0 -0
  170. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/composite.py +0 -0
  171. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/csv.py +0 -0
  172. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/indicator.py +0 -0
  173. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/inmemory.py +0 -0
  174. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/prometheus.py +0 -0
  175. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/emitters/questdb.py +0 -0
  176. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/__init__.py +0 -0
  177. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/composite.py +0 -0
  178. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/formatters/__init__.py +0 -0
  179. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/formatters/base.py +0 -0
  180. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/formatters/incremental.py +0 -0
  181. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/formatters/slack.py +0 -0
  182. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/formatters/target_position.py +0 -0
  183. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/redis_streams.py +0 -0
  184. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/exporters/slack.py +0 -0
  185. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/gathering/simplest.py +0 -0
  186. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/health/__init__.py +0 -0
  187. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/health/base.py +0 -0
  188. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/health/dummy.py +0 -0
  189. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/health/status.py +0 -0
  190. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/loggers/csv.py +0 -0
  191. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/loggers/inmemory.py +0 -0
  192. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/loggers/postgres.py +0 -0
  193. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/notifications/__init__.py +0 -0
  194. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/notifications/composite.py +0 -0
  195. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/notifications/slack.py +0 -0
  196. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/notifications/throttler.py +0 -0
  197. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/pandaz/__init__.py +0 -0
  198. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/pandaz/stats.py +0 -0
  199. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/pandaz/ta.py +0 -0
  200. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/pandaz/utils.py +0 -0
  201. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/plugins/__init__.py +0 -0
  202. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/plugins/loader.py +0 -0
  203. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/__init__.py +0 -0
  204. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/backend.py +0 -0
  205. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/config.py +0 -0
  206. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/engine.py +0 -0
  207. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/ip_resolver.py +0 -0
  208. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/manager.py +0 -0
  209. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/pools.py +0 -0
  210. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/redis_backend.py +0 -0
  211. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/rate_limiting/resilient.py +0 -0
  212. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/_build.py +0 -0
  213. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/crypto-fees.ini +0 -0
  214. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  215. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  216. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  217. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  218. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  219. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  220. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  221. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  222. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  223. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  224. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  225. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restarts/__init__.py +0 -0
  226. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restarts/state_resolvers.py +0 -0
  227. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restarts/time_finders.py +0 -0
  228. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/__init__.py +0 -0
  229. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/restorers/interfaces.py +0 -0
  230. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/state/__init__.py +0 -0
  231. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/state/dummy.py +0 -0
  232. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/state/redis.py +0 -0
  233. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/state/runtime_info.py +0 -0
  234. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/state/safe.py +0 -0
  235. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/ta/__init__.py +0 -0
  236. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/ta/indicators.pxd +0 -0
  237. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/ta/indicators.pyi +0 -0
  238. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/ta/indicators.pyx +0 -0
  239. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/__init__.py +0 -0
  240. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/base.py +0 -0
  241. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  242. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/config.yml.j2 +0 -0
  243. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  244. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  245. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  246. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  247. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  248. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/project/template.yml +0 -0
  249. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.claude/skills/qubx-cli/SKILL.md +0 -0
  250. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.claude/skills/qubx-indicators/SKILL.md +0 -0
  251. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.claude/skills/simulation-explorer/SKILL.md +0 -0
  252. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.claude/skills/strategy-release/SKILL.md +0 -0
  253. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.github/workflows/ci.yml.j2 +0 -0
  254. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.gitignore.j2 +0 -0
  255. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.python-version +0 -0
  256. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.vscode/launch.json +0 -0
  257. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.vscode/settings.json +0 -0
  258. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/.vscode/tasks.json +0 -0
  259. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/CLAUDE.md.j2 +0 -0
  260. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/README.md.j2 +0 -0
  261. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/configs/.gitkeep +0 -0
  262. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/justfile.j2 +0 -0
  263. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/pyproject.toml.j2 +0 -0
  264. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/research/.gitkeep +0 -0
  265. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  266. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/cli.py.j2 +0 -0
  267. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  268. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/template.yml +0 -0
  269. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/repo/tests/test_strategy.py.j2 +0 -0
  270. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  271. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  272. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/config.yml.j2 +0 -0
  273. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  274. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  275. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  276. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/templates/simple/template.yml +0 -0
  277. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/__init__.py +0 -0
  278. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/advanced.py +0 -0
  279. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/composite.py +0 -0
  280. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/rebalancers.py +0 -0
  281. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/riskctrl.py +0 -0
  282. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/trackers/sizers.py +0 -0
  283. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/__init__.py +0 -0
  284. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/_pyxreloader.py +0 -0
  285. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/charting/lookinglass.py +0 -0
  286. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  287. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/charting/orderbook.py +0 -0
  288. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/clock.py +0 -0
  289. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/collections.py +0 -0
  290. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/hft/__init__.py +0 -0
  291. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/hft/numba_utils.py +0 -0
  292. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/hft/orderbook.pyi +0 -0
  293. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/hft/orderbook.pyx +0 -0
  294. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/misc.py +0 -0
  295. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/nonce.py +0 -0
  296. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/numbers_utils.py +0 -0
  297. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/orderbook.py +0 -0
  298. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/__init__.py +0 -0
  299. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/dashboard.py +0 -0
  300. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/data.py +0 -0
  301. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/interfaces.py +0 -0
  302. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  303. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  304. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/questdb.py +0 -0
  305. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/rate_limiter.py +0 -0
  306. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/results.py +0 -0
  307. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/ringbuffer.pxd +0 -0
  308. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/ringbuffer.pyi +0 -0
  309. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/ringbuffer.pyx +0 -0
  310. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/__init__.py +0 -0
  311. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  312. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/accounts.py +0 -0
  313. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/factory.py +0 -0
  314. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/kernel_service.py +0 -0
  315. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/__init__.py +0 -0
  316. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/app.py +0 -0
  317. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/handlers.py +0 -0
  318. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/init_code.py +0 -0
  319. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/kernel.py +0 -0
  320. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/styles.tcss +0 -0
  321. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
  322. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/account_summary.py +0 -0
  323. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
  324. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
  325. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/log_filter.py +0 -0
  326. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
  327. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
  328. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
  329. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
  330. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/s3.py +0 -0
  331. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/slack.py +0 -0
  332. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/threading.py +0 -0
  333. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/throttler.py +0 -0
  334. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/time.py +0 -0
  335. {qubx-3.22.1 → qubx-4.0.0.dev1}/src/qubx/utils/websocket_manager.py +0 -0
  336. {qubx-3.22.1 → qubx-4.0.0.dev1}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
  337. {qubx-3.22.1 → qubx-4.0.0.dev1}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
  338. {qubx-3.22.1 → qubx-4.0.0.dev1}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
  339. {qubx-3.22.1 → qubx-4.0.0.dev1}/tests/strategies/obi_trader/src/obi_trader/models/obi_trader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: Qubx
3
- Version: 3.22.1
3
+ Version: 4.0.0.dev1
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
@@ -34,7 +34,6 @@ Requires-Dist: psycopg<4,>=3.1.18
34
34
  Requires-Dist: pyarrow>=15.0.0
35
35
  Requires-Dist: pydantic-settings<3,>=2.4.0
36
36
  Requires-Dist: pydantic<3,>=2.9.2
37
- Requires-Dist: pymongo<5,>=4.6.1
38
37
  Requires-Dist: python-dotenv<2,>=1.0.0
39
38
  Requires-Dist: pyyaml<7,>=6.0.2
40
39
  Requires-Dist: questdb<3,>=2.0.3
@@ -62,7 +62,6 @@ dependencies = [
62
62
  "statsmodels>=0.14.6,<0.15",
63
63
 
64
64
  # - - - Database backends - - -
65
- "pymongo>=4.6.1,<5",
66
65
  "redis>=5.2.1,<6",
67
66
  "psycopg>=3.1.18,<4",
68
67
  "psycopg-binary>=3.1.19,<4",
@@ -177,7 +176,6 @@ dev = [
177
176
  "pytest-cov>=4.1.0,<5",
178
177
  "pytest-xdist>=3.6.1,<4",
179
178
  "pytest-textual-snapshot>=1.1.0,<2",
180
- "mongomock>=4.3.0,<5",
181
179
  "pyiceberg[pyarrow,sql-sqlite,pyiceberg-core]==0.12.0",
182
180
 
183
181
  # - - - Linting & formatting - - -
@@ -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 = '3.22.1'
22
- __version_tuple__ = version_tuple = (3, 22, 1)
21
+ __version__ = version = '4.0.0.dev1'
22
+ __version_tuple__ = version_tuple = (4, 0, 0, 'dev1')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -259,13 +259,13 @@ def _run_setup(
259
259
  # Adjust the start date for the simulation to the onboard date of the instrument with the minimum onboard date.
260
260
  # TODO: this can be removed once we add some artificial data stream to move the simulation
261
261
  if setup.setup_type in [SetupTypes.SIGNAL, SetupTypes.SIGNAL_AND_TRACKER]:
262
- onboard_dates = [
263
- to_utc_naive(to_timestamp(instrument.onboard_date))
262
+ listed_dates = [
263
+ to_utc_naive(to_timestamp(instrument.listed_at))
264
264
  for instrument in setup.instruments
265
- if instrument.onboard_date is not None
265
+ if instrument.listed_at is not None
266
266
  ]
267
- if onboard_dates:
268
- start = max(start, min(onboard_dates))
267
+ if listed_dates:
268
+ start = max(start, min(listed_dates))
269
269
 
270
270
  runner = SimulationRunner(
271
271
  setup=setup,
@@ -22,7 +22,7 @@ from functools import lru_cache
22
22
  from pathlib import Path
23
23
  from typing import Any, ClassVar
24
24
 
25
- from pydantic import BaseModel
25
+ from pydantic import BaseModel, field_validator
26
26
  from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
27
27
 
28
28
 
@@ -47,8 +47,18 @@ class IcebergAccount(BaseModel):
47
47
  class LookupConfig(BaseModel):
48
48
  """Configuration for instrument/fees lookups."""
49
49
 
50
- type: str = "file"
51
- mongo_url: str | None = None
50
+ type: str = "file" # "file" or "service"
51
+ url: str | None = None # instrument-service base, e.g. http://control-api.platform.svc/internal/instrument-service
52
+ token: str | None = None # bearer token for the gateway route
53
+ exchanges: list[str] | None = None # service: snapshot only these exchanges (env: JSON list or comma-separated)
54
+
55
+ @field_validator("exchanges", mode="before")
56
+ @classmethod
57
+ def _split_exchanges(cls, v: Any) -> Any:
58
+ if isinstance(v, str):
59
+ return [e.strip() for e in v.split(",") if e.strip()]
60
+ return v
61
+
52
62
  reload_interval: str | None = None
53
63
  path: str | None = None
54
64
 
@@ -318,8 +318,7 @@ def ccxt_convert_position(info: dict, ccxt_exchange_name: str, markets: dict[str
318
318
  pos.update_market_price(_pts, info["markPrice"], 1)
319
319
 
320
320
  # Use exchange-provided margins when reported — only the venue knows the configured leverage
321
- # tier. The internal fallback cannot: with no instrument.initial_margin metadata (0.0 on
322
- # BINANCE.UM) it yields 0.0, and with metadata it applies a static ratio that ignores the tier.
321
+ # tier. The internal fallback yields 0.0 initial margin and a flat maintenance rate.
323
322
  if info.get("maintenanceMargin") is not None:
324
323
  pos.set_external_maint_margin(float(info["maintenanceMargin"]))
325
324
 
@@ -1,5 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
 
3
+ from qubx.core.basics import DEFAULT_MAINTENANCE_MARGIN
4
+
3
5
 
4
6
  @dataclass
5
7
  class AccountManagerConfig:
@@ -21,3 +23,5 @@ class AccountManagerConfig:
21
23
 
22
24
  terminal_order_retention_ms: int = 30_000
23
25
  terminal_order_history_size: int = 10_000
26
+
27
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN # - framework-computed maintenance margin (fraction of notional) when the venue reports none
@@ -161,6 +161,7 @@ class AccountManager(IAccountViewer, IAccountConfigurator):
161
161
  exchange=ex,
162
162
  base_currency=base_currencies[ex],
163
163
  terminal_history_size=self._cfg.terminal_order_history_size,
164
+ maint_margin_rate=self._cfg.maint_margin_rate,
164
165
  )
165
166
  for ex in connectors
166
167
  }
@@ -19,7 +19,16 @@ from dataclasses import dataclass
19
19
  import numpy as np
20
20
 
21
21
  from qubx import logger
22
- from qubx.core.basics import STABLE_CURRENCIES, Balance, Deal, Instrument, Order, OrderStatus, Position
22
+ from qubx.core.basics import (
23
+ DEFAULT_MAINTENANCE_MARGIN,
24
+ STABLE_CURRENCIES,
25
+ Balance,
26
+ Deal,
27
+ Instrument,
28
+ Order,
29
+ OrderStatus,
30
+ Position,
31
+ )
23
32
 
24
33
  # Bounded per-exchange funding-bucket dedup (insertion order ≈ funding-event time order):
25
34
  # old buckets evict once the cap is hit so the set can't grow unbounded over long-running
@@ -57,6 +66,7 @@ class AccountState:
57
66
  __slots__ = (
58
67
  "exchange",
59
68
  "base_currency",
69
+ "maint_margin_rate",
60
70
  "_active_orders",
61
71
  "_positions",
62
72
  "_balances",
@@ -77,9 +87,17 @@ class AccountState:
77
87
  "_position_deal_booked_at",
78
88
  )
79
89
 
80
- def __init__(self, exchange: str, base_currency: str, *, terminal_history_size: int = 10_000):
90
+ def __init__(
91
+ self,
92
+ exchange: str,
93
+ base_currency: str,
94
+ *,
95
+ terminal_history_size: int = 10_000,
96
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN,
97
+ ):
81
98
  self.exchange: str = exchange
82
99
  self.base_currency: str = base_currency.upper()
100
+ self.maint_margin_rate: float = maint_margin_rate
83
101
 
84
102
  # ---- primary data ------------------------------------------------
85
103
  self._active_orders: dict[str, Order] = {} # client_order_id -> Order
@@ -471,6 +489,7 @@ class AccountState:
471
489
  # the framework hold references to it), never swapped for a new object.
472
490
  existing = self._positions.get(instrument)
473
491
  if existing is None:
492
+ position.maint_margin_rate = self.maint_margin_rate
474
493
  self._positions[instrument] = position
475
494
  else:
476
495
  existing.reset_by_position(position)
@@ -645,6 +664,7 @@ class AccountState:
645
664
  pos = self._positions.get(instrument)
646
665
  if pos is None:
647
666
  pos = Position(instrument=instrument)
667
+ pos.maint_margin_rate = self.maint_margin_rate
648
668
  self._positions[instrument] = pos
649
669
  return pos
650
670
 
@@ -1,8 +1,8 @@
1
1
  import re
2
- from dataclasses import dataclass, field
2
+ from dataclasses import KW_ONLY, dataclass, field
3
3
  from datetime import datetime
4
4
  from enum import StrEnum
5
- from functools import cache
5
+ from functools import cache, total_ordering
6
6
  from queue import Empty, Queue
7
7
  from threading import Event
8
8
  from typing import Any, Literal, TypeAlias
@@ -347,10 +347,47 @@ def multiplier_coin(base: str) -> str:
347
347
  return base
348
348
 
349
349
 
350
- @dataclass(order=True)
350
+ class AssetKind(StrEnum):
351
+ CRYPTO = "CRYPTO"
352
+ EQUITY = "EQUITY"
353
+ ETF = "ETF"
354
+ INDEX = "INDEX"
355
+ COMMODITY = "COMMODITY"
356
+ FX = "FX"
357
+ EVENT = "EVENT"
358
+
359
+
360
+ @dataclass(frozen=True)
361
+ class Underlying:
362
+ """What a listing is a contract on: (kind, code) is its identity, e.g. (EQUITY, NVDA.XNAS), (CRYPTO, PEPE)."""
363
+
364
+ kind: AssetKind
365
+ code: str
366
+
367
+ def __post_init__(self):
368
+ object.__setattr__(self, "kind", AssetKind(self.kind))
369
+
370
+ def __str__(self) -> str:
371
+ return f"{self.kind}:{self.code}"
372
+
373
+
374
+ class VenueAttributes(dict):
375
+ """Read-only venue labels (Binance contractType, HL dex, ...): filter on them, never branch."""
376
+
377
+ def _readonly(self, *args, **kwargs):
378
+ raise TypeError("venue_attributes is read-only")
379
+
380
+ __setitem__ = __delitem__ = clear = pop = popitem = setdefault = update = __ior__ = _readonly # type: ignore
381
+
382
+ def __reduce__(self):
383
+ return (VenueAttributes, (dict(self),))
384
+
385
+
386
+ @total_ordering
387
+ @dataclass(eq=False)
351
388
  class Instrument:
352
389
  """
353
- Instrument class.
390
+ A tradable listing: identity (eq/hash/str) is (exchange, market_type, symbol).
354
391
 
355
392
  - 2025-06-11: Important change for FUTURE type: now instrument's symbol contains delivery date in format YYYYMMDD.
356
393
  So now for let's say september's BTCUSDT future, symbol would be BTCUSD.20250914
@@ -368,24 +405,28 @@ class Instrument:
368
405
  lot_size: float # minimal position size
369
406
  min_size: float # minimal allowed position size
370
407
  min_notional: float = 0.0 # minimal notional value
371
- initial_margin: float = 0.0 # initial margin
372
- maint_margin: float = 0.0 # maintenance margin
373
- liquidation_fee: float = 0.0 # liquidation fee
374
- contract_size: float = 1.0 # contract size (tokens per contract)
375
- contract_multiplier: float = 1.0 # contract multiplier (additional multiplier, always 1 for crypto)
376
- onboard_date: datetime | None = None # date when instrument was listed on the exchange
377
- delivery_date: datetime | None = None # date when instrument is delivered
378
- delist_date: datetime | None = None # date when instrument is delisted
379
- inverse: bool = False # if true, then the future is inverse
408
+ _: KW_ONLY
409
+ contract_size: float = 1.0 # quantity per contract: base units (linear) or quote units (inverse)
410
+ inverse: bool = False
411
+ listing_id: str | None = None # instrument-service listing id, stable through renames
412
+ underlying: Underlying | None = None
413
+ calendar: str | None = None # when this listing trades: "24/7", a MIC ("XNAS") or None
414
+ expiry: datetime | None = None
415
+ strike: float | None = None
416
+ option_right: str | None = None # CALL / PUT
417
+ listed_at: datetime | None = None
418
+ delisted_at: datetime | None = None # a future value is a scheduled delisting
419
+ margin_tradable: bool = False
420
+ venue_attributes: VenueAttributes = field(default_factory=VenueAttributes)
380
421
 
381
422
  def __post_init__(self):
382
- # define how ordering works
383
- object.__setattr__(self, "sort_index", f"{self.exchange}:{self.market_type}:{self.symbol}")
423
+ if not isinstance(self.venue_attributes, VenueAttributes):
424
+ self.venue_attributes = VenueAttributes(self.venue_attributes or {})
384
425
 
385
426
  @property
386
427
  def quantity_multiplier(self) -> float:
387
- """Combined multiplier: contract_size * contract_multiplier. Multiply contracts by this to get token quantity."""
388
- return self.contract_size * self.contract_multiplier
428
+ """Multiply contracts by this to get token quantity (alias of contract_size)."""
429
+ return self.contract_size
389
430
 
390
431
  @property
391
432
  def price_precision(self):
@@ -401,8 +442,15 @@ class Instrument:
401
442
 
402
443
  @property
403
444
  def asset(self) -> str:
445
+ """The venue coin, multiplier stripped (1000PEPE -> PEPE): a function of the listing alone, so
446
+ connector-built and lookup-built instruments agree. Economic exposure is `exposure_code`."""
404
447
  return multiplier_coin(self.base)
405
448
 
449
+ @property
450
+ def exposure_code(self) -> str:
451
+ """What the listing is a contract on (NVDA.XNAS for a bStock, XAU for PAXG); `asset` when the underlying is unknown."""
452
+ return self.underlying.code if self.underlying is not None else self.asset
453
+
406
454
  def is_futures(self) -> bool:
407
455
  return self.market_type in [MarketType.FUTURE, MarketType.SWAP]
408
456
 
@@ -521,6 +569,11 @@ class Instrument:
521
569
  return False
522
570
  return str(self) == str(other)
523
571
 
572
+ def __lt__(self, other: "Instrument") -> bool:
573
+ if not isinstance(other, Instrument):
574
+ return NotImplemented
575
+ return (self.symbol, self.market_type, self.exchange) < (other.symbol, other.market_type, other.exchange)
576
+
524
577
  def __str__(self) -> str:
525
578
  return ":".join([self.exchange, self.market_type, self.symbol])
526
579
 
@@ -574,11 +627,10 @@ class Instrument:
574
627
  Min Size: {self.min_size}
575
628
  Min Notional: {self.min_notional}
576
629
  Contract Size: {self.contract_size}
577
- Contract Mult: {self.contract_multiplier}
578
- Initial Margin: {self.initial_margin}
579
- Maint. Margin: {self.maint_margin}
580
- Onboard Date: {self.onboard_date}
581
- Delist Date: {self.delist_date}
630
+ Underlying: {self.underlying}
631
+ Calendar: {self.calendar}
632
+ Listed At: {self.listed_at}
633
+ Delisted At: {self.delisted_at}
582
634
  """
583
635
  print(info_str)
584
636
 
@@ -1186,6 +1238,7 @@ class Position:
1186
1238
  _initial_margin_external: bool = False # If True, initial_margin is managed by exchange (skip recalculation)
1187
1239
  maint_margin: float = 0.0
1188
1240
  _maint_margin_external: bool = False # If True, maint_margin is managed by exchange (skip recalculation)
1241
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN # fraction of notional, set from the account config
1189
1242
 
1190
1243
  # ADL queue position from the exchange (None if not reported).
1191
1244
  # Lower values = more likely to be auto-deleveraged.
@@ -1711,8 +1764,9 @@ class Position:
1711
1764
  # Only apply maintenance margin for leveraged instruments (futures/swaps)
1712
1765
  # Spot positions don't have margin requirements since you own the actual asset
1713
1766
  if self.instrument.is_futures():
1714
- maint_margin = self.instrument.maint_margin or DEFAULT_MAINTENANCE_MARGIN
1715
- self.maint_margin = maint_margin * abs(self.quantity) * self._qty_multiplier * self.last_update_price
1767
+ self.maint_margin = (
1768
+ self.maint_margin_rate * abs(self.quantity) * self._qty_multiplier * self.last_update_price
1769
+ )
1716
1770
  else:
1717
1771
  self.maint_margin = 0.0
1718
1772
 
@@ -1727,17 +1781,9 @@ class Position:
1727
1781
  if self._initial_margin_external:
1728
1782
  return
1729
1783
 
1730
- # Only apply initial margin for leveraged instruments (futures/swaps).
1731
- # Use the per-asset initial_margin fraction from instrument metadata when
1732
- # populated; otherwise leave at 0.0 (the framework can't infer a sensible
1733
- # default without the per-instrument leverage setting, which lives on
1734
- # the account processor).
1735
- if self.instrument.is_futures() and self.instrument.initial_margin > 0:
1736
- self.initial_margin = (
1737
- self.instrument.initial_margin * abs(self.quantity) * self._qty_multiplier * self.last_update_price
1738
- )
1739
- else:
1740
- self.initial_margin = 0.0
1784
+ # Without a venue-reported value the framework can't infer one: it depends on the
1785
+ # per-instrument leverage setting, which lives on the account processor.
1786
+ self.initial_margin = 0.0
1741
1787
 
1742
1788
 
1743
1789
  VENUE_SETTINGS_EVENT = "venue_settings"
@@ -2094,24 +2140,24 @@ class InstrumentsLookup:
2094
2140
  i
2095
2141
  for i in self.get_lookup().values()
2096
2142
  if i.exchange == exchange
2097
- and (base is None or i.base == base or multiplier_coin(i.base) == base)
2143
+ and (base is None or i.base == base or i.asset == base)
2098
2144
  and (quote is None or i.quote == quote)
2099
2145
  and (market_type is None or i.market_type == market_type)
2100
2146
  and (
2101
2147
  _limit_time is None
2102
- or (i.onboard_date is None or pd.Timestamp(i.onboard_date).tz_localize(None) <= _limit_time)
2148
+ or (i.listed_at is None or pd.Timestamp(i.listed_at).tz_localize(None) <= _limit_time)
2103
2149
  )
2104
2150
  and (
2105
2151
  _limit_time is None
2106
- or (i.delist_date is None or pd.Timestamp(i.delist_date).tz_localize(None) >= _limit_time)
2152
+ or (i.delisted_at is None or pd.Timestamp(i.delisted_at).tz_localize(None) >= _limit_time)
2107
2153
  )
2108
2154
  ]
2109
2155
  if base is not None:
2110
2156
  aliases = sorted({i.base for i in matched} - {base})
2111
2157
  if aliases and any(i.base == base for i in matched):
2112
2158
  logger.warning(
2113
- f"[lookup] {exchange} base <y>{base}</y> also matches {aliases} through a contract "
2114
- f"multiplier; the exact base is listed first — pass the venue base to disambiguate"
2159
+ f"[lookup] {exchange} <y>{base}</y> is ambiguous: it also names the multiplier contracts "
2160
+ f"{aliases}; exact-base matches come first, pass a venue base (e.g. 1000{base}) to select one"
2115
2161
  )
2116
2162
  matched.sort(key=lambda i: i.base != base)
2117
2163
  return matched
@@ -38,11 +38,11 @@ class DelistingDetector:
38
38
 
39
39
  delisting = []
40
40
  for instrument in instruments:
41
- if instrument.delist_date is None:
41
+ if instrument.delisted_at is None:
42
42
  continue
43
43
 
44
44
  try:
45
- delist_timestamp = to_timestamp(instrument.delist_date).replace(tzinfo=None)
45
+ delist_timestamp = to_timestamp(instrument.delisted_at).replace(tzinfo=None)
46
46
  if bool(pd.isna(delist_timestamp)):
47
47
  continue
48
48
 
@@ -73,7 +73,7 @@ class DelistingDetector:
73
73
 
74
74
  # Log instruments being filtered out
75
75
  for instrument in delisting_instruments:
76
- self._info(f"Filtering out {instrument.symbol} - delisting on {instrument.delist_date}")
76
+ self._info(f"Filtering out {instrument.symbol} - delisting on {instrument.delisted_at}")
77
77
 
78
78
  # Return instruments that are NOT in the delisting set
79
79
  return [instrument for instrument in instruments if instrument not in delisting_set]
@@ -516,11 +516,10 @@ class IAccountViewer:
516
516
  In live this is the venue-reported figure when the venue provides one
517
517
  (e.g. Binance ``availableBalance``); otherwise it derives as
518
518
  ``total_capital - total_initial_margin``. For an accurate derivation,
519
- the connector must populate ``Position.initial_margin`` either via
519
+ the connector must populate ``Position.initial_margin`` via
520
520
  ``set_external_initial_margin(...)`` from venue data (e.g. HPL
521
- ``marginUsed``) or via ``instrument.initial_margin`` in the metadata.
522
- Connectors that populate neither will see this method return the full
523
- capital.
521
+ ``marginUsed``). Connectors that don't will see this method return the
522
+ full capital.
524
523
 
525
524
  Returns:
526
525
  float: Available balance
@@ -2665,7 +2664,7 @@ class IStrategyInitializer:
2665
2664
  """
2666
2665
  Set the number of days ahead to check for delisting.
2667
2666
 
2668
- When an instrument has a delist_date set, this configuration determines how many
2667
+ When an instrument has a delisted_at set, this configuration determines how many
2669
2668
  days before the delisting date the framework should:
2670
2669
  1. Filter the instrument out from universe updates
2671
2670
  2. Close positions and remove the instrument during the daily delisting check