Qubx 4.0.0.dev1__tar.gz → 4.0.1__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 (338) hide show
  1. {qubx-4.0.0.dev1 → qubx-4.0.1}/PKG-INFO +1 -1
  2. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/_version.py +2 -2
  3. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/runner.py +1 -1
  4. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/simulator.py +10 -3
  5. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/utils.py +13 -9
  6. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/state.py +12 -6
  7. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/basics.py +22 -13
  8. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/lookups.py +223 -205
  9. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/multi.py +70 -41
  10. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/questdb.py +47 -10
  11. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/configs.py +1 -0
  12. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/runner.py +10 -0
  13. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/time.py +3 -3
  14. {qubx-4.0.0.dev1 → qubx-4.0.1}/.gitignore +0 -0
  15. {qubx-4.0.0.dev1 → qubx-4.0.1}/LICENSE +0 -0
  16. {qubx-4.0.0.dev1 → qubx-4.0.1}/README.md +0 -0
  17. {qubx-4.0.0.dev1 → qubx-4.0.1}/pyproject.toml +0 -0
  18. {qubx-4.0.0.dev1 → qubx-4.0.1}/scripts/build.py +0 -0
  19. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/__init__.py +0 -0
  20. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/_nb_magic.py +0 -0
  21. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/__init__.py +0 -0
  22. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/connector.py +0 -0
  23. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/data.py +0 -0
  24. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/iteratedstream.py +0 -0
  25. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/management.py +0 -0
  26. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/ome.py +0 -0
  27. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/optimization.py +0 -0
  28. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/sentinels.py +0 -0
  29. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/simulated_data.py +0 -0
  30. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/simulated_exchange.py +0 -0
  31. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/backtester/transfers.py +0 -0
  32. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/__init__.py +0 -0
  33. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/commands.py +0 -0
  34. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/deploy.py +0 -0
  35. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/misc.py +0 -0
  36. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/release.py +0 -0
  37. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/resolver.py +0 -0
  38. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/s3.py +0 -0
  39. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/theme.py +0 -0
  40. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/tui.py +0 -0
  41. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/cli/user_config.py +0 -0
  42. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/config.py +0 -0
  43. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/__init__.py +0 -0
  44. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/__init__.py +0 -0
  45. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  46. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  47. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
  48. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/connector.py +0 -0
  49. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/data.py +0 -0
  50. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  51. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  52. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  53. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/_two_stream.py +0 -0
  54. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  55. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/binance/connector.py +0 -0
  56. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  57. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  58. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/bitfinex/connector.py +0 -0
  59. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/bybit/__init__.py +0 -0
  60. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/bybit/bybit.py +0 -0
  61. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/bybit/connector.py +0 -0
  62. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
  63. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
  64. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  65. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  66. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  67. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/okx/__init__.py +0 -0
  68. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/okx/connector.py +0 -0
  69. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/exchanges/okx/okx.py +0 -0
  70. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/factory.py +0 -0
  71. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  72. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  73. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  74. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  75. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  76. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
  77. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  78. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  79. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  80. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  81. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/plugin.py +0 -0
  82. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/rate_limits.py +0 -0
  83. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  84. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  85. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  86. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/utils.py +0 -0
  87. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  88. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/plugin.py +0 -0
  89. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/registry.py +0 -0
  90. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/tardis/data.py +0 -0
  91. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/tardis/plugin.py +0 -0
  92. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/connectors/tardis/utils.py +0 -0
  93. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/__init__.py +0 -0
  94. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/builtin.py +0 -0
  95. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/decorator.py +0 -0
  96. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/executor.py +0 -0
  97. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/interfaces.py +0 -0
  98. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/server.py +0 -0
  99. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/control/types.py +0 -0
  100. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/__init__.py +0 -0
  101. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/__init__.py +0 -0
  102. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/config.py +0 -0
  103. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/diffs.py +0 -0
  104. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/manager.py +0 -0
  105. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/reconciler.py +0 -0
  106. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/reducer.py +0 -0
  107. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/account_manager/state_machine.py +0 -0
  108. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/boot.py +0 -0
  109. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/connector.py +0 -0
  110. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/context.py +0 -0
  111. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/detectors/__init__.py +0 -0
  112. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/detectors/delisting.py +0 -0
  113. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/detectors/stale.py +0 -0
  114. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/errors.py +0 -0
  115. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/events.py +0 -0
  116. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/exceptions.py +0 -0
  117. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/fit_context.py +0 -0
  118. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/fit_executor.py +0 -0
  119. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/helpers.py +0 -0
  120. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/initializer.py +0 -0
  121. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/instrument_service.py +0 -0
  122. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/interfaces.py +0 -0
  123. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/loggers.py +0 -0
  124. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/metrics.py +0 -0
  125. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/__init__.py +0 -0
  126. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/instrument_service.py +0 -0
  127. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/market.py +0 -0
  128. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/processing.py +0 -0
  129. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/subscription.py +0 -0
  130. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/trading.py +0 -0
  131. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/universe.py +0 -0
  132. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/mixins/utils.py +0 -0
  133. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/series.pxd +0 -0
  134. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/series.pyi +0 -0
  135. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/series.pyx +0 -0
  136. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/state_snapshot.py +0 -0
  137. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/status.py +0 -0
  138. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/subscription_watchdog.py +0 -0
  139. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/utils.pyi +0 -0
  140. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/core/utils.pyx +0 -0
  141. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/__init__.py +0 -0
  142. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/cache.py +0 -0
  143. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/containers.py +0 -0
  144. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/guards.py +0 -0
  145. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/registry.py +0 -0
  146. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storage.py +0 -0
  147. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/_missing_extra.py +0 -0
  148. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/ccxt.py +0 -0
  149. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/csv.py +0 -0
  150. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/dukascopy.py +0 -0
  151. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/handy.py +0 -0
  152. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/iceberg.py +0 -0
  153. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/stub.py +0 -0
  154. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/utils.py +0 -0
  155. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/storages/yahoo.py +0 -0
  156. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/data/transformers.py +0 -0
  157. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/__init__.py +0 -0
  158. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/base.py +0 -0
  159. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/composite.py +0 -0
  160. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/csv.py +0 -0
  161. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/indicator.py +0 -0
  162. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/inmemory.py +0 -0
  163. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/prometheus.py +0 -0
  164. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/emitters/questdb.py +0 -0
  165. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/__init__.py +0 -0
  166. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/composite.py +0 -0
  167. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/formatters/__init__.py +0 -0
  168. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/formatters/base.py +0 -0
  169. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/formatters/incremental.py +0 -0
  170. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/formatters/slack.py +0 -0
  171. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/formatters/target_position.py +0 -0
  172. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/redis_streams.py +0 -0
  173. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/exporters/slack.py +0 -0
  174. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/gathering/simplest.py +0 -0
  175. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/health/__init__.py +0 -0
  176. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/health/base.py +0 -0
  177. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/health/dummy.py +0 -0
  178. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/health/status.py +0 -0
  179. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/loggers/__init__.py +0 -0
  180. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/loggers/csv.py +0 -0
  181. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/loggers/factory.py +0 -0
  182. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/loggers/inmemory.py +0 -0
  183. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/loggers/postgres.py +0 -0
  184. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/notifications/__init__.py +0 -0
  185. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/notifications/composite.py +0 -0
  186. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/notifications/slack.py +0 -0
  187. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/notifications/throttler.py +0 -0
  188. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/pandaz/__init__.py +0 -0
  189. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/pandaz/stats.py +0 -0
  190. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/pandaz/ta.py +0 -0
  191. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/pandaz/utils.py +0 -0
  192. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/plugins/__init__.py +0 -0
  193. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/plugins/loader.py +0 -0
  194. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/__init__.py +0 -0
  195. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/backend.py +0 -0
  196. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/config.py +0 -0
  197. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/engine.py +0 -0
  198. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/ip_resolver.py +0 -0
  199. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/manager.py +0 -0
  200. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/pools.py +0 -0
  201. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/redis_backend.py +0 -0
  202. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/rate_limiting/resilient.py +0 -0
  203. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/_build.py +0 -0
  204. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/crypto-fees.ini +0 -0
  205. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  206. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  207. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  208. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  209. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  210. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  211. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  212. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  213. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  214. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  215. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  216. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restarts/__init__.py +0 -0
  217. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restarts/state_resolvers.py +0 -0
  218. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restarts/time_finders.py +0 -0
  219. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/__init__.py +0 -0
  220. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/balance.py +0 -0
  221. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/factory.py +0 -0
  222. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/interfaces.py +0 -0
  223. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/position.py +0 -0
  224. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/signal.py +0 -0
  225. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/state.py +0 -0
  226. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/restorers/utils.py +0 -0
  227. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/state/__init__.py +0 -0
  228. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/state/dummy.py +0 -0
  229. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/state/redis.py +0 -0
  230. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/state/runtime_info.py +0 -0
  231. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/state/safe.py +0 -0
  232. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/ta/__init__.py +0 -0
  233. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/ta/indicators.pxd +0 -0
  234. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/ta/indicators.pyi +0 -0
  235. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/ta/indicators.pyx +0 -0
  236. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/__init__.py +0 -0
  237. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/base.py +0 -0
  238. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  239. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/config.yml.j2 +0 -0
  240. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  241. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  242. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  243. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  244. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  245. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/project/template.yml +0 -0
  246. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.claude/skills/qubx-cli/SKILL.md +0 -0
  247. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.claude/skills/qubx-indicators/SKILL.md +0 -0
  248. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.claude/skills/simulation-explorer/SKILL.md +0 -0
  249. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.claude/skills/strategy-release/SKILL.md +0 -0
  250. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.github/workflows/ci.yml.j2 +0 -0
  251. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.gitignore.j2 +0 -0
  252. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.python-version +0 -0
  253. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.vscode/launch.json +0 -0
  254. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.vscode/settings.json +0 -0
  255. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/.vscode/tasks.json +0 -0
  256. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/CLAUDE.md.j2 +0 -0
  257. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/README.md.j2 +0 -0
  258. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/configs/.gitkeep +0 -0
  259. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/justfile.j2 +0 -0
  260. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/pyproject.toml.j2 +0 -0
  261. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/research/.gitkeep +0 -0
  262. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  263. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/src/{{ strategy_name }}/cli.py.j2 +0 -0
  264. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  265. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/template.yml +0 -0
  266. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/repo/tests/test_strategy.py.j2 +0 -0
  267. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  268. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  269. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/config.yml.j2 +0 -0
  270. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  271. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  272. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  273. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/templates/simple/template.yml +0 -0
  274. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/__init__.py +0 -0
  275. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/advanced.py +0 -0
  276. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/composite.py +0 -0
  277. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/rebalancers.py +0 -0
  278. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/riskctrl.py +0 -0
  279. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/trackers/sizers.py +0 -0
  280. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/__init__.py +0 -0
  281. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/_pyxreloader.py +0 -0
  282. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/charting/lookinglass.py +0 -0
  283. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  284. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/charting/orderbook.py +0 -0
  285. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/clock.py +0 -0
  286. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/collections.py +0 -0
  287. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/hft/__init__.py +0 -0
  288. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/hft/numba_utils.py +0 -0
  289. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/hft/orderbook.pyi +0 -0
  290. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/hft/orderbook.pyx +0 -0
  291. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/marketdata/binance.py +0 -0
  292. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/marketdata/ccxt.py +0 -0
  293. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/marketdata/dukas.py +0 -0
  294. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/misc.py +0 -0
  295. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/nonce.py +0 -0
  296. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/numbers_utils.py +0 -0
  297. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/orderbook.py +0 -0
  298. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/__init__.py +0 -0
  299. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/dashboard.py +0 -0
  300. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/data.py +0 -0
  301. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/interfaces.py +0 -0
  302. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  303. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  304. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/questdb.py +0 -0
  305. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/rate_limiter.py +0 -0
  306. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/results.py +0 -0
  307. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/ringbuffer.pxd +0 -0
  308. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/ringbuffer.pyi +0 -0
  309. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/ringbuffer.pyx +0 -0
  310. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/__init__.py +0 -0
  311. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  312. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/accounts.py +0 -0
  313. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/factory.py +0 -0
  314. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/kernel_service.py +0 -0
  315. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/__init__.py +0 -0
  316. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/app.py +0 -0
  317. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/handlers.py +0 -0
  318. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/init_code.py +0 -0
  319. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/kernel.py +0 -0
  320. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/styles.tcss +0 -0
  321. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
  322. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/account_summary.py +0 -0
  323. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
  324. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
  325. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/log_filter.py +0 -0
  326. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
  327. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
  328. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
  329. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
  330. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/s3.py +0 -0
  331. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/slack.py +0 -0
  332. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/threading.py +0 -0
  333. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/throttler.py +0 -0
  334. {qubx-4.0.0.dev1 → qubx-4.0.1}/src/qubx/utils/websocket_manager.py +0 -0
  335. {qubx-4.0.0.dev1 → qubx-4.0.1}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
  336. {qubx-4.0.0.dev1 → qubx-4.0.1}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
  337. {qubx-4.0.0.dev1 → qubx-4.0.1}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
  338. {qubx-4.0.0.dev1 → qubx-4.0.1}/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: 4.0.0.dev1
