Qubx 0.6.91__tar.gz → 0.6.93__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.

Potentially problematic release.


This version of Qubx might be problematic. Click here for more details.

Files changed (264) hide show
  1. {qubx-0.6.91 → qubx-0.6.93}/PKG-INFO +5 -2
  2. {qubx-0.6.91 → qubx-0.6.93}/pyproject.toml +9 -2
  3. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/management.py +2 -1
  4. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/commands.py +117 -2
  5. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/factory.py +15 -20
  6. qubx-0.6.93/src/qubx/connectors/xlighter/__init__.py +83 -0
  7. qubx-0.6.93/src/qubx/connectors/xlighter/account.py +531 -0
  8. qubx-0.6.93/src/qubx/connectors/xlighter/broker.py +857 -0
  9. qubx-0.6.93/src/qubx/connectors/xlighter/client.py +378 -0
  10. qubx-0.6.93/src/qubx/connectors/xlighter/constants.py +126 -0
  11. qubx-0.6.93/src/qubx/connectors/xlighter/data.py +620 -0
  12. qubx-0.6.93/src/qubx/connectors/xlighter/extensions.py +248 -0
  13. qubx-0.6.93/src/qubx/connectors/xlighter/factory.py +330 -0
  14. qubx-0.6.93/src/qubx/connectors/xlighter/handlers/__init__.py +13 -0
  15. qubx-0.6.93/src/qubx/connectors/xlighter/handlers/base.py +104 -0
  16. qubx-0.6.93/src/qubx/connectors/xlighter/handlers/orderbook.py +207 -0
  17. qubx-0.6.93/src/qubx/connectors/xlighter/handlers/quote.py +158 -0
  18. qubx-0.6.93/src/qubx/connectors/xlighter/handlers/trades.py +146 -0
  19. qubx-0.6.93/src/qubx/connectors/xlighter/instruments.py +253 -0
  20. qubx-0.6.93/src/qubx/connectors/xlighter/orderbook_maintainer.py +314 -0
  21. qubx-0.6.93/src/qubx/connectors/xlighter/parsers.py +694 -0
  22. qubx-0.6.93/src/qubx/connectors/xlighter/reader.py +489 -0
  23. qubx-0.6.93/src/qubx/connectors/xlighter/utils.py +281 -0
  24. qubx-0.6.93/src/qubx/connectors/xlighter/websocket.py +359 -0
  25. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/account.py +25 -22
  26. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/interfaces.py +197 -0
  27. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/trading.py +73 -0
  28. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/series.pxd +8 -0
  29. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/series.pyi +46 -2
  30. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/series.pyx +134 -4
  31. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/storages/questdb.py +18 -6
  32. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/transformers.py +36 -1
  33. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/pandaz/utils.py +1 -1
  34. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/accounts.py +30 -1
  35. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/configs.py +2 -1
  36. qubx-0.6.93/src/qubx/utils/runner/kernel_service.py +195 -0
  37. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/runner.py +107 -7
  38. qubx-0.6.93/src/qubx/utils/runner/textual/__init__.py +177 -0
  39. qubx-0.6.93/src/qubx/utils/runner/textual/app.py +392 -0
  40. qubx-0.6.93/src/qubx/utils/runner/textual/handlers.py +90 -0
  41. qubx-0.6.93/src/qubx/utils/runner/textual/init_code.py +304 -0
  42. qubx-0.6.93/src/qubx/utils/runner/textual/kernel.py +269 -0
  43. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/textual/styles.tcss +43 -9
  44. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/__init__.py +10 -0
  45. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/command_input.py +105 -0
  46. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/debug_log.py +97 -0
  47. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/orders_table.py +61 -0
  48. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/textual/widgets/positions_table.py +3 -1
  49. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/quotes_table.py +90 -0
  50. qubx-0.6.93/src/qubx/utils/runner/textual/widgets/repl_output.py +97 -0
  51. qubx-0.6.93/src/qubx/utils/websocket_manager.py +442 -0
  52. qubx-0.6.91/src/qubx/utils/runner/textual/__init__.py +0 -60
  53. qubx-0.6.91/src/qubx/utils/runner/textual/app.py +0 -149
  54. qubx-0.6.91/src/qubx/utils/runner/textual/handlers.py +0 -72
  55. qubx-0.6.91/src/qubx/utils/runner/textual/init_code.py +0 -143
  56. qubx-0.6.91/src/qubx/utils/runner/textual/kernel.py +0 -110
  57. qubx-0.6.91/src/qubx/utils/runner/textual/widgets/__init__.py +0 -6
  58. qubx-0.6.91/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -14
  59. {qubx-0.6.91 → qubx-0.6.93}/LICENSE +0 -0
  60. {qubx-0.6.91 → qubx-0.6.93}/README.md +0 -0
  61. {qubx-0.6.91 → qubx-0.6.93}/build.py +0 -0
  62. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/__init__.py +0 -0
  63. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/_nb_magic.py +0 -0
  64. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/__init__.py +0 -0
  65. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/account.py +0 -0
  66. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/broker.py +0 -0
  67. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/data.py +0 -0
  68. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/ome.py +0 -0
  69. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/optimization.py +0 -0
  70. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/runner.py +0 -0
  71. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/sentinels.py +0 -0
  72. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/simulated_data.py +0 -0
  73. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/simulated_exchange.py +0 -0
  74. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/simulator.py +0 -0
  75. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/backtester/utils.py +0 -0
  76. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/__init__.py +0 -0
  77. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/deploy.py +0 -0
  78. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/misc.py +0 -0
  79. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/release.py +0 -0
  80. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/cli/tui.py +0 -0
  81. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/__init__.py +0 -0
  82. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/account.py +0 -0
  83. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
  84. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
  85. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/broker.py +0 -0
  86. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
  87. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/data.py +0 -0
  88. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  89. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
  90. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  91. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
  92. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  93. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  94. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  95. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  96. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
  97. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py +0 -0
  98. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +0 -0
  99. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
  100. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  101. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
  102. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
  103. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
  104. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
  105. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
  106. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
  107. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
  108. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
  109. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
  110. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
  111. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/reader.py +0 -0
  112. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
  113. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
  114. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
  115. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/utils.py +0 -0
  116. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
  117. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/tardis/data.py +0 -0
  118. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/connectors/tardis/utils.py +0 -0
  119. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/__init__.py +0 -0
  120. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/basics.py +0 -0
  121. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/context.py +0 -0
  122. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/deque.py +0 -0
  123. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/errors.py +0 -0
  124. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/exceptions.py +0 -0
  125. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/helpers.py +0 -0
  126. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/initializer.py +0 -0
  127. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/loggers.py +0 -0
  128. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/lookups.py +0 -0
  129. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/metrics.py +0 -0
  130. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/__init__.py +0 -0
  131. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/market.py +0 -0
  132. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/processing.py +0 -0
  133. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/subscription.py +0 -0
  134. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/universe.py +0 -0
  135. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/mixins/utils.py +0 -0
  136. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/stale_data_detector.py +0 -0
  137. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/utils.pyi +0 -0
  138. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/core/utils.pyx +0 -0
  139. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/__init__.py +0 -0
  140. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/composite.py +0 -0
  141. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/containers.py +0 -0
  142. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/helpers.py +0 -0
  143. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/hft.py +0 -0
  144. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/readers.py +0 -0
  145. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/registry.py +0 -0
  146. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/storage.py +0 -0
  147. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/storages/csv.py +0 -0
  148. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/storages/utils.py +0 -0
  149. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/data/tardis.py +0 -0
  150. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/__init__.py +0 -0
  151. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/base.py +0 -0
  152. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/composite.py +0 -0
  153. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/csv.py +0 -0
  154. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/indicator.py +0 -0
  155. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/inmemory.py +0 -0
  156. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/prometheus.py +0 -0
  157. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/emitters/questdb.py +0 -0
  158. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/__init__.py +0 -0
  159. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/composite.py +0 -0
  160. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/formatters/__init__.py +0 -0
  161. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/formatters/base.py +0 -0
  162. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/formatters/incremental.py +0 -0
  163. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/formatters/slack.py +0 -0
  164. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/formatters/target_position.py +0 -0
  165. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/redis_streams.py +0 -0
  166. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/exporters/slack.py +0 -0
  167. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/__init__.py +0 -0
  168. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/core.py +0 -0
  169. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/orderbook.py +0 -0
  170. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/price.py +0 -0
  171. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/trades.py +0 -0
  172. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/features/utils.py +0 -0
  173. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/gathering/simplest.py +0 -0
  174. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/health/__init__.py +0 -0
  175. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/health/base.py +0 -0
  176. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/loggers/__init__.py +0 -0
  177. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/loggers/csv.py +0 -0
  178. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/loggers/factory.py +0 -0
  179. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/loggers/inmemory.py +0 -0
  180. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/loggers/mongo.py +0 -0
  181. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/math/__init__.py +0 -0
  182. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/math/stats.py +0 -0
  183. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/notifications/__init__.py +0 -0
  184. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/notifications/composite.py +0 -0
  185. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/notifications/slack.py +0 -0
  186. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/notifications/throttler.py +0 -0
  187. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/pandaz/__init__.py +0 -0
  188. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/pandaz/ta.py +0 -0
  189. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/_build.py +0 -0
  190. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/crypto-fees.ini +0 -0
  191. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
  192. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
  193. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
  194. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
  195. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
  196. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
  197. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
  198. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
  199. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
  200. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
  201. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
  202. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restarts/__init__.py +0 -0
  203. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restarts/state_resolvers.py +0 -0
  204. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restarts/time_finders.py +0 -0
  205. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/__init__.py +0 -0
  206. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/balance.py +0 -0
  207. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/factory.py +0 -0
  208. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/interfaces.py +0 -0
  209. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/position.py +0 -0
  210. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/signal.py +0 -0
  211. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/state.py +0 -0
  212. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/restorers/utils.py +0 -0
  213. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/ta/__init__.py +0 -0
  214. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/ta/indicators.pxd +0 -0
  215. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/ta/indicators.pyi +0 -0
  216. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/ta/indicators.pyx +0 -0
  217. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/__init__.py +0 -0
  218. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/base.py +0 -0
  219. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/accounts.toml.j2 +0 -0
  220. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/config.yml.j2 +0 -0
  221. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/jlive.sh.j2 +0 -0
  222. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
  223. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
  224. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
  225. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
  226. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/project/template.yml +0 -0
  227. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/__init__.py.j2 +0 -0
  228. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
  229. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/config.yml.j2 +0 -0
  230. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
  231. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
  232. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/strategy.py.j2 +0 -0
  233. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/templates/simple/template.yml +0 -0
  234. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/__init__.py +0 -0
  235. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/advanced.py +0 -0
  236. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/composite.py +0 -0
  237. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/rebalancers.py +0 -0
  238. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/riskctrl.py +0 -0
  239. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/trackers/sizers.py +0 -0
  240. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/__init__.py +0 -0
  241. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/_pyxreloader.py +0 -0
  242. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/charting/lookinglass.py +0 -0
  243. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  244. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/charting/orderbook.py +0 -0
  245. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/collections.py +0 -0
  246. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/marketdata/binance.py +0 -0
  247. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/marketdata/ccxt.py +0 -0
  248. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/marketdata/dukas.py +0 -0
  249. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/misc.py +0 -0
  250. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/ntp.py +0 -0
  251. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/numbers_utils.py +0 -0
  252. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/orderbook.py +0 -0
  253. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/__init__.py +0 -0
  254. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/dashboard.py +0 -0
  255. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/data.py +0 -0
  256. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/interfaces.py +0 -0
  257. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  258. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  259. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/questdb.py +0 -0
  260. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/__init__.py +0 -0
  261. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  262. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/runner/factory.py +0 -0
  263. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/time.py +0 -0
  264. {qubx-0.6.91 → qubx-0.6.93}/src/qubx/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Qubx
3
- Version: 0.6.91
3
+ Version: 0.6.93
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  License-File: LICENSE
6
6
  Author: Dmitry Marienko
@@ -24,6 +24,7 @@ Requires-Dist: ipywidgets (>=8.1.5,<9.0.0)
24
24
  Requires-Dist: jinja2 (>=3.1.0,<4.0.0)
25
25
  Requires-Dist: jupyter (>=1.1.1,<2.0.0)
26
26
  Requires-Dist: jupyter-console (>=6.6.3,<7.0.0)
27
+ Requires-Dist: lighter-sdk (>=0.1.4,<0.2.0)
27
28
  Requires-Dist: loguru (>=0.7.2,<0.8.0)
28
29
  Requires-Dist: matplotlib (>=3.8.4,<4.0.0)
29
30
  Requires-Dist: msgspec (>=0.18.6,<0.19.0)
@@ -52,7 +53,9 @@ Requires-Dist: sortedcontainers (>=2.4.0,<3.0.0)
52
53
  Requires-Dist: stackprinter (>=0.2.10,<0.3.0)
53
54
  Requires-Dist: statsmodels (>=0.14.2,<0.15.0)
54
55
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
55
- Requires-Dist: textual (>=0.88.0,<0.89.0)
56
+ Requires-Dist: textual-autocomplete (>=4.0.0,<5.0.0)
57
+ Requires-Dist: textual-serve (>=1.0.0,<2.0.0)
58
+ Requires-Dist: textual[syntax] (>=6.0.0,<7.0.0)
56
59
  Requires-Dist: toml (>=0.10.2,<0.11.0)
57
60
  Requires-Dist: tqdm
58
61
  Requires-Dist: websockets (==15.0.1)
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "Qubx"
7
- version = "0.6.91"
7
+ version = "0.6.93"
8
8
  description = "Qubx - Quantitative Trading Framework"
9
9
  authors = [ "Dmitry Marienko <dmitry.marienko@xlydian.com>", "Yuriy Arabskyy <yuriy.arabskyy@xlydian.com>",]
10
10
  readme = "README.md"
@@ -74,9 +74,11 @@ orjson = "^3.10.15"
74
74
  aiohttp = "~3.10.11"
75
75
  websockets = "15.0.1"
76
76
  qubx-bitfinex-api = "^3.0.7"
77
- textual = "^0.88.0"
77
+ textual-autocomplete = "^4.0.0"
78
+ textual-serve = "^1.0.0"
78
79
  rich = "^13.9.4"
79
80
  jinja2 = "^3.1.0"
81
+ lighter-sdk = "^0.1.4"
80
82
 
81
83
  [tool.ruff.lint]
82
84
  extend-select = [ "I",]
@@ -90,6 +92,10 @@ markers = [ "integration: mark test as requiring external services like Redis",
90
92
  addopts = "--disable-warnings"
91
93
  filterwarnings = [ "ignore:.*Jupyter is migrating.*:DeprecationWarning", "ignore:coroutine.*AsyncMockMixin._execute_mock_call.*was never awaited:RuntimeWarning",]
92
94
 
95
+ [tool.poetry.dependencies.textual]
96
+ extras = [ "syntax",]
97
+ version = "^6.0.0"
98
+
93
99
  [tool.ruff.lint.extend-per-file-ignores]
94
100
  "*.ipynb" = [ "F405", "F401", "E701", "E402", "F403", "E401", "E702", "I001",]
95
101
 
@@ -120,6 +126,7 @@ pytest-mock = "^3.12.0"
120
126
  pytest-lazy-fixture = "^0.6.3"
121
127
  pytest-cov = "^4.1.0"
122
128
  mongomock = "^4.3.0"
129
+ pytest-textual-snapshot = "^1.1.0"
123
130
 
124
131
  [tool.poetry.group.k8.dependencies]
125
132
  prometheus-client = "^0.21.1"
@@ -1,6 +1,7 @@
1
1
  import re
2
2
  import zipfile
3
3
  from collections import defaultdict
4
+ from os.path import expanduser
4
5
  from pathlib import Path
5
6
 
6
7
  import numpy as np
@@ -39,7 +40,7 @@ class BacktestsResultsManager:
39
40
  """
40
41
 
41
42
  def __init__(self, path: str):
42
- self.path = path
43
+ self.path = expanduser(path)
43
44
  self.reload()
44
45
 
45
46
  def reload(self) -> "BacktestsResultsManager":
@@ -72,11 +72,29 @@ def main(debug: bool, debug_port: int, log_level: str):
72
72
  @click.option(
73
73
  "--textual", "-t", is_flag=True, default=False, help="Run strategy in textual TUI.", show_default=True
74
74
  )
75
+ @click.option(
76
+ "--textual-dev", is_flag=True, default=False, help="Enable Textual dev mode (use with 'textual console').", show_default=True
77
+ )
78
+ @click.option(
79
+ "--textual-web", is_flag=True, default=False, help="Serve Textual app in web browser.", show_default=True
80
+ )
81
+ @click.option(
82
+ "--textual-port", type=int, default=None, help="Port for Textual (web server: 8000, devtools: 8081).", show_default=False
83
+ )
84
+ @click.option(
85
+ "--textual-host", type=str, default="0.0.0.0", help="Host for Textual web server.", show_default=True
86
+ )
87
+ @click.option(
88
+ "--kernel-only", is_flag=True, default=False, help="Start kernel without UI (returns connection file).", show_default=True
89
+ )
90
+ @click.option(
91
+ "--connect", type=Path, default=None, help="Connect to existing kernel via connection file.", show_default=False
92
+ )
75
93
  @click.option(
76
94
  "--restore", "-r", is_flag=True, default=False, help="Restore strategy state from previous run.", show_default=True
77
95
  )
78
96
  @click.option("--no-color", is_flag=True, default=False, help="Disable colored logging output.", show_default=True)
79
- def run(config_file: Path, account_file: Path | None, paper: bool, jupyter: bool, textual: bool, restore: bool, no_color: bool):
97
+ def run(config_file: Path, account_file: Path | None, paper: bool, jupyter: bool, textual: bool, textual_dev: bool, textual_web: bool, textual_port: int | None, textual_host: str, kernel_only: bool, connect: Path | None, restore: bool, no_color: bool):
80
98
  """
81
99
  Starts the strategy with the given configuration file. If paper mode is enabled, account is not required.
82
100
 
@@ -94,6 +112,39 @@ def run(config_file: Path, account_file: Path | None, paper: bool, jupyter: bool
94
112
  click.echo("Error: --jupyter and --textual cannot be used together.", err=True)
95
113
  raise click.Abort()
96
114
 
115
+ # Handle --kernel-only mode
116
+ if kernel_only:
117
+ import asyncio
118
+
119
+ from qubx.utils.runner.kernel_service import KernelService
120
+
121
+ add_project_to_system_path()
122
+ add_project_to_system_path(str(config_file.parent.parent))
123
+ add_project_to_system_path(str(config_file.parent))
124
+
125
+ click.echo("Starting persistent kernel...")
126
+ connection_file = asyncio.run(KernelService.start(config_file, account_file, paper, restore))
127
+ click.echo(click.style("✓ Kernel started successfully!", fg="green", bold=True))
128
+ click.echo(click.style(f"Connection file: {connection_file}", fg="cyan"))
129
+ click.echo()
130
+ click.echo("To connect a UI to this kernel:")
131
+ click.echo(f" qubx run --textual --connect {connection_file}")
132
+ click.echo()
133
+ click.echo("To stop this kernel:")
134
+ click.echo(f" qubx kernel stop {connection_file}")
135
+ click.echo()
136
+ click.echo("Press Ctrl+C to stop the kernel and exit...")
137
+
138
+ # Keep the process alive until interrupted
139
+ try:
140
+ import signal
141
+ signal.pause()
142
+ except KeyboardInterrupt:
143
+ click.echo("\nShutting down kernel...")
144
+ asyncio.run(KernelService.stop(connection_file))
145
+ click.echo("Kernel stopped.")
146
+ return
147
+
97
148
  add_project_to_system_path()
98
149
  add_project_to_system_path(str(config_file.parent.parent))
99
150
  add_project_to_system_path(str(config_file.parent))
@@ -101,7 +152,7 @@ def run(config_file: Path, account_file: Path | None, paper: bool, jupyter: bool
101
152
  if jupyter:
102
153
  run_strategy_yaml_in_jupyter(config_file, account_file, paper, restore)
103
154
  elif textual:
104
- run_strategy_yaml_in_textual(config_file, account_file, paper, restore)
155
+ run_strategy_yaml_in_textual(config_file, account_file, paper, restore, textual_dev, textual_web, textual_port, textual_host, connect)
105
156
  else:
106
157
  logo()
107
158
  run_strategy_yaml(config_file, account_file, paper=paper, restore=restore, blocking=True, no_color=no_color)
@@ -461,5 +512,69 @@ def init(
461
512
  raise click.Abort()
462
513
 
463
514
 
515
+ @main.group()
516
+ def kernel():
517
+ """
518
+ Manage persistent Jupyter kernels for strategy execution.
519
+
520
+ Kernels can be started independently of the UI, allowing multiple
521
+ UI instances to connect to the same running strategy.
522
+ """
523
+ pass
524
+
525
+
526
+ @kernel.command("list")
527
+ def kernel_list():
528
+ """
529
+ List all active kernel sessions.
530
+
531
+ Shows connection files and associated strategy configurations
532
+ for all currently running kernels.
533
+ """
534
+ from qubx.utils.runner.kernel_service import KernelService
535
+
536
+ active = KernelService.list_active()
537
+
538
+ if not active:
539
+ click.echo("No active kernels found.")
540
+ return
541
+
542
+ import datetime
543
+
544
+ click.echo(click.style("Active Kernels:", fg="cyan", bold=True))
545
+ click.echo()
546
+ for i, kernel_info in enumerate(active, 1):
547
+ # Format timestamp
548
+ ts = datetime.datetime.fromtimestamp(kernel_info["timestamp"])
549
+ time_str = ts.strftime("%Y-%m-%d %H:%M:%S")
550
+
551
+ click.echo(f"{i}. {click.style('Strategy:', fg='yellow')} {kernel_info['strategy_name']}")
552
+ click.echo(f" {click.style('Started:', fg='yellow')} {time_str}")
553
+ click.echo(f" {click.style('Connection:', fg='yellow')} {kernel_info['connection_file']}")
554
+ click.echo()
555
+
556
+
557
+ @kernel.command("stop")
558
+ @click.argument("connection-file", type=Path, required=True)
559
+ def kernel_stop(connection_file: Path):
560
+ """
561
+ Stop a running kernel by its connection file.
562
+
563
+ This will gracefully shutdown the kernel and clean up
564
+ the connection file.
565
+ """
566
+ import asyncio
567
+
568
+ from qubx.utils.runner.kernel_service import KernelService
569
+
570
+ if not connection_file.exists():
571
+ click.echo(click.style(f"✗ Connection file not found: {connection_file}", fg="red"))
572
+ raise click.Abort()
573
+
574
+ click.echo(f"Stopping kernel: {connection_file}")
575
+ asyncio.run(KernelService.stop(str(connection_file)))
576
+ click.echo(click.style("✓ Kernel stopped successfully", fg="green"))
577
+
578
+
464
579
  if __name__ == "__main__":
465
580
  main()
@@ -8,8 +8,8 @@ from qubx.core.basics import CtrlChannel
8
8
  from qubx.core.interfaces import IAccountProcessor, IBroker, IDataProvider, ITimeProvider
9
9
 
10
10
  from .account import CcxtAccountProcessor
11
- from .exchanges import CUSTOM_ACCOUNTS, CUSTOM_BROKERS, EXCHANGE_ALIASES
12
11
  from .exchange_manager import ExchangeManager
12
+ from .exchanges import CUSTOM_ACCOUNTS, CUSTOM_BROKERS, EXCHANGE_ALIASES
13
13
 
14
14
 
15
15
  def get_ccxt_exchange(
@@ -22,10 +22,10 @@ def get_ccxt_exchange(
22
22
  ) -> cxp.Exchange:
23
23
  """
24
24
  Get a raw CCXT exchange object.
25
-
25
+
26
26
  Creates and configures a CCXT exchange instance without any stability wrapper.
27
27
  Use get_ccxt_exchange_manager() if you need automatic stability management.
28
-
28
+
29
29
  Parameters:
30
30
  exchange (str): The exchange name.
31
31
  api_key (str, optional): The API key. Default is None.
@@ -33,7 +33,7 @@ def get_ccxt_exchange(
33
33
  loop (asyncio.AbstractEventLoop, optional): Event loop. Default is None.
34
34
  use_testnet (bool): Use testnet/sandbox mode. Default is False.
35
35
  **kwargs: Additional parameters for exchange configuration.
36
-
36
+
37
37
  Returns:
38
38
  Raw CCXT Exchange instance
39
39
  """
@@ -90,10 +90,10 @@ def get_ccxt_exchange_manager(
90
90
  ) -> ExchangeManager:
91
91
  """
92
92
  Get a CCXT exchange with automatic stability management.
93
-
93
+
94
94
  Returns ExchangeManager wrapper that handles exchange recreation
95
95
  during data stall scenarios via self-monitoring.
96
-
96
+
97
97
  Parameters:
98
98
  exchange (str): The exchange name.
99
99
  api_key (str, optional): The API key. Default is None.
@@ -102,28 +102,23 @@ def get_ccxt_exchange_manager(
102
102
  use_testnet (bool): Use testnet/sandbox mode. Default is False.
103
103
  check_interval_seconds (float): How often to check for stalls. Default is 30.0.
104
104
  **kwargs: Additional parameters for exchange configuration.
105
-
105
+
106
106
  Returns:
107
107
  ExchangeManager wrapping the CCXT Exchange
108
108
  """
109
109
  # Prepare factory parameters for ExchangeManager recreation
110
110
  factory_params = {
111
- 'exchange': exchange,
112
- 'api_key': api_key,
113
- 'secret': secret,
114
- 'loop': loop,
115
- 'use_testnet': use_testnet,
116
- **{k: v for k, v in kwargs.items() if k != 'check_interval_seconds'}
111
+ "exchange": exchange,
112
+ "api_key": api_key,
113
+ "secret": secret,
114
+ "loop": loop,
115
+ "use_testnet": use_testnet,
116
+ **{k: v for k, v in kwargs.items() if k != "check_interval_seconds"},
117
117
  }
118
-
118
+
119
119
  # Create raw CCXT exchange using public factory method
120
120
  ccxt_exchange = get_ccxt_exchange(
121
- exchange=exchange,
122
- api_key=api_key,
123
- secret=secret,
124
- loop=loop,
125
- use_testnet=use_testnet,
126
- **kwargs
121
+ exchange=exchange, api_key=api_key, secret=secret, loop=loop, use_testnet=use_testnet, **kwargs
127
122
  )
128
123
 
129
124
  # Wrap in ExchangeManager for stability management
@@ -0,0 +1,83 @@
1
+ """XLighter exchange connector for Qubx"""
2
+
3
+ from .account import LighterAccountProcessor
4
+ from .broker import LighterBroker
5
+ from .client import LighterClient
6
+ from .constants import (
7
+ DEDICATED_CHANNELS,
8
+ MULTIPLEX_CHANNELS,
9
+ WS_CHANNEL_ACCOUNT_ALL,
10
+ WS_CHANNEL_EXECUTED_TX,
11
+ WS_CHANNEL_MARKET_STATS,
12
+ WS_CHANNEL_ORDER_BOOK,
13
+ WS_CHANNEL_TRADE,
14
+ WS_CHANNEL_USER_STATS,
15
+ LighterMarginMode,
16
+ LighterOrderSide,
17
+ LighterOrderType,
18
+ LighterTimeInForce,
19
+ )
20
+ from .data import LighterDataProvider
21
+ from .factory import (
22
+ get_xlighter_account,
23
+ get_xlighter_broker,
24
+ get_xlighter_client,
25
+ get_xlighter_data_provider,
26
+ )
27
+ from .instruments import LighterInstrumentLoader, load_lighter_instruments
28
+ from .parsers import PositionState
29
+ from .reader import XLighterDataReader
30
+ from .utils import (
31
+ convert_lighter_order,
32
+ convert_lighter_orderbook,
33
+ convert_lighter_quote,
34
+ convert_lighter_trade,
35
+ lighter_order_side_to_qubx,
36
+ lighter_symbol_to_qubx,
37
+ qubx_order_side_to_lighter,
38
+ qubx_symbol_to_lighter,
39
+ )
40
+ from .websocket import LighterWebSocketManager
41
+
42
+ __all__ = [
43
+ # Core Components
44
+ "LighterClient",
45
+ "LighterDataProvider",
46
+ "LighterBroker",
47
+ "LighterAccountProcessor",
48
+ "LighterWebSocketManager",
49
+ # Factory Functions
50
+ "get_xlighter_client",
51
+ "get_xlighter_data_provider",
52
+ "get_xlighter_account",
53
+ "get_xlighter_broker",
54
+ # Data Reader
55
+ "XLighterDataReader",
56
+ # Instruments
57
+ "LighterInstrumentLoader",
58
+ "load_lighter_instruments",
59
+ # Parsers
60
+ "PositionState",
61
+ # Constants
62
+ "LighterOrderType",
63
+ "LighterTimeInForce",
64
+ "LighterOrderSide",
65
+ "LighterMarginMode",
66
+ "WS_CHANNEL_ORDER_BOOK",
67
+ "WS_CHANNEL_TRADE",
68
+ "WS_CHANNEL_MARKET_STATS",
69
+ "WS_CHANNEL_ACCOUNT_ALL",
70
+ "WS_CHANNEL_USER_STATS",
71
+ "WS_CHANNEL_EXECUTED_TX",
72
+ "MULTIPLEX_CHANNELS",
73
+ "DEDICATED_CHANNELS",
74
+ # Utils
75
+ "lighter_symbol_to_qubx",
76
+ "qubx_symbol_to_lighter",
77
+ "lighter_order_side_to_qubx",
78
+ "qubx_order_side_to_lighter",
79
+ "convert_lighter_orderbook",
80
+ "convert_lighter_trade",
81
+ "convert_lighter_quote",
82
+ "convert_lighter_order",
83
+ ]