Qubx 1.0.0.dev4__tar.gz → 1.0.0.dev5__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 (263) hide show
  1. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/PKG-INFO +1 -1
  2. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/pyproject.toml +1 -1
  3. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/_version.py +2 -2
  4. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/connection_manager.py +7 -1
  5. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/ohlc.py +3 -0
  6. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/basics.py +5 -0
  7. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/interfaces.py +2 -1
  8. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/lookups.py +38 -1
  9. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/processing.py +2 -0
  10. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/composite.py +11 -9
  11. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/formatters/base.py +4 -2
  12. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/formatters/incremental.py +2 -1
  13. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/formatters/slack.py +5 -1
  14. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/redis_streams.py +3 -2
  15. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/slack.py +4 -3
  16. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/factory.py +4 -7
  17. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/runner.py +3 -1
  18. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/.gitignore +0 -0
  19. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/LICENSE +0 -0
  20. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/README.md +0 -0
  21. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/hatch_build.py +0 -0
  22. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/__init__.py +0 -0
  23. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/_nb_magic.py +0 -0
  24. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/__init__.py +0 -0
  25. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/account.py +0 -0
  26. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/broker.py +0 -0
  27. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/data.py +0 -0
  28. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/iteratedstream.py +0 -0
  29. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/management.py +0 -0
  30. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/ome.py +0 -0
  31. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/optimization.py +0 -0
  32. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/runner.py +0 -0
  33. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/sentinels.py +0 -0
  34. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/simulated_data.py +0 -0
  35. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/simulated_exchange.py +0 -0
  36. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/simulator.py +0 -0
  37. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/transfers.py +0 -0
  38. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/backtester/utils.py +0 -0
  39. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/__init__.py +0 -0
  40. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/commands.py +0 -0
  41. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/deploy.py +0 -0
  42. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/misc.py +0 -0
  43. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/release.py +0 -0
  44. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/theme.py +0 -0
  45. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/cli/tui.py +0 -0
  46. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/config.py +0 -0
  47. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/__init__.py +0 -0
  48. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/__init__.py +0 -0
  49. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/account.py +0 -0
  50. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  51. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  52. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/broker.py +0 -0
  53. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/data.py +0 -0
  54. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  55. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  56. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  57. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  58. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  59. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  60. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  61. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  62. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
  63. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
  64. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  65. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py +0 -0
  66. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +0 -0
  67. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  68. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  69. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/factory.py +0 -0
  70. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  71. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  72. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  73. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  74. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  75. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  76. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  77. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  78. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  79. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  80. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  81. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  82. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/utils.py +0 -0
  83. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  84. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/registry.py +0 -0
  85. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/tardis/data.py +0 -0
  86. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/connectors/tardis/utils.py +0 -0
  87. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/__init__.py +0 -0
  88. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/account.py +0 -0
  89. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/context.py +0 -0
  90. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/detectors/__init__.py +0 -0
  91. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/detectors/delisting.py +0 -0
  92. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/detectors/stale.py +0 -0
  93. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/errors.py +0 -0
  94. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/exceptions.py +0 -0
  95. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/helpers.py +0 -0
  96. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/initializer.py +0 -0
  97. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/loggers.py +0 -0
  98. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/metrics.py +0 -0
  99. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/__init__.py +0 -0
  100. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/market.py +0 -0
  101. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/subscription.py +0 -0
  102. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/trading.py +0 -0
  103. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/universe.py +0 -0
  104. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/mixins/utils.py +0 -0
  105. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/series.pxd +0 -0
  106. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/series.pyi +0 -0
  107. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/series.pyx +0 -0
  108. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/utils.pyi +0 -0
  109. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/core/utils.pyx +0 -0
  110. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/__init__.py +0 -0
  111. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/cache.py +0 -0
  112. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/containers.py +0 -0
  113. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/guards.py +0 -0
  114. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/registry.py +0 -0
  115. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storage.py +0 -0
  116. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/ccxt.py +0 -0
  117. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/csv.py +0 -0
  118. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/handy.py +0 -0
  119. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/multi.py +0 -0
  120. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/questdb.py +0 -0
  121. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/stub.py +0 -0
  122. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/storages/utils.py +0 -0
  123. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/data/transformers.py +0 -0
  124. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/__init__.py +0 -0
  125. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/base.py +0 -0
  126. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/composite.py +0 -0
  127. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/csv.py +0 -0
  128. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/indicator.py +0 -0
  129. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/inmemory.py +0 -0
  130. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/prometheus.py +0 -0
  131. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/emitters/questdb.py +0 -0
  132. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/__init__.py +0 -0
  133. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/formatters/__init__.py +0 -0
  134. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/exporters/formatters/target_position.py +0 -0
  135. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/gathering/simplest.py +0 -0
  136. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/health/__init__.py +0 -0
  137. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/health/base.py +0 -0
  138. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/health/dummy.py +0 -0
  139. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/loggers/__init__.py +0 -0
  140. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/loggers/csv.py +0 -0
  141. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/loggers/factory.py +0 -0
  142. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/loggers/inmemory.py +0 -0
  143. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/loggers/mongo.py +0 -0
  144. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/notifications/__init__.py +0 -0
  145. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/notifications/composite.py +0 -0
  146. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/notifications/slack.py +0 -0
  147. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/notifications/throttler.py +0 -0
  148. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/pandaz/__init__.py +0 -0
  149. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/pandaz/stats.py +0 -0
  150. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/pandaz/ta.py +0 -0
  151. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/pandaz/utils.py +0 -0
  152. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/plugins/__init__.py +0 -0
  153. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/plugins/loader.py +0 -0
  154. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/_build.py +0 -0
  155. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/crypto-fees.ini +0 -0
  156. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  157. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  158. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  159. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  160. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  161. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  162. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  163. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  164. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  165. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  166. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  167. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restarts/__init__.py +0 -0
  168. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restarts/state_resolvers.py +0 -0
  169. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restarts/time_finders.py +0 -0
  170. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/__init__.py +0 -0
  171. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/balance.py +0 -0
  172. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/factory.py +0 -0
  173. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/interfaces.py +0 -0
  174. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/position.py +0 -0
  175. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/signal.py +0 -0
  176. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/state.py +0 -0
  177. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/restorers/utils.py +0 -0
  178. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/state/__init__.py +0 -0
  179. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/state/dummy.py +0 -0
  180. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/state/redis.py +0 -0
  181. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/ta/__init__.py +0 -0
  182. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/ta/indicators.pxd +0 -0
  183. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/ta/indicators.pyi +0 -0
  184. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/ta/indicators.pyx +0 -0
  185. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/__init__.py +0 -0
  186. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/base.py +0 -0
  187. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  188. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/config.yml.j2 +0 -0
  189. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  190. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  191. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  192. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  193. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  194. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/project/template.yml +0 -0
  195. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  196. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  197. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/config.yml.j2 +0 -0
  198. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  199. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  200. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  201. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/templates/simple/template.yml +0 -0
  202. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/__init__.py +0 -0
  203. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/advanced.py +0 -0
  204. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/composite.py +0 -0
  205. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/rebalancers.py +0 -0
  206. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/riskctrl.py +0 -0
  207. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/trackers/sizers.py +0 -0
  208. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/__init__.py +0 -0
  209. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/_pyxreloader.py +0 -0
  210. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/charting/lookinglass.py +0 -0
  211. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  212. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/charting/orderbook.py +0 -0
  213. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/collections.py +0 -0
  214. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/hft/__init__.py +0 -0
  215. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/hft/numba_utils.py +0 -0
  216. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/hft/orderbook.pyi +0 -0
  217. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/hft/orderbook.pyx +0 -0
  218. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/marketdata/binance.py +0 -0
  219. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/marketdata/ccxt.py +0 -0
  220. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/marketdata/dukas.py +0 -0
  221. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/misc.py +0 -0
  222. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/nonce.py +0 -0
  223. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/ntp.py +0 -0
  224. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/numbers_utils.py +0 -0
  225. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/orderbook.py +0 -0
  226. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/__init__.py +0 -0
  227. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/dashboard.py +0 -0
  228. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/data.py +0 -0
  229. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/interfaces.py +0 -0
  230. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  231. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  232. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/questdb.py +0 -0
  233. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/rate_limiter.py +0 -0
  234. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/results.py +0 -0
  235. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/ringbuffer.pxd +0 -0
  236. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/ringbuffer.pyi +0 -0
  237. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/ringbuffer.pyx +0 -0
  238. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/__init__.py +0 -0
  239. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  240. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/accounts.py +0 -0
  241. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/configs.py +0 -0
  242. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/kernel_service.py +0 -0
  243. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/__init__.py +0 -0
  244. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/app.py +0 -0
  245. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/handlers.py +0 -0
  246. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/init_code.py +0 -0
  247. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/kernel.py +0 -0
  248. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/styles.tcss +0 -0
  249. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
  250. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
  251. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
  252. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
  253. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
  254. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
  255. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
  256. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/slack.py +0 -0
  257. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/throttler.py +0 -0
  258. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/time.py +0 -0
  259. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/src/qubx/utils/websocket_manager.py +0 -0
  260. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
  261. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
  262. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
  263. {qubx-1.0.0.dev4 → qubx-1.0.0.dev5}/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.0.0.dev4
3
+ Version: 1.0.0.dev5
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
@@ -180,5 +180,5 @@ dev = [
180
180
  "mongomock>=4.3.0,<5",
181
181
  "pytest-textual-snapshot>=1.1.0,<2",
182
182
  "git-cliff>=2.0.0",
183
- "duckdb>=1.0.0"
183
+ "duckdb>=1.0.0",
184
184
  ]
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.0.0.dev4'
32
- __version_tuple__ = version_tuple = (1, 0, 0, 'dev4')
31
+ __version__ = version = '1.0.0.dev5'
32
+ __version_tuple__ = version_tuple = (1, 0, 0, 'dev5')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -12,7 +12,7 @@ from asyncio.exceptions import CancelledError
12
12
  from collections import defaultdict
13
13
  from typing import Awaitable, Callable
14
14
 
15
- from ccxt import ExchangeClosedByUser, ExchangeError, ExchangeNotAvailable, NetworkError
15
+ from ccxt import BadSymbol, ExchangeClosedByUser, ExchangeError, ExchangeNotAvailable, NetworkError
16
16
  from ccxt.async_support.base.ws.client import Client as _WsClient
17
17
  from ccxt.pro import Exchange
18
18
 
@@ -133,6 +133,12 @@ class ConnectionManager:
133
133
  # Connection closed by us, stop gracefully