3
+ Version: 4.0.1
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 = '4.0.0.dev1'
22
- __version_tuple__ = version_tuple = (4, 0, 0, 'dev1')
21
+ __version__ = version = '4.0.1'
22
+ __version_tuple__ = version_tuple = (4, 0, 1)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -612,7 +612,7 @@ class SimulationRunner:
612
612
  connectors=self._connectors,
613
613
  base_currencies=self.setup.base_currencies,
614
614
  time=time_provider,
615
- cfg=AccountManagerConfig(),
615
+ cfg=AccountManagerConfig(maint_margin_rate=self.setup.maint_margin_rate),
616
616
  account_id=self.account_id,
617
617
  tcc=_exchange_to_tcc,
618
618
  )
@@ -5,8 +5,9 @@ from joblib import delayed
5
5
 
6
6
  from qubx import QubxLogConfig, file_formatter, logger
7
7
  from qubx.backtester.utils import SetupTypes
8
- from qubx.core.basics import Instrument
8
+ from qubx.core.basics import DEFAULT_MAINTENANCE_MARGIN, Instrument
9
9
  from qubx.core.exceptions import SimulationError
10
+ from qubx.core.lookups import lookup
10
11
  from qubx.core.metrics import TradingSessionResult
11
12
  from qubx.data.storage import IStorage
12
13
  from qubx.emitters.inmemory import InMemoryMetricEmitter
@@ -45,6 +46,7 @@ def simulate(
45
46
  accurate_stop_orders_execution: bool = False,
46
47
  signal_timeframe: str = "1Min",
47
48
  enable_funding: bool = False,
49
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN,
48
50
  debug: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = "WARNING",
49
51
  show_latency_report: bool = False,
50
52
  portfolio_log_freq: str = "5Min",
@@ -76,6 +78,7 @@ def simulate(
76
78
  - accurate_stop_orders_execution (bool): If True, enables more accurate stop order execution simulation.
77
79
  - signal_timeframe (str): Timeframe for signals, default is "1Min".
78
80
  - enable_funding (bool): If True, enables funding rate simulation, default is False.
81
+ - maint_margin_rate (float): Maintenance margin as a fraction of notional for simulated positions (the account's `maint_margin_rate`).
79
82
  - debug (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None): Logging level for debugging.
80
83
  - show_latency_report: If True, shows simulator's latency report.
81
84
  - portfolio_log_freq (str): Frequency for portfolio logging, default is "5Min".
@@ -125,6 +128,7 @@ def simulate(
125
128
  accurate_stop_orders_execution=accurate_stop_orders_execution,
126
129
  run_separate_instruments=run_separate_instruments,
127
130
  enable_funding=enable_funding,
131
+ maint_margin_rate=maint_margin_rate,
128
132
  )
129
133
  if not simulation_setups:
130
134
  logger.error(
@@ -259,10 +263,13 @@ def _run_setup(
259
263
  # Adjust the start date for the simulation to the onboard date of the instrument with the minimum onboard date.
260
264
  # TODO: this can be removed once we add some artificial data stream to move the simulation
261
265
  if setup.setup_type in [SetupTypes.SIGNAL, SetupTypes.SIGNAL_AND_TRACKER]:
266
+ # - a relisted symbol has data from its first listing on
262
267
  listed_dates = [
263
- to_utc_naive(to_timestamp(instrument.listed_at))
268
+ to_utc_naive(to_timestamp(listing.listed_at))
264
269
  for instrument in setup.instruments
265
- if instrument.listed_at is not None
270
+ for listing in lookup.find_listings(instrument.exchange, instrument.symbol, instrument.market_type)
271
+ or [instrument]
272
+ if listing.listed_at is not None
266
273
  ]
267
274
  if listed_dates:
268
275
  start = max(start, min(listed_dates))
@@ -8,6 +8,7 @@ import pandas as pd
8
8
 
9
9
  from qubx import logger
10
10
  from qubx.core.basics import (
11
+ DEFAULT_MAINTENANCE_MARGIN,
11
12
  STABLE_CURRENCIES,
12
13
  Balance,
13
14
  CtrlChannel,
@@ -114,6 +115,7 @@ class SimulationSetup:
114
115
  signal_timeframe: str = "1Min"
115
116
  accurate_stop_orders_execution: bool = False
116
117
  enable_funding: bool = False
118
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN
117
119
  base_currencies: dict[str, str] = field(init=False, default_factory=dict)
118
120
 
119
121
  def __post_init__(self) -> None:
@@ -405,6 +407,7 @@ def recognize_simulation_configuration(
405
407
  accurate_stop_orders_execution: bool,
406
408
  run_separate_instruments: bool = False,
407
409
  enable_funding: bool = False,
410
+ maint_margin_rate: float = DEFAULT_MAINTENANCE_MARGIN,
408
411
  ) -> list[SimulationSetup]:
409
412
  """
410
413
  Recognize and create setups based on the provided simulation configuration.
@@ -426,6 +429,7 @@ def recognize_simulation_configuration(
426
429
  - accurate_stop_orders_execution (bool): If True, enables more accurate stop order execution simulation.
427
430
  - run_separate_instruments (bool): If True, creates separate setups for each instrument.
428
431
  - enable_funding (bool): If True, enables funding rate simulation, default is False.
432
+ - maint_margin_rate (float): Maintenance margin as a fraction of notional for simulated positions.
429
433
 
430
434
  Returns:
431
435
  - list[SimulationSetup]: A list of SimulationSetup objects, each representing a
@@ -447,7 +451,7 @@ def recognize_simulation_configuration(
447
451
  recognize_simulation_configuration(
448
452
  _n + n, v, instruments, exchanges, capital, basic_currency, commissions,
449
453
  signal_timeframe, accurate_stop_orders_execution, run_separate_instruments,
450
- enable_funding
454
+ enable_funding, maint_margin_rate
451
455
  )
452
456
  )
453
457
 
@@ -468,14 +472,14 @@ def recognize_simulation_configuration(
468
472
  if run_separate_instruments:
469
473
  # Create separate setups for each instrument
470
474
  for instrument in setup_instruments:
471
- _s1 = c1[instrument.symbol] if isinstance(_s, pd.DataFrame) else _s
475
+ _s1 = _s[instrument.symbol] if isinstance(_s, pd.DataFrame) else _s
472
476
  r.append(
473
477
  SimulationSetup(
474
478
  _t, f"{name}/{instrument.symbol}", _s1, c1, # type: ignore
475
479
  [instrument],
476
480
  exchanges, capital, basic_currency, commissions,
477
481
  signal_timeframe, accurate_stop_orders_execution,
478
- enable_funding
482
+ enable_funding, maint_margin_rate
479
483
  )
480
484
  )
481
485
  else:
@@ -485,7 +489,7 @@ def recognize_simulation_configuration(
485
489
  setup_instruments,
486
490
  exchanges, capital, basic_currency, commissions,
487
491
  signal_timeframe, accurate_stop_orders_execution,
488
- enable_funding
492
+ enable_funding, maint_margin_rate
489
493
  )
490
494
  )
491
495
  else:
@@ -495,7 +499,7 @@ def recognize_simulation_configuration(
495
499
  # name + "/" + str(j), s, instruments, exchange, capital, basic_currency, commissions
496
500
  name, s, instruments, exchanges, capital, basic_currency, commissions, # type: ignore
497
501
  signal_timeframe, accurate_stop_orders_execution, run_separate_instruments,
498
- enable_funding
502
+ enable_funding, maint_margin_rate
499
503
  )
500
504
  )
501
505
 
@@ -509,7 +513,7 @@ def recognize_simulation_configuration(
509
513
  f"{name}/{instrument.symbol}", configs, None, [instrument],
510
514
  exchanges, capital, basic_currency, commissions,
511
515
  signal_timeframe, accurate_stop_orders_execution,
512
- enable_funding
516
+ enable_funding, maint_margin_rate
513
517
  )
514
518
  )
515
519
  else:
@@ -519,7 +523,7 @@ def recognize_simulation_configuration(
519
523
  name, configs, None, instruments,
520
524
  exchanges, capital, basic_currency, commissions,
521
525
  signal_timeframe, accurate_stop_orders_execution,
522
- enable_funding
526
+ enable_funding, maint_margin_rate
523
527
  )
524
528
  )
525
529
 
@@ -538,7 +542,7 @@ def recognize_simulation_configuration(
538
542
  f"{name}/{instrument.symbol}", _c1, None, [instrument],
539
543
  exchanges, capital, basic_currency, commissions,
540
544
  signal_timeframe, accurate_stop_orders_execution,
541
- enable_funding
545
+ enable_funding, maint_margin_rate
542
546
  )
543
547
  )
544
548
  else:
@@ -548,7 +552,7 @@ def recognize_simulation_configuration(
548
552
  name, c1, None, setup_instruments,
549
553
  exchanges, capital, basic_currency, commissions,
550
554
  signal_timeframe, accurate_stop_orders_execution,
551
- enable_funding
555
+ enable_funding, maint_margin_rate
552
556
  )
553
557
  )
554
558
 
@@ -489,11 +489,19 @@ class AccountState:
489
489
  # the framework hold references to it), never swapped for a new object.
490
490
  existing = self._positions.get(instrument)
491
491
  if existing is None:
492
- position.maint_margin_rate = self.maint_margin_rate
493
- self._positions[instrument] = position
492
+ self._adopt_position(instrument, position)
494
493
  else:
495
494
  existing.reset_by_position(position)
496
495
 
496
+ def _adopt_position(self, instrument: Instrument, position: Position) -> Position:
497
+ # - every held position margins at the account's rate, however it got here; a venue-reported
498
+ # margin is kept, a framework one is recomputed now rather than on the next mark
499
+ position.maint_margin_rate = self.maint_margin_rate
500
+ if not position._maint_margin_external and position.is_open() and not np.isnan(position.last_update_price):
501
+ position._update_maint_margin()
502
+ self._positions[instrument] = position
503
+ return position
504
+
497
505
  def settle_position(self, instrument: Instrument) -> None:
498
506
  # Reconcile a delisted/gone position to flat WITHOUT trading: the exchange has
499
507
  # already cash-settled it, so we zero quantity/market value while preserving the
@@ -525,7 +533,7 @@ class AccountState:
525
533
  """
526
534
  existing = self._positions.get(snapshot.instrument)
527
535
  if existing is None:
528
- self._positions[snapshot.instrument] = snapshot
536
+ self._adopt_position(snapshot.instrument, snapshot)
529
537
  logger.info(
530
538
  f"[{self.exchange}] reconcile: materialized position <y>{snapshot.instrument}</y> from snapshot "
531
539
  f"-> size=<g>{snapshot.quantity}</g> avg={snapshot.position_avg_price}"
@@ -663,9 +671,7 @@ class AccountState:
663
671
  def ensure_position(self, instrument: Instrument) -> Position:
664
672
  pos = self._positions.get(instrument)
665
673
  if pos is None:
666
- pos = Position(instrument=instrument)
667
- pos.maint_margin_rate = self.maint_margin_rate
668
- self._positions[instrument] = pos
674
+ pos = self._adopt_position(instrument, Position(instrument=instrument))
669
675
  return pos
670
676
 
671
677
  def adjust_balance(self, currency: str, delta: float) -> None:
@@ -23,7 +23,7 @@ from qubx.core.utils import (
23
23
  )
24
24
  from qubx.utils.clock import start_clock_discipline, time_now
25
25
  from qubx.utils.misc import Stopwatch
26
- from qubx.utils.time import to_timedelta
26
+ from qubx.utils.time import to_timedelta, to_utc_naive
27
27
 
28
28
  dt_64 = np.datetime64
29
29
  td_64 = np.timedelta64
@@ -408,7 +408,7 @@ class Instrument:
408
408
  _: KW_ONLY
409
409
  contract_size: float = 1.0 # quantity per contract: base units (linear) or quote units (inverse)
410
410
  inverse: bool = False
411
- listing_id: str | None = None # instrument-service listing id, stable through renames
411
+ listing_id: str | None = None # instrument-service listing id; a new symbol is a new listing
412
412
  underlying: Underlying | None = None
413
413
  calendar: str | None = None # when this listing trades: "24/7", a MIC ("XNAS") or None
414
414
  expiry: datetime | None = None
@@ -451,6 +451,13 @@ class Instrument:
451
451
  """What the listing is a contract on (NVDA.XNAS for a bStock, XAU for PAXG); `asset` when the underlying is unknown."""
452
452
  return self.underlying.code if self.underlying is not None else self.asset
453
453
 
454
+ def is_listed_at(self, time: datetime | str) -> bool:
455
+ """listed_at <= time < delisted_at, an unknown date leaving that side open."""
456
+ t = to_utc_naive(time)
457
+ return (self.listed_at is None or to_utc_naive(self.listed_at) <= t) and (
458
+ self.delisted_at is None or t < to_utc_naive(self.delisted_at)
459
+ )
460
+
454
461
  def is_futures(self) -> bool:
455
462
  return self.market_type in [MarketType.FUTURE, MarketType.SWAP]
456
463
 
@@ -2080,6 +2087,10 @@ class RestoredState:
2080
2087
  class InstrumentsLookup:
2081
2088
  def get_lookup(self) -> dict[str, Instrument]: ...
2082
2089
 
2090
+ def get_listings(self) -> list[Instrument]:
2091
+ """Every listing, including the earlier, delisted incarnations of relisted symbols that get_lookup() drops."""
2092
+ return list(self.get_lookup().values())
2093
+
2083
2094
  def find(
2084
2095
  self,
2085
2096
  exchange: str,
@@ -2118,6 +2129,10 @@ class InstrumentsLookup:
2118
2129
 
2119
2130
  return None
2120
2131
 
2132
+ def find_listings(self, exchange: str, symbol: str, market_type: MarketType | None = None) -> list[Instrument]:
2133
+ """Every listing a symbol has had, the current (find_symbol) one first."""
2134
+ return [i for i in [self.find_symbol(exchange, symbol, market_type)] if i is not None]
2135
+
2121
2136
  def find_instruments(
2122
2137
  self,
2123
2138
  exchange: str,
@@ -2128,29 +2143,23 @@ class InstrumentsLookup:
2128
2143
  ) -> list[Instrument]:
2129
2144
  """
2130
2145
  Find instruments by exchange, quote, market type and as of date.
2131
- If as_of is not None, then only instruments that are not delisted after as_of date will be returned.
2146
+ If as_of is not None, only instruments listed at that time are returned, delisted predecessors
2147
+ of relisted symbols included (see get_listings).
2132
2148
  - exchange: str - exchange name
2133
2149
  - base: str | None - base currency
2134
2150
  - quote: str | None - quote currency
2135
2151
  - market_type: MarketType | None - market type
2136
2152
  - as_of is a string in format YYYY-MM-DD or pd.Timestamp or None
2137
2153
  """
2138
- _limit_time = pd.Timestamp(as_of) if as_of else None
2154
+ _limit_time = to_utc_naive(as_of) if as_of else None
2139
2155
  matched = [
2140
2156
  i
2141
- for i in self.get_lookup().values()
2157
+ for i in (self.get_lookup().values() if _limit_time is None else self.get_listings())
2142
2158
  if i.exchange == exchange
2143
2159
  and (base is None or i.base == base or i.asset == base)
2144
2160
  and (quote is None or i.quote == quote)
2145
2161
  and (market_type is None or i.market_type == market_type)
2146
- and (
2147
- _limit_time is None
2148
- or (i.listed_at is None or pd.Timestamp(i.listed_at).tz_localize(None) <= _limit_time)
2149
- )
2150
- and (
2151
- _limit_time is None
2152
- or (i.delisted_at is None or pd.Timestamp(i.delisted_at).tz_localize(None) >= _limit_time)
2153
- )
2162
+ and (_limit_time is None or i.is_listed_at(_limit_time))
2154
2163
  ]
2155
2164
  if base is not None:
2156
2165
  aliases = sorted({i.base for i in matched} - {base})