Qubx 0.6.71__cp312-cp312-manylinux_2_39_x86_64.whl → 0.6.73__cp312-cp312-manylinux_2_39_x86_64.whl

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 (45) hide show
  1. qubx/backtester/data.py +16 -6
  2. qubx/backtester/runner.py +7 -4
  3. qubx/connectors/ccxt/adapters/polling_adapter.py +151 -343
  4. qubx/connectors/ccxt/connection_manager.py +122 -133
  5. qubx/connectors/ccxt/data.py +108 -43
  6. qubx/connectors/ccxt/exchanges/__init__.py +26 -0
  7. qubx/connectors/ccxt/exchanges/base.py +63 -0
  8. qubx/connectors/ccxt/exchanges/binance/exchange.py +186 -166
  9. qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +3 -1
  10. qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +6 -1
  11. qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +69 -0
  12. qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +385 -27
  13. qubx/connectors/ccxt/exchanges/kraken/kraken.py +3 -1
  14. qubx/connectors/ccxt/factory.py +4 -0
  15. qubx/connectors/ccxt/handlers/base.py +2 -1
  16. qubx/connectors/ccxt/handlers/funding_rate.py +88 -88
  17. qubx/connectors/ccxt/handlers/liquidation.py +1 -0
  18. qubx/connectors/ccxt/handlers/ohlc.py +63 -45
  19. qubx/connectors/ccxt/handlers/open_interest.py +12 -13
  20. qubx/connectors/ccxt/handlers/orderbook.py +65 -39
  21. qubx/connectors/ccxt/handlers/quote.py +3 -1
  22. qubx/connectors/ccxt/handlers/trade.py +15 -1
  23. qubx/connectors/ccxt/reader.py +179 -72
  24. qubx/connectors/ccxt/subscription_config.py +39 -34
  25. qubx/connectors/ccxt/subscription_manager.py +103 -118
  26. qubx/connectors/ccxt/subscription_orchestrator.py +265 -228
  27. qubx/connectors/ccxt/utils.py +50 -26
  28. qubx/core/account.py +5 -5
  29. qubx/core/basics.py +24 -0
  30. qubx/core/initializer.py +7 -0
  31. qubx/core/interfaces.py +21 -5
  32. qubx/core/mixins/subscription.py +6 -1
  33. qubx/core/series.cpython-312-x86_64-linux-gnu.so +0 -0
  34. qubx/core/utils.cpython-312-x86_64-linux-gnu.so +0 -0
  35. qubx/data/readers.py +11 -0
  36. qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so +0 -0
  37. qubx/trackers/advanced.py +41 -4
  38. qubx/utils/charting/mpl_helpers.py +134 -0
  39. qubx/utils/charting/orderbook.py +314 -0
  40. qubx/utils/runner/runner.py +9 -0
  41. {qubx-0.6.71.dist-info → qubx-0.6.73.dist-info}/METADATA +1 -1
  42. {qubx-0.6.71.dist-info → qubx-0.6.73.dist-info}/RECORD +45 -42
  43. {qubx-0.6.71.dist-info → qubx-0.6.73.dist-info}/LICENSE +0 -0
  44. {qubx-0.6.71.dist-info → qubx-0.6.73.dist-info}/WHEEL +0 -0
  45. {qubx-0.6.71.dist-info → qubx-0.6.73.dist-info}/entry_points.txt +0 -0
qubx/backtester/data.py CHANGED
@@ -27,7 +27,7 @@ def _get_first_existing(data: dict, keys: list, default: T = None) -> T:
27
27
  data_get = data.get # Cache method lookup
28
28
  sentinel = object()
29
29
  for key in keys:
30
- if (value := data_get(key, sentinel)) is not sentinel:
30
+ if (value := data_get(key, sentinel)) is not sentinel and value is not None:
31
31
  return value
32
32
  return default
33
33
 
@@ -169,14 +169,24 @@ class SimulatedDataProvider(IDataProvider):
169
169
  if _b_ts_0 <= cut_time_ns and cut_time_ns < _b_ts_1:
170
170
  break
171
171
 
172
+ # Handle None values in OHLC data
173
+ open_price = r.data["open"]
174
+ high_price = r.data["high"]
175
+ low_price = r.data["low"]
176
+ close_price = r.data["close"]
177
+
178
+ # Skip this record if any OHLC value is None
179
+ if open_price is None or high_price is None or low_price is None or close_price is None:
180
+ continue
181
+
172
182
  bars.append(
173
183
  Bar(
174
184
  _b_ts_0,
175
- r.data["open"],
176
- r.data["high"],
177
- r.data["low"],
178
- r.data["close"],
179
- volume=r.data.get("volume", 0),
185
+ open_price,
186
+ high_price,
187
+ low_price,
188
+ close_price,
189
+ volume=r.data.get("volume", 0) or 0, # Handle None volume
180
190
  bought_volume=_get_first_existing(r.data, ["taker_buy_volume", "bought_volume"], 0),
181
191
  volume_quote=_get_first_existing(r.data, ["quote_volume", "volume_quote"], 0),
182
192
  bought_volume_quote=_get_first_existing(
qubx/backtester/runner.py CHANGED
@@ -4,10 +4,9 @@ import numpy as np
4
4
  import pandas as pd
5
5
  from tqdm.auto import tqdm
6
6
 
7
- from qubx import logger
7
+ from qubx import QubxLogConfig, logger
8
8
  from qubx.backtester.sentinels import NoDataContinue
9
9
  from qubx.backtester.simulated_data import IterableSimulationData
10
- from qubx.backtester.utils import SimulationDataConfig, TimeGuardedWrapper
11
10
  from qubx.core.account import CompositeAccountProcessor
12
11
  from qubx.core.basics import SW, DataType, Instrument, TransactionCostsCalculator
13
12
  from qubx.core.context import StrategyContext
@@ -41,6 +40,7 @@ from .utils import (
41
40
  SimulatedTimeProvider,
42
41
  SimulationDataConfig,
43
42
  SimulationSetup,
43
+ TimeGuardedWrapper,
44
44
  )
45
45
 
46
46
 
@@ -328,6 +328,7 @@ class SimulationRunner:
328
328
 
329
329
  if not _run(instrument, data_type, event, is_hist):
330
330
  return False
331
+
331
332
  return True
332
333
 
333
334
  def _handle_no_data_scenario(self, stop_time):
@@ -356,8 +357,9 @@ class SimulationRunner:
356
357
  return False # No scheduled events, stop simulation
357
358
 
358
359
  def print_latency_report(self) -> None:
359
- _l_r = SW.latency_report()
360
- if _l_r is not None:
360
+ if (_l_r := SW.latency_report()) is not None:
361
+ _llvl = QubxLogConfig.get_log_level()
362
+ QubxLogConfig.set_log_level("INFO")
361
363
  logger.info(
362
364
  "<BLUE> Time spent in simulation report </BLUE>\n<r>"
363
365
  + _frame_to_str(
@@ -365,6 +367,7 @@ class SimulationRunner:
365
367
  )
366
368
  + "</r>"
367
369
  )
370
+ QubxLogConfig.set_log_level(_llvl)
368
371
 
369
372
  def _create_backtest_context(self) -> IStrategyContext:
370
373
  logger.debug(