134
134
  logger.info(f"<yellow>{self._exchange_id}</yellow> {stream_name} listening has been stopped")
135
135
  break
136
+ except BadSymbol as e:
137
+ # Bad symbol is a permanent error - retrying will never succeed
138
+ logger.error(
139
+ f"<yellow>{self._exchange_id}</yellow> BadSymbol :: {stream_name} : {e} - stopping stream"
140
+ )
141
+ break
136
142
  except (NetworkError, ExchangeError, ExchangeNotAvailable) as e:
137
143
  # Network/exchange errors - retry after short delay
138
144
  logger.error(
@@ -8,6 +8,7 @@ import asyncio
8
8
  from typing import Set
9
9
 
10
10
  import pandas as pd
11
+ from ccxt import BadSymbol
11
12
 
12
13
  from qubx import logger
13
14
  from qubx.core.basics import CtrlChannel, DataType, Instrument
@@ -274,6 +275,8 @@ class OhlcDataHandler(BaseDataTypeHandler):
274
275
  # Use private processing method to avoid duplication
275
276
  self._process_ohlcv_bar(oh, inst, sub_type, channel, timeframe, ohlcv_data)
276
277
 
278
+ except BadSymbol:
279
+ raise # Permanent error, let ConnectionManager handle it
277
280
  except Exception as e:
278
281
  logger.error(
279
282
  f"<yellow>{exchange_id}</yellow> Error in individual OHLCV subscription for {inst.symbol}: {e}"
@@ -1455,3 +1455,8 @@ class InstrumentsLookup:
1455
1455
 
1456
1456
  class FeesLookup:
1457
1457
  def find_fees(self, exchange: str, spec: str | None) -> TransactionCostsCalculator: ...
1458
+
1459
+
1460
+ class AccountsLookup:
1461
+ def get_credentials(self, exchange: str): ...
1462
+ def get_settings(self, exchange: str): ...
@@ -148,7 +148,8 @@ class ITradeDataExport:
148
148
  pass
149
149
 
150
150
  def export_position_changes(
151
- self, time: dt_64, instrument: Instrument, price: float, account: "IAccountViewer"
151
+ self, time: dt_64, instrument: Instrument, price: float, account: "IAccountViewer",
152
+ metadata: dict[str, Any] | None = None,
152
153
  ) -> None:
153
154
  """
154
155
  Export position changes to an external system.
@@ -13,6 +13,7 @@ import stackprinter
13
13
  from qubx import logger
14
14
  from qubx.core.basics import (
15
15
  ZERO_COSTS,
16
+ AccountsLookup,
16
17
  FeesLookup,
17
18
  Instrument,
18
19
  InstrumentsLookup,
@@ -440,9 +441,30 @@ class InstrumentsLookupMongo(InstrumentsLookup):
440
441
  return self._lookup
441
442
 
442
443
 
443
- class LookupsManager(InstrumentsLookup, FeesLookup):
444
+ class AccountsLookupFromManager(AccountsLookup):
445
+ """Concrete AccountsLookup that delegates to an AccountConfigurationManager."""
446
+
447
+ _manager = None
448
+
449
+ def register(self, manager) -> None:
450
+ """Register account manager. Called once at startup by the runner."""
451
+ self._manager = manager
452
+
453
+ def get_credentials(self, exchange: str):
454
+ if self._manager is None:
455
+ raise RuntimeError("No account manager registered — call lookup.register_accounts() at startup")
456
+ return self._manager.get_exchange_credentials(exchange)
457
+
458
+ def get_settings(self, exchange: str):
459
+ if self._manager is None:
460
+ raise RuntimeError("No account manager registered — call lookup.register_accounts() at startup")
461
+ return self._manager.get_exchange_settings(exchange)
462
+
463
+
464
+ class LookupsManager(InstrumentsLookup, FeesLookup, AccountsLookup):
444
465
  _i_lookup: InstrumentsLookup
445
466
  _t_lookup: FeesLookup
467
+ _a_lookup: AccountsLookupFromManager
446
468
 
447
469
  def __new__(cls):
448
470
  if not hasattr(cls, "instance"):
@@ -466,6 +488,7 @@ class LookupsManager(InstrumentsLookup, FeesLookup):
466
488
  if f_cfg.path:
467
489
  f_kwargs["path"] = f_cfg.path
468
490
  cls.instance._t_lookup = LookupsManager._get_fees_lookup(type=f_cfg.type, **f_kwargs)
491
+ cls.instance._a_lookup = AccountsLookupFromManager()
469
492
 
470
493
  return cls.instance
471
494
 
@@ -511,6 +534,12 @@ class LookupsManager(InstrumentsLookup, FeesLookup):
511
534
  def __getitem__(self, spath: str) -> list[Instrument]:
512
535
  return self._i_lookup[spath]
513
536
 
537
+ def get_credentials(self, exchange: str):
538
+ return self._a_lookup.get_credentials(exchange)
539
+
540
+ def get_settings(self, exchange: str):
541
+ return self._a_lookup.get_settings(exchange)
542
+
514
543
 
515
544
  # - global lookup helper (lazy-loaded to avoid slow import)
516
545
  _lookup = None
@@ -523,3 +552,11 @@ def __getattr__(name):
523
552
  _lookup = LookupsManager()
524
553
  return _lookup
525
554
  raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
555
+
556
+
557
+ def register_accounts(manager) -> None:
558
+ """Register account manager in the global lookup. Called once at startup by the runner."""
559
+ global _lookup
560
+ if _lookup is None:
561
+ _lookup = LookupsManager()
562
+ _lookup._a_lookup.register(manager)
@@ -1015,11 +1015,13 @@ class ProcessingManager(IProcessingManager):
1015
1015
 
1016
1016
  if self._exporter is not None and (q := self._market_data.quote(instrument)) is not None:
1017
1017
  # - export position changes if exporter is available
1018
+ _active = self._active_targets.get(instrument)
1018
1019
  self._exporter.export_position_changes(
1019
1020
  time=self._time_provider.time(),
1020
1021
  instrument=instrument,
1021
1022
  price=q.mid_price(),
1022
1023
  account=self._account,
1024
+ metadata=_active.options if _active else None,
1023
1025
  )
1024
1026
 
1025
1027
  # - notify universe manager about position change
@@ -5,7 +5,7 @@ This module provides a composite implementation of ITradeDataExport that delegat
5
5
  to multiple exporters.
6
6
  """
7
7
 
8
- from typing import List
8
+ from typing import Any
9
9
 
10
10
  from qubx.core.basics import Instrument, Signal, TargetPosition, dt_64
11
11
  from qubx.core.interfaces import IAccountViewer, ITradeDataExport
@@ -19,22 +19,22 @@ class CompositeExporter(ITradeDataExport):
19
19
  by combining multiple exporters into one.
20
20
  """
21
21
 
22
- def __init__(self, exporters: List[ITradeDataExport]):
22
+ def __init__(self, exporters: list[ITradeDataExport]):
23
23
  """
24
24
  Initialize the Composite Exporter.
25
25
 
26
26
  Args:
27
- exporters: List of exporters to delegate to
27
+ exporters: list of exporters to delegate to
28
28
  """
29
29
  self._exporters = exporters
30
30
 
31
- def export_signals(self, time: dt_64, signals: List[Signal], account: IAccountViewer) -> None:
31
+ def export_signals(self, time: dt_64, signals: list[Signal], account: IAccountViewer) -> None:
32
32
  """
33
33
  Export signals to all configured exporters.
34
34
 
35
35
  Args:
36
36
  time: Timestamp when the signals were generated
37
- signals: List of signals to export
37
+ signals: list of signals to export
38
38
  account: Account viewer to get account information
39
39
  """
40
40
  for exporter in self._exporters:
@@ -45,13 +45,13 @@ class CompositeExporter(ITradeDataExport):
45
45
 
46
46
  logger.error(f"Error exporting signals to {exporter.__class__.__name__}: {e}")
47
47
 
48
- def export_target_positions(self, time: dt_64, targets: List[TargetPosition], account: IAccountViewer) -> None:
48
+ def export_target_positions(self, time: dt_64, targets: list[TargetPosition], account: IAccountViewer) -> None:
49
49
  """
50
50
  Export target positions to all configured exporters.
51
51
 
52
52
  Args:
53
53
  time: Timestamp when the target positions were generated
54
- targets: List of target positions to export
54
+ targets: list of target positions to export
55
55
  account: Account viewer to get account information
56
56
  """
57
57
  for exporter in self._exporters:
@@ -63,7 +63,8 @@ class CompositeExporter(ITradeDataExport):
63
63
  logger.error(f"Error exporting target positions to {exporter.__class__.__name__}: {e}")
64
64
 
65
65
  def export_position_changes(
66
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
66
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
67
+ metadata: dict[str, Any] | None = None,
67
68
  ) -> None:
68
69
  """
69
70
  Export position changes to all configured exporters.
@@ -73,10 +74,11 @@ class CompositeExporter(ITradeDataExport):
73
74
  instrument: The instrument for which the position changed
74
75
  price: Price at which the position changed
75
76
  account: Account viewer to get account information
77
+ metadata: Optional metadata to pass to exporters
76
78
  """
77
79
  for exporter in self._exporters:
78
80
  try:
79
- exporter.export_position_changes(time, instrument, price, account)
81
+ exporter.export_position_changes(time, instrument, price, account, metadata=metadata)
80
82
  except Exception as e:
81
83
  from qubx import logger
82
84
 
@@ -54,7 +54,8 @@ class IExportFormatter(ABC):
54
54
 
55
55
  @abstractmethod
56
56
  def format_position_change(
57
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
57
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
58
+ metadata: dict[str, Any] | None = None,
58
59
  ) -> dict[str, Any]:
59
60
  """
60
61
  Format a leverage change for export.
@@ -137,7 +138,8 @@ class DefaultFormatter(IExportFormatter):
137
138
  }
138
139
 
139
140
  def format_position_change(
140
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
141
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
142
+ metadata: dict[str, Any] | None = None,
141
143
  ) -> dict[str, Any]:
142
144
  """
143
145
  Format a position change for export.
@@ -37,7 +37,8 @@ class IncrementalFormatter(DefaultFormatter):
37
37
  self.instrument_leverages = dict(account.get_leverages())
38
38
 
39
39
  def format_position_change(
40
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
40
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
41
+ metadata: dict[str, Any] | None = None,
41
42
  ) -> dict[str, Any]:
42
43
  """
43
44
  Format a position change for export.
@@ -148,7 +148,8 @@ class SlackMessageFormatter(IExportFormatter):
148
148
  return {"blocks": blocks}
149
149
 
150
150
  def format_position_change(
151
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
151
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
152
+ metadata: dict[str, Any] | None = None,
152
153
  ) -> dict[str, Any]:
153
154
  """
154
155
  Format a position change as a Slack message.
@@ -172,6 +173,9 @@ class SlackMessageFormatter(IExportFormatter):
172
173
  f"*Current Quantity:* {position.quantity}\n"
173
174
  )
174
175
 
176
+ if metadata and "sources" in metadata:
177
+ position_text += f"*Sources:* {', '.join(metadata['sources'])}\n"
178
+
175
179
  # Create blocks
176
180
  blocks = [self._create_header_block("Position Change", timestamp), self._create_section_block(position_text)]
177
181
 
@@ -210,7 +210,8 @@ class RedisStreamsExporter(ITradeDataExport):
210
210
  logger.exception("[RedisStreamsExporter] Failed to export target positions")
211
211
 
212
212
  def export_position_changes(
213
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
213
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
214
+ metadata: dict[str, Any] | None = None,
214
215
  ) -> None:
215
216
  """
216
217
  Export position changes to Redis Stream.
@@ -230,7 +231,7 @@ class RedisStreamsExporter(ITradeDataExport):
230
231
 
231
232
  try:
232
233
  # Format the leverage change using the formatter
233
- data = self._formatter.format_position_change(time, instrument, price, account)
234
+ data = self._formatter.format_position_change(time, instrument, price, account, metadata=metadata)
234
235
 
235
236
  # Add to Redis stream in background thread
236
237
  self._add_to_redis_stream(self._position_changes_stream, data)
@@ -4,7 +4,7 @@ Slack Exporter for trading data.
4
4
  This module provides an implementation of ITradeDataExport that exports trading data to Slack channels.
5
5
  """
6
6
 
7
- from typing import List, Optional
7
+ from typing import Any, List, Optional
8
8
 
9
9
  from qubx import logger
10
10
  from qubx.core.basics import Instrument, Signal, TargetPosition, dt_64
@@ -140,7 +140,8 @@ class SlackExporter(ITradeDataExport):
140
140
  logger.error(f"Failed to export target positions: {e}")
141
141
 
142
142
  def export_position_changes(
143
- self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer
143
+ self, time: dt_64, instrument: Instrument, price: float, account: IAccountViewer,
144
+ metadata: dict[str, Any] | None = None,
144
145
  ) -> None:
145
146
  """
146
147
  Export position changes to Slack.
@@ -156,7 +157,7 @@ class SlackExporter(ITradeDataExport):
156
157
 
157
158
  try:
158
159
  # Format the position change using the formatter
159
- data = self._formatter.format_position_change(time, instrument, price, account)
160
+ data = self._formatter.format_position_change(time, instrument, price, account, metadata=metadata)
160
161
 
161
162
  # Extract blocks and create fallback message
162
163
  blocks = data.get("blocks", [])
@@ -4,10 +4,7 @@ Factory functions for creating various components used in strategy running and s
4
4
 
5
5
  import inspect
6
6
  import os
7
- from typing import TYPE_CHECKING, Any, Optional
8
-
9
- if TYPE_CHECKING:
10
- from qubx.utils.runner.accounts import AccountConfigurationManager
7
+ from typing import Any
11
8
 
12
9
  from qubx import logger
13
10
  from qubx.core.interfaces import IAccountViewer, IMetricEmitter, IStatePersistence, IStrategyNotifier, ITradeDataExport
@@ -47,7 +44,7 @@ def construct_storage(storage_config: StorageConfig | None) -> IStorage | None:
47
44
  (e.g., 'qdb::quantlab', 'csv::/data/path/', 'mqdb::nebula').
48
45
 
49
46
  Args:
50
- reader_config: Reader/storage configuration
47
+ storage_config: Storage configuration
51
48
 
52
49
  Returns:
53
50
  IStorage instance or None if storage_config is None
@@ -222,7 +219,7 @@ def create_data_type_storages(storages_configs: list[TypedStorageConfig] | None)
222
219
  def create_exporters(
223
220
  exporters: list[ExporterConfig] | None,
224
221
  strategy_name: str,
225
- account: Optional[IAccountViewer] = None,
222
+ account: IAccountViewer | None = None,
226
223
  ) -> ITradeDataExport | None:
227
224
  """
228
225
  Create exporters from the configuration.
@@ -400,7 +397,7 @@ def construct_multi_storage(storage_configs: list[StorageConfig]) -> IStorage |
400
397
  Construct auxiliary data storage from config.
401
398
 
402
399
  Args:
403
- aux_configs: List of reader configurations
400
+ storage_configs: List of storage configurations
404
401
 
405
402
  Returns:
406
403
  Single IStorage if only one config, MultiStorage if multiple configs, None if empty
@@ -42,7 +42,7 @@ from qubx.core.interfaces import (
42
42
  ITimeProvider,
43
43
  )
44
44
  from qubx.core.loggers import StrategyLogging
45
- from qubx.core.lookups import lookup
45
+ from qubx.core.lookups import lookup, register_accounts
46
46
  from qubx.core.mixins.utils import EXCHANGE_MAPPINGS
47
47
  from qubx.data.cache import CachedStorage, MemoryCache
48
48
  from qubx.data.storages.stub import NoConfiguredStorage
@@ -254,6 +254,8 @@ def run_strategy(
254
254
  loop_thread.start()
255
255
  logger.debug("Shared event loop started in background thread")
256
256
 
257
+ register_accounts(account_manager)
258
+
257
259
  QubxLogConfig.setup_logger(
258
260
  level=QubxLogConfig.get_log_level(),
259
261
  custom_formatter=(simulated_formatter := SimulatedLogFormatter(LiveTimeProvider())).formatter,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes