Qubx 1.1.2.dev4__tar.gz → 1.1.2.dev6__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 (294) hide show
  1. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/PKG-INFO +1 -1
  2. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/_version.py +2 -2
  3. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/metrics.py +121 -9
  4. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/multi.py +17 -5
  5. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/.gitignore +0 -0
  6. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/LICENSE +0 -0
  7. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/README.md +0 -0
  8. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/pyproject.toml +0 -0
  9. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/scripts/build.py +0 -0
  10. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/__init__.py +0 -0
  11. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/_nb_magic.py +0 -0
  12. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/__init__.py +0 -0
  13. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/account.py +0 -0
  14. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/broker.py +0 -0
  15. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/data.py +0 -0
  16. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/iteratedstream.py +0 -0
  17. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/management.py +0 -0
  18. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/ome.py +0 -0
  19. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/optimization.py +0 -0
  20. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/runner.py +0 -0
  21. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/sentinels.py +0 -0
  22. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/simulated_data.py +0 -0
  23. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/simulated_exchange.py +0 -0
  24. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/simulator.py +0 -0
  25. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/transfers.py +0 -0
  26. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/backtester/utils.py +0 -0
  27. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/__init__.py +0 -0
  28. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/commands.py +0 -0
  29. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/deploy.py +0 -0
  30. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/misc.py +0 -0
  31. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/release.py +0 -0
  32. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/resolver.py +0 -0
  33. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/s3.py +0 -0
  34. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/theme.py +0 -0
  35. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/tui.py +0 -0
  36. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/cli/user_config.py +0 -0
  37. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/config.py +0 -0
  38. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/__init__.py +0 -0
  39. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/__init__.py +0 -0
  40. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/account.py +0 -0
  41. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  42. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  43. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/broker.py +0 -0
  44. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
  45. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/data.py +0 -0
  46. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  47. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  48. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  49. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  50. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  51. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  52. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  53. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  54. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
  55. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
  56. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  57. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py +0 -0
  58. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +0 -0
  59. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  60. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  61. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/okx/__init__.py +0 -0
  62. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/okx/account.py +0 -0
  63. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/okx/broker.py +0 -0
  64. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/exchanges/okx/okx.py +0 -0
  65. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/factory.py +0 -0
  66. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  67. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  68. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  69. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  70. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  71. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
  72. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  73. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  74. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  75. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  76. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  77. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  78. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  79. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/utils.py +0 -0
  80. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  81. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/registry.py +0 -0
  82. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/tardis/data.py +0 -0
  83. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/connectors/tardis/utils.py +0 -0
  84. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/__init__.py +0 -0
  85. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/account.py +0 -0
  86. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/basics.py +0 -0
  87. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/context.py +0 -0
  88. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/detectors/__init__.py +0 -0
  89. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/detectors/delisting.py +0 -0
  90. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/detectors/stale.py +0 -0
  91. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/errors.py +0 -0
  92. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/exceptions.py +0 -0
  93. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/helpers.py +0 -0
  94. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/initializer.py +0 -0
  95. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/interfaces.py +0 -0
  96. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/loggers.py +0 -0
  97. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/lookups.py +0 -0
  98. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/__init__.py +0 -0
  99. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/market.py +0 -0
  100. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/processing.py +0 -0
  101. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/subscription.py +0 -0
  102. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/trading.py +0 -0
  103. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/universe.py +0 -0
  104. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/mixins/utils.py +0 -0
  105. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/series.pxd +0 -0
  106. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/series.pyi +0 -0
  107. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/series.pyx +0 -0
  108. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/utils.pyi +0 -0
  109. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/core/utils.pyx +0 -0
  110. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/__init__.py +0 -0
  111. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/cache.py +0 -0
  112. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/containers.py +0 -0
  113. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/guards.py +0 -0
  114. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/registry.py +0 -0
  115. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storage.py +0 -0
  116. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/ccxt.py +0 -0
  117. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/csv.py +0 -0
  118. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/handy.py +0 -0
  119. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/questdb.py +0 -0
  120. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/stub.py +0 -0
  121. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/storages/utils.py +0 -0
  122. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/data/transformers.py +0 -0
  123. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/__init__.py +0 -0
  124. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/base.py +0 -0
  125. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/composite.py +0 -0
  126. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/csv.py +0 -0
  127. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/indicator.py +0 -0
  128. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/inmemory.py +0 -0
  129. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/prometheus.py +0 -0
  130. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/emitters/questdb.py +0 -0
  131. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/__init__.py +0 -0
  132. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/composite.py +0 -0
  133. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/formatters/__init__.py +0 -0
  134. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/formatters/base.py +0 -0
  135. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/formatters/incremental.py +0 -0
  136. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/formatters/slack.py +0 -0
  137. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/formatters/target_position.py +0 -0
  138. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/redis_streams.py +0 -0
  139. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/exporters/slack.py +0 -0
  140. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/gathering/simplest.py +0 -0
  141. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/health/__init__.py +0 -0
  142. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/health/base.py +0 -0
  143. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/health/dummy.py +0 -0
  144. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/health/server.py +0 -0
  145. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/loggers/__init__.py +0 -0
  146. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/loggers/csv.py +0 -0
  147. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/loggers/factory.py +0 -0
  148. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/loggers/inmemory.py +0 -0
  149. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/loggers/mongo.py +0 -0
  150. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/notifications/__init__.py +0 -0
  151. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/notifications/composite.py +0 -0
  152. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/notifications/slack.py +0 -0
  153. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/notifications/throttler.py +0 -0
  154. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/pandaz/__init__.py +0 -0
  155. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/pandaz/stats.py +0 -0
  156. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/pandaz/ta.py +0 -0
  157. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/pandaz/utils.py +0 -0
  158. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/plugins/__init__.py +0 -0
  159. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/plugins/loader.py +0 -0
  160. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/_build.py +0 -0
  161. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/crypto-fees.ini +0 -0
  162. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  163. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  164. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  165. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  166. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  167. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  168. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  169. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  170. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  171. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  172. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  173. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restarts/__init__.py +0 -0
  174. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restarts/state_resolvers.py +0 -0
  175. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restarts/time_finders.py +0 -0
  176. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/__init__.py +0 -0
  177. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/balance.py +0 -0
  178. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/factory.py +0 -0
  179. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/interfaces.py +0 -0
  180. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/position.py +0 -0
  181. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/signal.py +0 -0
  182. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/state.py +0 -0
  183. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/restorers/utils.py +0 -0
  184. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/state/__init__.py +0 -0
  185. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/state/dummy.py +0 -0
  186. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/state/redis.py +0 -0
  187. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/ta/__init__.py +0 -0
  188. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/ta/indicators.pxd +0 -0
  189. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/ta/indicators.pyi +0 -0
  190. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/ta/indicators.pyx +0 -0
  191. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/__init__.py +0 -0
  192. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/base.py +0 -0
  193. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  194. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/config.yml.j2 +0 -0
  195. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  196. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  197. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  198. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  199. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  200. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/project/template.yml +0 -0
  201. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.claude/skills/qubx-cli/SKILL.md +0 -0
  202. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.claude/skills/qubx-indicators/SKILL.md +0 -0
  203. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.claude/skills/simulation-explorer/SKILL.md +0 -0
  204. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.claude/skills/strategy-release/SKILL.md +0 -0
  205. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.github/workflows/ci.yml.j2 +0 -0
  206. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.gitignore.j2 +0 -0
  207. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.python-version +0 -0
  208. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.vscode/launch.json +0 -0
  209. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.vscode/settings.json +0 -0
  210. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/.vscode/tasks.json +0 -0
  211. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/CLAUDE.md.j2 +0 -0
  212. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/README.md.j2 +0 -0
  213. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/configs/.gitkeep +0 -0
  214. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/justfile.j2 +0 -0
  215. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/pyproject.toml.j2 +0 -0
  216. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/research/.gitkeep +0 -0
  217. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  218. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/src/{{ strategy_name }}/cli.py.j2 +0 -0
  219. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  220. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/template.yml +0 -0
  221. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/repo/tests/test_strategy.py.j2 +0 -0
  222. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  223. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  224. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/config.yml.j2 +0 -0
  225. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  226. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  227. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  228. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/templates/simple/template.yml +0 -0
  229. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/__init__.py +0 -0
  230. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/advanced.py +0 -0
  231. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/composite.py +0 -0
  232. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/rebalancers.py +0 -0
  233. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/riskctrl.py +0 -0
  234. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/trackers/sizers.py +0 -0
  235. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/__init__.py +0 -0
  236. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/_pyxreloader.py +0 -0
  237. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/charting/lookinglass.py +0 -0
  238. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  239. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/charting/orderbook.py +0 -0
  240. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/collections.py +0 -0
  241. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/hft/__init__.py +0 -0
  242. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/hft/numba_utils.py +0 -0
  243. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/hft/orderbook.pyi +0 -0
  244. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/hft/orderbook.pyx +0 -0
  245. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/marketdata/binance.py +0 -0
  246. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/marketdata/ccxt.py +0 -0
  247. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/marketdata/dukas.py +0 -0
  248. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/misc.py +0 -0
  249. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/nonce.py +0 -0
  250. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/ntp.py +0 -0
  251. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/numbers_utils.py +0 -0
  252. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/orderbook.py +0 -0
  253. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/__init__.py +0 -0
  254. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/dashboard.py +0 -0
  255. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/data.py +0 -0
  256. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/interfaces.py +0 -0
  257. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  258. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  259. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/questdb.py +0 -0
  260. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/rate_limiter.py +0 -0
  261. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/results.py +0 -0
  262. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/ringbuffer.pxd +0 -0
  263. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/ringbuffer.pyi +0 -0
  264. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/ringbuffer.pyx +0 -0
  265. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/__init__.py +0 -0
  266. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  267. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/accounts.py +0 -0
  268. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/configs.py +0 -0
  269. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/factory.py +0 -0
  270. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/kernel_service.py +0 -0
  271. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/runner.py +0 -0
  272. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/__init__.py +0 -0
  273. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/app.py +0 -0
  274. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/handlers.py +0 -0
  275. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/init_code.py +0 -0
  276. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/kernel.py +0 -0
  277. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/styles.tcss +0 -0
  278. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
  279. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/account_summary.py +0 -0
  280. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
  281. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
  282. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
  283. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
  284. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
  285. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
  286. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/s3.py +0 -0
  287. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/slack.py +0 -0
  288. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/throttler.py +0 -0
  289. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/time.py +0 -0
  290. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/src/qubx/utils/websocket_manager.py +0 -0
  291. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
  292. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
  293. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
  294. {qubx-1.1.2.dev4 → qubx-1.1.2.dev6}/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.1.2.dev4
3
+ Version: 1.1.2.dev6
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Project-URL: homepage, https://xlydian.com
6
6
  Project-URL: repository, https://github.com/xLydianSoftware/Qubx
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.1.2.dev4'
22
- __version_tuple__ = version_tuple = (1, 1, 2, 'dev4')
21
+ __version__ = version = '1.1.2.dev6'
22
+ __version_tuple__ = version_tuple = (1, 1, 2, 'dev6')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -913,11 +913,34 @@ class TradingSessionResult:
913
913
  return pd.Series(dtype=float)
914
914
  return calculate_leverage(self.portfolio_log, self.get_total_capital(), self.start)
915
915
 
916
+ @property
917
+ def gross_leverage(self) -> pd.Series:
918
+ """Get gross leverage over time (sum of absolute exposures / capital)"""
919
+ if self.portfolio_log.empty:
920
+ return pd.Series(dtype=float)
921
+ return calculate_gross_leverage(self.portfolio_log, self.get_total_capital(), self.start)
922
+
916
923
  def get_funding_per_symbol(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.DataFrame:
917
924
  if self.portfolio_log.empty:
918
925
  return pd.DataFrame(dtype=float)
919
926
  return calculate_funding_per_symbol(self.portfolio_log, start, stop)
920
927
 
928
+ def get_commissions_per_asset(
929
+ self, start: OptTimestamp = None, stop: OptTimestamp = None, filter_zero: bool = True
930
+ ) -> pd.DataFrame:
931
+ if self.portfolio_log.empty:
932
+ return pd.DataFrame(dtype=float)
933
+ return calculate_commissions_per_asset(self.portfolio_log, start, stop, filter_zero)
934
+
935
+ def get_commissions_total(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.Series:
936
+ return self.get_commissions_per_asset(start, stop).sum(axis=1).rename("commissions_total")
937
+
938
+ def get_commissions_breakdown(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.Series:
939
+ df = self.get_commissions_per_asset(start, stop)
940
+ if df.empty:
941
+ return pd.Series(dtype=float)
942
+ return df.iloc[-1].sort_values(ascending=False).rename("commissions_breakdown")
943
+
921
944
  def get_funding_per_asset(
922
945
  self, start: OptTimestamp = None, stop: OptTimestamp = None, filter_zero: bool = True
923
946
  ) -> pd.DataFrame:
@@ -928,8 +951,8 @@ class TradingSessionResult:
928
951
  def get_funding_total(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.Series:
929
952
  return self.get_funding_per_asset(start, stop).sum(axis=1).rename("funding_total")
930
953
 
931
- def get_funding_pnl(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.Series:
932
- return self.get_funding_per_asset(start, stop).iloc[-1].sort_values(ascending=False).rename("funding_pnl")
954
+ def get_funding_breakdown(self, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.Series:
955
+ return self.get_funding_per_asset(start, stop).iloc[-1].sort_values(ascending=False).rename("funding_breakdown")
933
956
 
934
957
  def get_asset_pnl(
935
958
  self,
@@ -951,7 +974,7 @@ class TradingSessionResult:
951
974
  funding_delta = funding.diff().fillna(funding.iloc[0])
952
975
  pnl -= funding_delta.cumsum()
953
976
  if commission_factor:
954
- comm = portfolio.filter(regex=f".*{asset}.*_Commissions").loc[start:stop].sum(axis=1).cumsum()
977
+ comm = portfolio.filter(regex=f".*:{asset}USD.*_Commissions").loc[start:stop].sum(axis=1).cumsum()
955
978
  pnl -= comm * commission_factor
956
979
  return pnl / init_capital * 100 if pct_from_initial_capital else pnl
957
980
 
@@ -959,10 +982,11 @@ class TradingSessionResult:
959
982
  self,
960
983
  start: OptTimestamp = None,
961
984
  stop: OptTimestamp = None,
985
+ commission_factor: float = 1.0,
962
986
  pct_from_initial_capital: bool = False,
963
987
  drop_zero: bool = True,
964
988
  include_funding: bool = False,
965
- ) -> pd.Series:
989
+ ) -> pd.DataFrame:
966
990
  start = start or self.start
967
991
  stop = stop or self.stop
968
992
  assets = set()
@@ -976,13 +1000,60 @@ class TradingSessionResult:
976
1000
  assets.add(instrument.asset)
977
1001
  asset_to_pnl = {}
978
1002
  for asset in assets:
979
- pnl = self.get_asset_pnl(asset, start, stop, pct_from_initial_capital=pct_from_initial_capital, include_funding=include_funding)
1003
+ pnl = self.get_asset_pnl(
1004
+ asset,
1005
+ start,
1006
+ stop,
1007
+ commission_factor=commission_factor,
1008
+ pct_from_initial_capital=pct_from_initial_capital,
1009
+ include_funding=include_funding,
1010
+ )
980
1011
  if pnl is not None and not pnl.empty:
981
- last_pnl = pnl.iloc[-1]
982
- if drop_zero and last_pnl == 0:
1012
+ if drop_zero and pnl.iloc[-1] == 0:
983
1013
  continue
984
- asset_to_pnl[asset] = last_pnl
985
- return pd.Series(asset_to_pnl).sort_values(ascending=False)
1014
+ asset_to_pnl[asset] = pnl
1015
+ if not asset_to_pnl:
1016
+ return pd.DataFrame(dtype=float)
1017
+ return pd.DataFrame(asset_to_pnl)
1018
+
1019
+ def get_pnl_total(
1020
+ self,
1021
+ start: OptTimestamp = None,
1022
+ stop: OptTimestamp = None,
1023
+ commission_factor: float = 1.0,
1024
+ pct_from_initial_capital: bool = False,
1025
+ include_funding: bool = False,
1026
+ ) -> pd.Series:
1027
+ return (
1028
+ self.get_pnl_per_asset(
1029
+ start,
1030
+ stop,
1031
+ commission_factor=commission_factor,
1032
+ pct_from_initial_capital=pct_from_initial_capital,
1033
+ include_funding=include_funding,
1034
+ )
1035
+ .sum(axis=1)
1036
+ .rename("pnl_total")
1037
+ )
1038
+
1039
+ def get_pnl_breakdown(
1040
+ self,
1041
+ start: OptTimestamp = None,
1042
+ stop: OptTimestamp = None,
1043
+ pct_from_initial_capital: bool = False,
1044
+ drop_zero: bool = True,
1045
+ include_funding: bool = False,
1046
+ ) -> pd.Series:
1047
+ df = self.get_pnl_per_asset(
1048
+ start,
1049
+ stop,
1050
+ pct_from_initial_capital=pct_from_initial_capital,
1051
+ drop_zero=drop_zero,
1052
+ include_funding=include_funding,
1053
+ )
1054
+ if df.empty:
1055
+ return pd.Series(dtype=float)
1056
+ return df.iloc[-1].sort_values(ascending=False).rename("pnl_breakdown")
986
1057
 
987
1058
  def get_position_asset(self, asset: str, start: OptTimestamp = None, stop: OptTimestamp = None) -> pd.DataFrame:
988
1059
  pos = self.portfolio_log.filter(regex=f".*{asset}.*_Pos")
@@ -2062,6 +2133,14 @@ def calculate_leverage(
2062
2133
  return (value.squeeze() / capital).mul(100).rename("Leverage") # type: ignore
2063
2134
 
2064
2135
 
2136
+ def calculate_gross_leverage(portfolio: pd.DataFrame, init_capital: float, start: str | pd.Timestamp) -> pd.Series:
2137
+ total_pnl = calculate_total_pnl(portfolio, split_cumulative=False).loc[start:]
2138
+ capital = init_capital + total_pnl["Total_PnL"].cumsum() - total_pnl["Total_Commissions"].cumsum()
2139
+ value_columns = [col for col in portfolio.columns if "_Value" in col]
2140
+ abs_value = portfolio[value_columns].loc[start:].abs().sum(axis=1)
2141
+ return (abs_value / capital).mul(100).rename("Gross Leverage")
2142
+
2143
+
2065
2144
  def calculate_leverage_per_symbol(
2066
2145
  session: TradingSessionResult,
2067
2146
  start: str | pd.Timestamp | None = None,
@@ -2173,6 +2252,39 @@ def _slice_df(df: pd.DataFrame, start: OptTimestamp = None, stop: OptTimestamp =
2173
2252
  return df
2174
2253
 
2175
2254
 
2255
+ def calculate_commissions_per_symbol(
2256
+ portfolio_log: pd.DataFrame, start: OptTimestamp = None, stop: OptTimestamp = None
2257
+ ) -> pd.DataFrame:
2258
+ """Calculate cumulative commissions for each symbol in the trading session."""
2259
+ return _slice_df(portfolio_log.filter(like="_Commissions"), start, stop).cumsum()
2260
+
2261
+
2262
+ def calculate_commissions_per_asset(
2263
+ portfolio_log: pd.DataFrame,
2264
+ start: OptTimestamp = None,
2265
+ stop: OptTimestamp = None,
2266
+ filter_zero: bool = True,
2267
+ ) -> pd.DataFrame:
2268
+ """
2269
+ Calculate cumulative commissions for each asset in the trading session.
2270
+ """
2271
+ df = calculate_commissions_per_symbol(portfolio_log, start, stop)
2272
+ df = df.rename(columns=lambda x: x.replace("_Commissions", ""))
2273
+
2274
+ # Map each column (EXCHANGE:SYMBOL) to its asset name
2275
+ col_to_asset: dict[str, str] = {}
2276
+ for col in df.columns:
2277
+ exchange, symbol = col.split(":")
2278
+ instr = lookup.find_symbol(exchange, symbol)
2279
+ col_to_asset[col] = instr.asset if instr else col
2280
+
2281
+ # Group by asset and sum
2282
+ df = df.rename(columns=col_to_asset).T.groupby(level=0).sum().T
2283
+ if filter_zero:
2284
+ df = df.loc[:, df.ne(0).any(axis=0)]
2285
+ return df
2286
+
2287
+
2176
2288
  def calculate_funding_per_symbol(
2177
2289
  portfolio_log: pd.DataFrame, start: OptTimestamp = None, stop: OptTimestamp = None
2178
2290
  ) -> pd.DataFrame:
@@ -143,7 +143,9 @@ class MultiReader(IReader):
143
143
  dtype_ref = result.dtype
144
144
  batches.append(result.data)
145
145
  except Exception as e:
146
- logger.warning(f"{reader.__class__.__name__}.read() failed for '{data_id}': {e}")
146
+ # - expected when one storage doesn't carry this dtype (e.g. QuestDB has no
147
+ # vendor microstructure tables); the next reader will be tried
148
+ logger.debug(f"{reader.__class__.__name__} has no '{data_id}' ({dtype}): {e}")
147
149
 
148
150
  return batches, time_idx, schema, dtype_ref
149
151
 
@@ -180,9 +182,14 @@ class MultiReader(IReader):
180
182
  time_idx = raw.index
181
183
  dtype_ref = raw.dtype
182
184
  except Exception as e:
183
- logger.warning(f"{reader.__class__.__name__}.read() failed for multi data_ids: {e}")
185
+ # - expected when one storage doesn't carry this dtype; the next reader will be tried
186
+ logger.debug(f"{reader.__class__.__name__} has no ({dtype}) for multi data_ids: {e}")
184
187
 
185
188
  if not batches_per_id:
189
+ # - all readers exhausted with no data — only now it's worth a warning
190
+ logger.warning(
191
+ f"No data for ({dtype}) in any of {len(self._readers)} reader(s): {[r.__class__.__name__ for r in self._readers]}"
192
+ )
186
193
  return RawMultiData([])
187
194
 
188
195
  merged_raws = [
@@ -239,7 +246,9 @@ class MultiReader(IReader):
239
246
  if ts_name is None:
240
247
  ts_name = f.name
241
248
  ts_unit = f.type.unit
242
- elif f.name == ts_name and _precision_rank.get(f.type.unit, 0) > _precision_rank.get(ts_unit or "s", 0):
249
+ elif f.name == ts_name and _precision_rank.get(f.type.unit, 0) > _precision_rank.get(
250
+ ts_unit or "s", 0
251
+ ):
243
252
  ts_unit = f.type.unit
244
253
  # - fallback: if no timestamp column found, default to "ms"
245
254
  ts_unit = ts_unit or "ms"
@@ -407,11 +416,14 @@ class MultiStorage(IStorage):
407
416
 
408
417
  def __init__(
409
418
  self,
410
- storages: list[IStorage],
419
+ storages: list[str | IStorage],
411
420
  tolerance: str | None = None,
412
421
  keep: str = "last",
413
422
  ):
414
- self._storages = storages
423
+ from qubx.data.registry import StorageRegistry
424
+
425
+ # - resolve string URIs (e.g. "qdb::quantlab") to IStorage instances
426
+ self._storages = [StorageRegistry.get(s) if isinstance(s, str) else s for s in storages]
415
427
  self._tolerance = tolerance
416
428
  self._keep = keep
417
429
  self._reader_cache: dict[tuple[str, str], IReader] = {}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes