Qubx 0.6.48__tar.gz → 0.6.49__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 (165) hide show
  1. {qubx-0.6.48 → qubx-0.6.49}/PKG-INFO +1 -1
  2. {qubx-0.6.48 → qubx-0.6.49}/pyproject.toml +1 -1
  3. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/universe.py +13 -20
  4. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/readers.py +103 -17
  5. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/runner.py +5 -1
  6. {qubx-0.6.48 → qubx-0.6.49}/LICENSE +0 -0
  7. {qubx-0.6.48 → qubx-0.6.49}/README.md +0 -0
  8. {qubx-0.6.48 → qubx-0.6.49}/build.py +0 -0
  9. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/__init__.py +0 -0
  10. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/_nb_magic.py +0 -0
  11. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/__init__.py +0 -0
  12. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/account.py +0 -0
  13. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/broker.py +0 -0
  14. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/data.py +0 -0
  15. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/management.py +0 -0
  16. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/ome.py +0 -0
  17. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/optimization.py +0 -0
  18. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/runner.py +0 -0
  19. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/simulated_data.py +0 -0
  20. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/simulated_exchange.py +0 -0
  21. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/simulator.py +0 -0
  22. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/backtester/utils.py +0 -0
  23. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/__init__.py +0 -0
  24. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/commands.py +0 -0
  25. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/deploy.py +0 -0
  26. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/misc.py +0 -0
  27. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/release.py +0 -0
  28. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/cli/tui.py +0 -0
  29. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/__init__.py +0 -0
  30. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/account.py +0 -0
  31. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/broker.py +0 -0
  32. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/data.py +0 -0
  33. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  34. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
  35. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  36. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  37. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
  38. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  39. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  40. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/factory.py +0 -0
  41. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/reader.py +0 -0
  42. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/ccxt/utils.py +0 -0
  43. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/tardis/data.py +0 -0
  44. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/connectors/tardis/utils.py +0 -0
  45. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/__init__.py +0 -0
  46. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/account.py +0 -0
  47. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/basics.py +0 -0
  48. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/context.py +0 -0
  49. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/deque.py +0 -0
  50. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/errors.py +0 -0
  51. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/exceptions.py +0 -0
  52. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/helpers.py +0 -0
  53. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/initializer.py +0 -0
  54. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/interfaces.py +0 -0
  55. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/loggers.py +0 -0
  56. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/lookups.py +0 -0
  57. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/metrics.py +0 -0
  58. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/__init__.py +0 -0
  59. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/market.py +0 -0
  60. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/processing.py +0 -0
  61. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/subscription.py +0 -0
  62. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/mixins/trading.py +0 -0
  63. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/series.pxd +0 -0
  64. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/series.pyi +0 -0
  65. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/series.pyx +0 -0
  66. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/utils.pyi +0 -0
  67. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/core/utils.pyx +0 -0
  68. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/__init__.py +0 -0
  69. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/composite.py +0 -0
  70. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/helpers.py +0 -0
  71. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/hft.py +0 -0
  72. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/registry.py +0 -0
  73. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/data/tardis.py +0 -0
  74. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/__init__.py +0 -0
  75. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/base.py +0 -0
  76. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/composite.py +0 -0
  77. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/csv.py +0 -0
  78. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/prometheus.py +0 -0
  79. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/emitters/questdb.py +0 -0
  80. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/__init__.py +0 -0
  81. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/composite.py +0 -0
  82. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/formatters/__init__.py +0 -0
  83. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/formatters/base.py +0 -0
  84. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/formatters/incremental.py +0 -0
  85. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/formatters/slack.py +0 -0
  86. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/redis_streams.py +0 -0
  87. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/exporters/slack.py +0 -0
  88. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/__init__.py +0 -0
  89. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/core.py +0 -0
  90. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/orderbook.py +0 -0
  91. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/price.py +0 -0
  92. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/trades.py +0 -0
  93. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/features/utils.py +0 -0
  94. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/gathering/simplest.py +0 -0
  95. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/health/__init__.py +0 -0
  96. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/health/base.py +0 -0
  97. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/loggers/__init__.py +0 -0
  98. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/loggers/csv.py +0 -0
  99. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/loggers/factory.py +0 -0
  100. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/loggers/inmemory.py +0 -0
  101. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/loggers/mongo.py +0 -0
  102. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/math/__init__.py +0 -0
  103. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/math/stats.py +0 -0
  104. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/notifications/__init__.py +0 -0
  105. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/notifications/composite.py +0 -0
  106. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/notifications/slack.py +0 -0
  107. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/notifications/throttler.py +0 -0
  108. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/pandaz/__init__.py +0 -0
  109. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/pandaz/ta.py +0 -0
  110. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/pandaz/utils.py +0 -0
  111. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/_build.py +0 -0
  112. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-binance.cm.json +0 -0
  113. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-binance.json +0 -0
  114. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-binance.um.json +0 -0
  115. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-bitfinex.f.json +0 -0
  116. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-bitfinex.json +0 -0
  117. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-kraken.f.json +0 -0
  118. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/resources/instruments/symbols-kraken.json +0 -0
  119. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restarts/__init__.py +0 -0
  120. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restarts/state_resolvers.py +0 -0
  121. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restarts/time_finders.py +0 -0
  122. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/__init__.py +0 -0
  123. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/balance.py +0 -0
  124. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/factory.py +0 -0
  125. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/interfaces.py +0 -0
  126. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/position.py +0 -0
  127. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/signal.py +0 -0
  128. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/state.py +0 -0
  129. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/restorers/utils.py +0 -0
  130. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/ta/__init__.py +0 -0
  131. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/ta/indicators.pxd +0 -0
  132. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/ta/indicators.pyi +0 -0
  133. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/ta/indicators.pyx +0 -0
  134. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/__init__.py +0 -0
  135. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/advanced.py +0 -0
  136. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/composite.py +0 -0
  137. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/rebalancers.py +0 -0
  138. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/riskctrl.py +0 -0
  139. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/trackers/sizers.py +0 -0
  140. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/__init__.py +0 -0
  141. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/_pyxreloader.py +0 -0
  142. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/charting/lookinglass.py +0 -0
  143. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  144. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/collections.py +0 -0
  145. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/marketdata/binance.py +0 -0
  146. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/marketdata/ccxt.py +0 -0
  147. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/marketdata/dukas.py +0 -0
  148. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/misc.py +0 -0
  149. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/ntp.py +0 -0
  150. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/numbers_utils.py +0 -0
  151. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/orderbook.py +0 -0
  152. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/__init__.py +0 -0
  153. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/dashboard.py +0 -0
  154. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/data.py +0 -0
  155. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/interfaces.py +0 -0
  156. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  157. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  158. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/questdb.py +0 -0
  159. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/__init__.py +0 -0
  160. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  161. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/accounts.py +0 -0
  162. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/configs.py +0 -0
  163. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/runner/factory.py +0 -0
  164. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/time.py +0 -0
  165. {qubx-0.6.48 → qubx-0.6.49}/src/qubx/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Qubx
3
- Version: 0.6.48
3
+ Version: 0.6.49
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Author: Dmitry Marienko
6
6
  Author-email: dmitry.marienko@xlydian.com
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "Qubx"
7
- version = "0.6.48"
7
+ version = "0.6.49"
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"
@@ -2,8 +2,6 @@ from qubx.core.basics import DataType, Instrument, TargetPosition
2
2
  from qubx.core.helpers import CachedMarketDataHolder
3
3
  from qubx.core.interfaces import (
4
4
  IAccountProcessor,
5
- IBroker,
6
- IDataProvider,
7
5
  IPositionGathering,
8
6
  IStrategy,
9
7
  IStrategyContext,
@@ -14,7 +12,6 @@ from qubx.core.interfaces import (
14
12
  RemovalPolicy,
15
13
  )
16
14
  from qubx.core.loggers import StrategyLogging
17
- from qubx.core.lookups import lookup
18
15
 
19
16
 
20
17
  class UniverseManager(IUniverseManager):
@@ -50,7 +47,7 @@ class UniverseManager(IUniverseManager):
50
47
  self._time_provider = time_provider
51
48
  self._account = account
52
49
  self._position_gathering = position_gathering
53
- self._instruments = []
50
+ self._instruments = set()
54
51
  self._removal_queue = {}
55
52
 
56
53
  def _has_position(self, instrument: Instrument) -> bool:
@@ -72,7 +69,7 @@ class UniverseManager(IUniverseManager):
72
69
  ), "Invalid if_has_position_then policy"
73
70
 
74
71
  new_set = set(instruments)
75
- prev_set = set(self._instruments)
72
+ prev_set = self._instruments.copy()
76
73
 
77
74
  # - determine instruments to remove depending on if_has_position_then policy
78
75
  may_be_removed = list(prev_set - new_set)
@@ -93,9 +90,7 @@ class UniverseManager(IUniverseManager):
93
90
  self._subscription_manager.commit() # apply pending changes
94
91
 
95
92
  # set new instruments
96
- self._instruments.clear()
97
- self._instruments.extend(instruments)
98
- self._instruments.extend(to_keep)
93
+ self._instruments = new_set | set(to_keep)
99
94
 
100
95
  def _get_what_can_be_removed_or_kept(
101
96
  self, may_be_removed: list[Instrument], skip_callback: bool, if_has_position_then: RemovalPolicy
@@ -105,12 +100,11 @@ class UniverseManager(IUniverseManager):
105
100
  for instr in may_be_removed:
106
101
  if immediately_close:
107
102
  to_remove.append(instr)
103
+ elif self._has_position(instr):
104
+ self._removal_queue[instr] = (if_has_position_then, skip_callback)
105
+ to_keep.append(instr)
108
106
  else:
109
- if self._has_position(instr):
110
- self._removal_queue[instr] = (if_has_position_then, skip_callback)
111
- to_keep.append(instr)
112
- else:
113
- to_remove.append(instr)
107
+ to_remove.append(instr)
114
108
  return to_remove, to_keep
115
109
 
116
110
  def __cleanup_removal_queue(self, instruments: list[Instrument]):
@@ -124,7 +118,7 @@ class UniverseManager(IUniverseManager):
124
118
  self.__cleanup_removal_queue(instruments)
125
119
  self._strategy.on_universe_change(self._context, instruments, [])
126
120
  self._subscription_manager.commit()
127
- self._instruments.extend(instruments)
121
+ self._instruments.update(instruments)
128
122
 
129
123
  def remove_instruments(
130
124
  self,
@@ -146,12 +140,11 @@ class UniverseManager(IUniverseManager):
146
140
  self._subscription_manager.commit()
147
141
 
148
142
  # - update instruments list
149
- self._instruments = list(set(self._instruments) - set(to_remove))
150
- self._instruments.extend(to_keep)
143
+ self._instruments = (self._instruments - set(to_remove)) | set(to_keep)
151
144
 
152
145
  @property
153
146
  def instruments(self) -> list[Instrument]:
154
- return self._instruments
147
+ return list(self._instruments)
155
148
 
156
149
  def __do_remove_instruments(self, instruments: list[Instrument]):
157
150
  """
@@ -227,7 +220,7 @@ class UniverseManager(IUniverseManager):
227
220
  # if aux is not None:
228
221
  # instrument._aux_instrument = aux
229
222
  # instruments.append(aux)
230
- # _ = self._trading_service.get_position(aux)
223
+ # _ = self._account.get_position(aux)
231
224
 
232
225
  def on_alter_position(self, instrument: Instrument) -> None:
233
226
  """
@@ -247,7 +240,7 @@ class UniverseManager(IUniverseManager):
247
240
 
248
241
  # - commit changes and remove instrument from the universe
249
242
  self._subscription_manager.commit()
250
- self._instruments.remove(instrument)
243
+ self._instruments.discard(instrument)
251
244
 
252
245
  def is_trading_allowed(self, instrument: Instrument) -> bool:
253
246
  if instrument in self._removal_queue:
@@ -261,7 +254,7 @@ class UniverseManager(IUniverseManager):
261
254
 
262
255
  # - commit changes and remove instrument from the universe
263
256
  self._subscription_manager.commit()
264
- self._instruments.remove(instrument)
257
+ self._instruments.discard(instrument)
265
258
  return False
266
259
 
267
260
  return True
@@ -1054,7 +1054,7 @@ def _retry(fn):
1054
1054
  # print(x, cls._reconnect_tries)
1055
1055
  try:
1056
1056
  return fn(*args, **kw)
1057
- except (pg.InterfaceError, pg.OperationalError, AttributeError) as e:
1057
+ except (pg.InterfaceError, pg.OperationalError, AttributeError):
1058
1058
  logger.debug("Database Connection [InterfaceError or OperationalError]")
1059
1059
  # print ("Idle for %s seconds" % (cls._reconnect_idle))
1060
1060
  # time.sleep(cls._reconnect_idle)
@@ -1063,6 +1063,75 @@ def _retry(fn):
1063
1063
  return wrapper
1064
1064
 
1065
1065
 
1066
+ def _calculate_max_candles_chunksize(timeframe: str | None) -> int:
1067
+ """
1068
+ Calculate maximum chunksize for candles data based on timeframe.
1069
+ Limits to at most 1 week of data for candles_1m data type.
1070
+
1071
+ Args:
1072
+ timeframe: Timeframe string (e.g., "1m", "5m", "1h", "1d")
1073
+
1074
+ Returns:
1075
+ Maximum number of candles representing 1 week of data
1076
+ """
1077
+ if not timeframe:
1078
+ return 10080 # Default to 1 week of 1-minute candles
1079
+
1080
+ try:
1081
+ # Convert timeframe to pandas Timedelta
1082
+ tf_delta = pd.Timedelta(timeframe)
1083
+
1084
+ # Calculate how many candles fit in 1 week
1085
+ one_week = pd.Timedelta("7d")
1086
+ max_candles = int(one_week / tf_delta)
1087
+
1088
+ # Ensure we don't return 0 or negative values
1089
+ return max(1, max_candles)
1090
+ except (ValueError, TypeError):
1091
+ # If timeframe can't be parsed, default to 1 week of 1-minute candles
1092
+ return 10080
1093
+
1094
+
1095
+ def _calculate_time_windows_for_chunking(
1096
+ start: str | None, end: str | None, timeframe: str, chunksize: int
1097
+ ) -> list[tuple[pd.Timestamp, pd.Timestamp]]:
1098
+ """
1099
+ Calculate time windows for efficient chunking based on timeframe and chunksize.
1100
+
1101
+ Args:
1102
+ start: Start time string
1103
+ end: End time string
1104
+ timeframe: Timeframe string (e.g., "1m", "5m", "1h")
1105
+ chunksize: Number of candles per chunk
1106
+
1107
+ Returns:
1108
+ List of (start_time, end_time) tuples for each chunk
1109
+ """
1110
+ if not start or not end:
1111
+ return []
1112
+
1113
+ start_dt = pd.Timestamp(start)
1114
+ end_dt = pd.Timestamp(end)
1115
+
1116
+ try:
1117
+ # Calculate time period per chunk based on timeframe and chunksize
1118
+ tf_delta = pd.Timedelta(timeframe)
1119
+ chunk_duration = tf_delta * chunksize
1120
+
1121
+ windows = []
1122
+ current_start = start_dt
1123
+
1124
+ while current_start < end_dt:
1125
+ current_end = min(current_start + chunk_duration, end_dt)
1126
+ windows.append((current_start, current_end))
1127
+ current_start = current_end
1128
+
1129
+ return windows
1130
+ except (ValueError, TypeError):
1131
+ # If timeframe can't be parsed, fall back to single window
1132
+ return [(start_dt, end_dt)]
1133
+
1134
+
1066
1135
  class QuestDBSqlBuilder:
1067
1136
  """
1068
1137
  Generic sql builder for QuestDB data
@@ -1387,28 +1456,46 @@ class QuestDBConnector(DataReader):
1387
1456
  data_type: str,
1388
1457
  builder: QuestDBSqlBuilder,
1389
1458
  ) -> Any:
1390
- start, end = handle_start_stop(start, stop)
1391
- _req = builder.prepare_data_sql(data_id, start, end, timeframe, data_type)
1459
+ # Apply maximum chunksize limits for candles_1m data type when timeframe is provided
1460
+ if chunksize > 0 and data_type == "candles_1m" and timeframe:
1461
+ max_chunksize = _calculate_max_candles_chunksize(timeframe)
1462
+ chunksize = min(chunksize, max_chunksize)
1392
1463
 
1393
- _cursor = self._connection.cursor() # type: ignore
1394
- _cursor.execute(_req) # type: ignore
1395
- names = [d.name for d in _cursor.description] # type: ignore
1464
+ start, end = handle_start_stop(start, stop)
1465
+ # If timeframe is not specified, assume 1 minute as default
1466
+ effective_timeframe = timeframe or "1m"
1396
1467
 
1397
1468
  if chunksize > 0:
1469
+ # Use efficient chunking with multiple smaller queries
1470
+ def _iter_efficient_chunks():
1471
+ time_windows = _calculate_time_windows_for_chunking(start, end, effective_timeframe, chunksize)
1472
+ _cursor = self._connection.cursor() # type: ignore
1398
1473
 
1399
- def _iter_chunks():
1400
- while True:
1401
- records = _cursor.fetchmany(chunksize)
1402
- if not records:
1403
- _cursor.close()
1404
- break
1405
- transform.start_transform(data_id, names, start=start, stop=stop)
1406
- transform.process_data(records)
1407
- yield transform.collect()
1474
+ try:
1475
+ for window_start, window_end in time_windows:
1476
+ _req = builder.prepare_data_sql(
1477
+ data_id, str(window_start), str(window_end), effective_timeframe, data_type
1478
+ )
1408
1479
 
1409
- return _iter_chunks()
1480
+ _cursor.execute(_req) # type: ignore
1481
+ names = [d.name for d in _cursor.description] # type: ignore
1482
+ records = _cursor.fetchall()
1483
+
1484
+ if records:
1485
+ transform.start_transform(data_id, names, start=start, stop=stop)
1486
+ transform.process_data(records)
1487
+ yield transform.collect()
1488
+ finally:
1489
+ _cursor.close()
1410
1490
 
1491
+ return _iter_efficient_chunks()
1492
+
1493
+ # No chunking requested - return all data at once
1494
+ _req = builder.prepare_data_sql(data_id, start, end, effective_timeframe, data_type)
1495
+ _cursor = self._connection.cursor() # type: ignore
1411
1496
  try:
1497
+ _cursor.execute(_req) # type: ignore
1498
+ names = [d.name for d in _cursor.description] # type: ignore
1412
1499
  records = _cursor.fetchall()
1413
1500
  if not records:
1414
1501
  return None
@@ -1481,7 +1568,6 @@ class QuestDBSqlOrderBookBuilder(QuestDBSqlCandlesBuilder):
1481
1568
  if not start or not end:
1482
1569
  raise ValueError("Start and end dates must be provided for orderbook data!")
1483
1570
  start_dt, end_dt = pd.Timestamp(start), pd.Timestamp(end)
1484
- delta = end_dt - start_dt
1485
1571
 
1486
1572
  raw_start_dt = start_dt.floor(self.SNAPSHOT_DELTA) - self.MIN_DELTA
1487
1573
 
@@ -681,11 +681,15 @@ def _run_warmup(
681
681
  # - create a restored state based on warmup runner context
682
682
  warmup_account = warmup_runner.ctx.account
683
683
 
684
+ # - get the instruments from the warmup runner context
685
+ _instruments = warmup_runner.ctx.instruments
684
686
  _positions = warmup_account.get_positions()
687
+ _positions = {k: v for k, v in _positions.items() if k in _instruments}
685
688
  _orders = warmup_account.get_orders()
686
689
  instrument_to_orders = defaultdict(list)
687
690
  for o in _orders.values():
688
- instrument_to_orders[o.instrument].append(o)
691
+ if o.instrument in _instruments:
692
+ instrument_to_orders[o.instrument].append(o)
689
693
 
690
694
  # - set the warmup positions and orders
691
695
  ctx.set_warmup_positions(_positions)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes