Qubx 0.6.42__cp312-cp312-manylinux_2_39_x86_64.whl → 0.6.44__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.

qubx/backtester/utils.py CHANGED
@@ -218,7 +218,7 @@ def find_instruments_and_exchanges(
218
218
  exchange: ExchangeName_t | None,
219
219
  ) -> tuple[list[Instrument], list[ExchangeName_t]]:
220
220
  _instrs: list[Instrument] = []
221
- _exchanges = [] if exchange is None else [exchange.lower()]
221
+ _exchanges = [] if exchange is None else [exchange]
222
222
  for i in instruments:
223
223
  match i:
224
224
  case str():
qubx/core/lookups.py CHANGED
@@ -283,13 +283,14 @@ class InstrumentsLookup:
283
283
  query_exchanges=query_exchanges,
284
284
  )
285
285
 
286
+ #todo: temporaty disabled ccxt call to exchange, due to conectivity issues. Revert for bitfinex live usage
286
287
  def _update_bitfinex(self, path: str, query_exchanges: bool = False):
287
288
  self._ccxt_update(
288
289
  path,
289
290
  "bitfinex.f",
290
291
  {"bitfinex.f": "bitfinex"},
291
292
  keep_types=[MarketType.SWAP],
292
- query_exchanges=query_exchanges,
293
+ query_exchanges=False,
293
294
  )
294
295
 
295
296
  def _update_bitmex(self, path: str, query_exchanges: bool = False):
qubx/core/metrics.py CHANGED
@@ -1406,8 +1406,8 @@ def chart_signals(
1406
1406
  if show_leverage:
1407
1407
  leverage = calculate_leverage(portfolio, result.capital, start, symbol)
1408
1408
  indicators["Leverage"] = ["area", "cyan", leverage]
1409
- symbol_count = len(portfolio.filter(like="_PnL").columns)
1410
- pnl = portfolio.filter(regex=f"{symbol}_PnL").cumsum() + result.capital / symbol_count
1409
+ # symbol_count = len(portfolio.filter(like="_PnL").columns)
1410
+ pnl = portfolio.filter(regex=f"{symbol}_PnL").cumsum() + result.capital # / symbol_count
1411
1411
  pnl = pnl.loc[start:]
1412
1412
  if apply_commissions:
1413
1413
  comm = portfolio.filter(regex=f"{symbol}_Commissions").loc[start:].cumsum()
@@ -109,6 +109,8 @@ class UniverseManager(IUniverseManager):
109
109
  if self._has_position(instr):
110
110
  self._removal_queue[instr] = (if_has_position_then, skip_callback)
111
111
  to_keep.append(instr)
112
+ else:
113
+ to_remove.append(instr)
112
114
  return to_remove, to_keep
113
115
 
114
116
  def __cleanup_removal_queue(self, instruments: list[Instrument]):
qubx/pandaz/ta.py CHANGED
@@ -633,6 +633,17 @@ def rolling_std_with_mean(x: pd.Series, mean: float | pd.Series, window: int):
633
633
  return np.sqrt((((x - mean) ** 2).rolling(window=window).sum() / (window - 1)))
634
634
 
635
635
 
636
+ def rolling_zscore(x: pd.Series, window: int):
637
+ """
638
+ Calculates rolling z-score for data from x
639
+ :param x: series data
640
+ :param window: window
641
+ :return: rolling z-score
642
+ """
643
+ r = x.rolling(window=window)
644
+ return (x - r.mean()) / r.std(ddof=0)
645
+
646
+
636
647
  def bollinger(x: pd.Series, window=14, nstd=2, mean="sma") -> pd.DataFrame:
637
648
  """
638
649
  Bollinger Bands indicator
@@ -1326,11 +1337,11 @@ def rolling_rank(x, period, pctls=(25, 50, 75)):
1326
1337
  raise ValueError(f"Period {period} exceeds number of data records {len(x)} ")
1327
1338
 
1328
1339
  if isinstance(x, pd.DataFrame):
1329
- z = pd.DataFrame.from_dict({c: rolling_rank(s, period, pctls) for c, s in x.iteritems()})
1340
+ z = pd.DataFrame.from_dict({c: rolling_rank(s, period, pctls) for c, s in x.items()})
1330
1341
  elif isinstance(x, pd.Series):
1331
- z = pd.Series(_rolling_rank(x.values, period, pctls), x.index, name=x.name)
1342
+ z = pd.Series(_rolling_rank(np.ascontiguousarray(x.values), period, pctls), x.index, name=x.name)
1332
1343
  else:
1333
- z = _rolling_rank(x.values, period, pctls)
1344
+ z = _rolling_rank(np.ascontiguousarray(x), period, pctls)
1334
1345
  return z
1335
1346
 
1336
1347
 
@@ -1532,6 +1543,7 @@ def choppiness(
1532
1543
  volatility_estimator="t",
1533
1544
  volume_adjusting=False,
1534
1545
  identification="strong",
1546
+ with_raw_indicator=False,
1535
1547
  ) -> pd.Series:
1536
1548
  """
1537
1549
  Calculate market choppiness index using volatility-based formula.
@@ -1566,7 +1578,8 @@ def choppiness(
1566
1578
  0 when exiting trending regime (crossing above lower threshold)
1567
1579
  - 'weak': Binary classification focused on choppiness - returns 1 when entering choppy regime (crossing above upper threshold),
1568
1580
  0 when entering trending regime (crossing below lower threshold)
1569
-
1581
+ with_raw_indicator : bool, default False
1582
+ If True, returns the raw indicator value instead of the classification
1570
1583
  Returns
1571
1584
  -------
1572
1585
  pd.Series
@@ -1619,7 +1632,7 @@ def choppiness(
1619
1632
  # f0[(ci < lower) & (ci.shift(1) >= lower)] = 0
1620
1633
  # return f0.ffill().fillna(0)
1621
1634
 
1622
- return f0.ffill().fillna(0)
1635
+ return f0.ffill().fillna(0) if not with_raw_indicator else ci
1623
1636
 
1624
1637
 
1625
1638
  @njit
qubx/pandaz/utils.py CHANGED
@@ -590,9 +590,11 @@ class OhlcDict(dict):
590
590
  print(str(d))
591
591
  """
592
592
 
593
+ _orig: dict[str, pd.DataFrame | pd.Series | OHLCV]
593
594
  _fields: Set[str]
594
595
 
595
596
  def __init__(self, orig: dict[str, pd.DataFrame | pd.Series | OHLCV]):
597
+ self._orig = orig
596
598
  _o_copy = {}
597
599
  _lst = []
598
600
  if isinstance(orig, dict):
@@ -639,3 +641,16 @@ class OhlcDict(dict):
639
641
 
640
642
  def __repr__(self) -> str:
641
643
  return self.display(3, 3)
644
+
645
+ def __reduce__(self):
646
+ """
647
+ For joblib Parallel compatibility - defines how to pickle the object
648
+ """
649
+ # Return the class, constructor arguments, and additional state
650
+ data = {k: v for k, v in self.items()}
651
+ return (self.__class__, (data,), {"_orig": self._orig})
652
+
653
+ def __setstate__(self, state):
654
+ """Restore object from pickle state"""
655
+ # Recreate the object using the constructor
656
+ self.__init__(state["_orig"])
qubx/restorers/balance.py CHANGED
@@ -8,6 +8,7 @@ from various sources.
8
8
  import os
9
9
  from pathlib import Path
10
10
  from pymongo import MongoClient
11
+ from datetime import datetime, timedelta
11
12
 
12
13
  import pandas as pd
13
14
 
@@ -152,13 +153,16 @@ class MongoDBBalanceRestorer(IBalanceRestorer):
152
153
  Example: {'USDT': AssetBalance(total=100000.0, locked=0.0)}
153
154
  """
154
155
  try:
155
- match_query = {
156
+ now = datetime.utcnow()
157
+ lookup_range = now - timedelta(days=7)
158
+ base_match = {
156
159
  "log_type": "balance",
157
160
  "strategy_name": self.strategy_name,
161
+ "timestamp": {"$gte": lookup_range}
158
162
  }
159
163
 
160
164
  latest_run_doc = (
161
- self.collection.find(match_query, {"run_id": 1, "timestamp": 1})
165
+ self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
162
166
  .sort("timestamp", -1)
163
167
  .limit(1)
164
168
  )
@@ -172,23 +176,34 @@ class MongoDBBalanceRestorer(IBalanceRestorer):
172
176
 
173
177
  logger.info(f"Restoring balances from MongoDB for run_id: {latest_run_id}")
174
178
 
175
- query = {**match_query, "run_id": latest_run_id}
176
- logs = self.collection.find(query).sort("timestamp", 1)
177
-
178
- balances = {}
179
-
180
- for log in logs:
179
+ pipeline = [
180
+ {"$match": {**base_match, "run_id": latest_run_id}},
181
+ {"$sort": {"timestamp": -1}},
182
+ {
183
+ "$group": {
184
+ "_id": "$currency",
185
+ "doc": {"$first": "$$ROOT"}
186
+ }
187
+ }
188
+ ]
189
+
190
+ cursor = self.collection.aggregate(pipeline)
191
+ balances: dict[str, AssetBalance] = {}
192
+
193
+ for entry in cursor:
194
+ log = entry["doc"]
181
195
  currency = log.get("currency")
182
- if currency:
183
- total = log.get("total", 0.0)
184
- locked = log.get("locked", 0.0)
185
-
186
- balance = AssetBalance(
187
- total=total,
188
- locked=locked,
189
- )
190
- balance.free = total - locked
191
- balances[currency] = balance
196
+ if not currency:
197
+ continue
198
+ total = log.get("total", 0.0)
199
+ locked = log.get("locked", 0.0)
200
+
201
+ balance = AssetBalance(
202
+ total=total,
203
+ locked=locked,
204
+ )
205
+ balance.free = total - locked
206
+ balances[currency] = balance
192
207
 
193
208
  return balances
194
209
  except Exception as e:
@@ -8,6 +8,7 @@ for restoring positions from various sources.
8
8
  import os
9
9
  from pathlib import Path
10
10
  from pymongo import MongoClient
11
+ from datetime import datetime, timedelta
11
12
 
12
13
  import pandas as pd
13
14
 
@@ -168,13 +169,17 @@ class MongoDBPositionRestorer(IPositionRestorer):
168
169
  A dictionary mapping instruments to positions.
169
170
  """
170
171
  try:
171
- match_query = {
172
+ now = datetime.utcnow()
173
+ lookup_range = now - timedelta(days=7)
174
+
175
+ base_match = {
172
176
  "log_type": "positions",
173
177
  "strategy_name": self.strategy_name,
178
+ "timestamp": {"$gte": lookup_range}
174
179
  }
175
180
 
176
181
  latest_run_doc = (
177
- self.collection.find(match_query, {"run_id": 1, "timestamp": 1})
182
+ self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
178
183
  .sort("timestamp", -1)
179
184
  .limit(1)
180
185
  )
@@ -188,20 +193,34 @@ class MongoDBPositionRestorer(IPositionRestorer):
188
193
 
189
194
  logger.info(f"Restoring positions from MongoDB for run_id: {latest_run_id}")
190
195
 
191
- query = {**match_query, "run_id": latest_run_id}
192
- logs = self.collection.find(query).sort("timestamp", 1)
193
-
194
- positions = {}
195
- seen_keys = set()
196
-
197
- for log in logs:
198
- key = (log.get("symbol"), log.get("exchange"), log.get("market_type"))
199
- if None in key or key in seen_keys:
196
+ pipeline = [
197
+ {"$match": {**base_match, "run_id": latest_run_id}},
198
+ {"$sort": {"timestamp": -1}},
199
+ {
200
+ "$group": {
201
+ "_id": {
202
+ "symbol": "$symbol",
203
+ "exchange": "$exchange",
204
+ "market_type": "$market_type"
205
+ },
206
+ "doc": {"$first": "$$ROOT"}
207
+ }
208
+ }
209
+ ]
210
+
211
+ cursor = self.collection.aggregate(pipeline)
212
+
213
+ positions: dict[Instrument, Position] = {}
214
+
215
+ for entry in cursor:
216
+ log = entry["doc"]
217
+
218
+ symbol = log.get("symbol")
219
+ exchange = log.get("exchange")
220
+ market_type = log.get("market_type")
221
+
222
+ if not (symbol and exchange and market_type):
200
223
  continue
201
- seen_keys.add(key)
202
-
203
- symbol = log["symbol"]
204
- exchange = log["exchange"]
205
224
 
206
225
  instrument = lookup.find_symbol(exchange, symbol)
207
226
  if instrument is None:
qubx/restorers/signal.py CHANGED
@@ -208,13 +208,16 @@ class MongoDBSignalRestorer(ISignalRestorer):
208
208
  A dictionary mapping instruments to lists of signals.
209
209
  """
210
210
  try:
211
- match_query = {
211
+ now = datetime.utcnow()
212
+ lookup_range = now - timedelta(days=30)
213
+ base_match = {
212
214
  "log_type": "signals",
213
215
  "strategy_name": self.strategy_name,
216
+ "timestamp": {"$gte": lookup_range}
214
217
  }
215
218
 
216
219
  latest_run_doc = (
217
- self.collection.find(match_query, {"run_id": 1, "timestamp": 1})
220
+ self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
218
221
  .sort("timestamp", -1)
219
222
  .limit(1)
220
223
  )
@@ -228,12 +231,33 @@ class MongoDBSignalRestorer(ISignalRestorer):
228
231
 
229
232
  logger.info(f"Restoring signals from MongoDB for run_id: {latest_run_id}")
230
233
 
231
- query = {**match_query, "run_id": latest_run_id}
232
- logs = self.collection.find(query).sort("timestamp", 1)
233
-
234
+ pipeline = [
235
+ {"$match": {"log_type": "signals", "strategy_name": self.strategy_name, "run_id": latest_run_id}},
236
+ {"$sort": {"timestamp": -1}},
237
+ {
238
+ "$group": {
239
+ "_id": {
240
+ "symbol": "$symbol",
241
+ "exchange": "$exchange",
242
+ "market_type": "$market_type",
243
+ },
244
+ "signals": {"$push": "$$ROOT"}
245
+ }
246
+ },
247
+ {
248
+ "$project": {
249
+ "signals": {"$slice": ["$signals", 20]}
250
+ }
251
+ },
252
+ {"$unwind": "$signals"}
253
+ ]
254
+
255
+ cursor = self.collection.aggregate(pipeline)
256
+
234
257
  result: dict[Instrument, list[TargetPosition]] = {}
235
258
 
236
- for log in logs:
259
+ for entry in cursor:
260
+ log = entry["signals"]
237
261
  try:
238
262
  instrument = lookup.find_symbol(log["exchange"], log["symbol"])
239
263
  if instrument is None:
@@ -281,7 +305,6 @@ class MongoDBSignalRestorer(ISignalRestorer):
281
305
  )
282
306
 
283
307
  result.setdefault(instrument, []).append(target_position)
284
-
285
308
  except Exception as e:
286
309
  logger.exception(f"Failed to process signal document: {e}")
287
310
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Qubx
3
- Version: 0.6.42
3
+ Version: 0.6.44
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Author: Dmitry Marienko
6
6
  Author-email: dmitry.marienko@xlydian.com
@@ -11,7 +11,7 @@ qubx/backtester/runner.py,sha256=TnNM0t8PgBE_gnCOZZTIOc28a3RqtXmp2Xj4Gq5j6bo,205
11
11
  qubx/backtester/simulated_data.py,sha256=niujaMRj__jf4IyzCZrSBR5ZoH1VUbvsZHSewHftdmI,17240
12
12
  qubx/backtester/simulated_exchange.py,sha256=Xg0yv21gq4q9CeCeZoupcenNEBORrxpb93ONZEGL2xk,8076
13
13
  qubx/backtester/simulator.py,sha256=cSbW42X-YlAutZlOQ3Y4mAJWXr_1WomYprtWZVMe3Uk,9225
14
- qubx/backtester/utils.py,sha256=nHrgKcIkyp5gz8wrPwMp1fRItUtQfvOPjxZhcaCwN-o,32729
14
+ qubx/backtester/utils.py,sha256=dDaS7Wrc_xZXWuAqKDql7L3NRMvUkTxpuuAwS0SYA1c,32721
15
15
  qubx/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  qubx/cli/commands.py,sha256=EwGqbNvY5VRCEO9T1w0GgqtcEvPFYMW96KzC-FPUvDM,7259
17
17
  qubx/cli/deploy.py,sha256=pQ9FPOsywDyy8jOjLfrgYTTkKQ-MCixCzbgsG68Q3_0,8319
@@ -44,19 +44,19 @@ qubx/core/helpers.py,sha256=m7JrZaBckXHb4zjhKpdCbxFe3kfda-SCNLfagyq7Ve4,19158
44
44
  qubx/core/initializer.py,sha256=PUiD_cIjvGpuPjYyRpUjpwm3xNQ2Kipa8bAhbtxCQRo,3935
45
45
  qubx/core/interfaces.py,sha256=CzIl8tB6ImQkDcZEmhpstwHPOCY8NhZxXmBHLQUAieI,58253
46
46
  qubx/core/loggers.py,sha256=0g33jfipGFShSMrXBoYVzL0GfTzI36mwBJqHNUHmhdo,13342
47
- qubx/core/lookups.py,sha256=n5ZjjEhhRvmidCB-Cubr1b0Opm6lf_QVZNEWa_BOQG0,19376
48
- qubx/core/metrics.py,sha256=IUTVDfO7HW68GGoLsj6kkLz8ueg-bnXRiWflIts8K_w,60264
47
+ qubx/core/lookups.py,sha256=aEuyZqd_N4cQ-oHz3coEHcdX9Yb0cP5-NwDuj-DQyNk,19477
48
+ qubx/core/metrics.py,sha256=74xIecCvlxVXl0gy0JvgjJ2X5gg-RMmVZw9hQikkHE0,60269
49
49
  qubx/core/mixins/__init__.py,sha256=AMCLvfNuIb1kkQl3bhCj9jIOEl2eKcVPJeyLgrkB-rk,329
50
50
  qubx/core/mixins/market.py,sha256=lBappEimPhIuI0vmUvwVlIztkYjlEjJBpP-AdpfudII,3948
51
51
  qubx/core/mixins/processing.py,sha256=cmjD0PcQv3gFP6oILfNgdNgw7Tez0fUZu_nFn6680VI,24979
52
52
  qubx/core/mixins/subscription.py,sha256=V_g9wCPQ8S5SHkU-qOZ84cV5nReAUrV7DoSNAGG0LPY,10372
53
53
  qubx/core/mixins/trading.py,sha256=idfRPaqrvkfMxzu9mXr9i_xfqLee-ZAOrERxkxv6Ruo,7256
54
- qubx/core/mixins/universe.py,sha256=L3s2Jw46_J1iDh4622Gk_LvCjol4W7mflBwEHrLfZEw,9899
55
- qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=8DijkxPrz0lEvZCp81RfOj5oaxVt_0YTq0ihU5UtIVs,978280
54
+ qubx/core/mixins/universe.py,sha256=kMhBvGzkRBhuJJKr0Ld8w_BLHBuVIqCVwFGo9myWzT8,9966
55
+ qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=xWa2_qK_4NXxeIalUfHU1WJ-ljqymSPu6nAvrESHWY8,978280
56
56
  qubx/core/series.pxd,sha256=jBdMwgO8J4Zrue0e_xQ5RlqTXqihpzQNu6V3ckZvvpY,3978
57
57
  qubx/core/series.pyi,sha256=RaHm_oHHiWiNUMJqVfx5FXAXniGLsHxUFOUpacn7GC0,4604
58
58
  qubx/core/series.pyx,sha256=7cM3zZThW59waHiYcZmMxvYj-HYD7Ej_l7nKA4emPjE,46477
59
- qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=pP6PczrIK0qymrZDt2sywmhnkhCZqyPpzxT_4680uFU,86568
59
+ qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=YgNN7gV7PQUp0JTVt0452U2j-bjjCw8PMEHypG1QLxo,86568
60
60
  qubx/core/utils.pyi,sha256=a-wS13V2p_dM1CnGq40JVulmiAhixTwVwt0ah5By0Hc,348
61
61
  qubx/core/utils.pyx,sha256=k5QHfEFvqhqWfCob89ANiJDKNG8gGbOh-O4CVoneZ8M,1696
62
62
  qubx/data/__init__.py,sha256=ELZykvpPGWc5rX7QoNyNQwMLgdKMG8MACOByA4pM5hA,549
@@ -101,8 +101,8 @@ qubx/notifications/composite.py,sha256=fa-rvHEn6k-Fma5N7cT-7Sk7hzVyB0KDs2ktDyoyL
101
101
  qubx/notifications/slack.py,sha256=FZ0zfTA-zRHOsOsIVBtM7mkt4m-adiuiV5yrwliS9RM,7976
102
102
  qubx/notifications/throttler.py,sha256=8jnymPQbrgtN1rD7REQa2sA9teSWTqkk_uT9oaknOyc,5618
103
103
  qubx/pandaz/__init__.py,sha256=6BYz6gSgxjNa7WP1XqWflYG7WIq1ppSD9h1XGR5M5YQ,682
104
- qubx/pandaz/ta.py,sha256=SjK3jORf6Q3XYBwTixXnjK5elbzdvT14WR2OJdQXo20,91666
105
- qubx/pandaz/utils.py,sha256=f7airZjUKHkhKICL0HF_R9Vvcswdgef7Yr35Xb_Ppzs,23407
104
+ qubx/pandaz/ta.py,sha256=sIX9YxxB2S2nWU4vnS4rXFuEI5WSY76Ky1TFwf9RhMw,92154
105
+ qubx/pandaz/utils.py,sha256=rg28KfcbWw4NelaI196OiAq0VM6DsszO5nrGSDPQFWk,23972
106
106
  qubx/resources/_build.py,sha256=XE7XNuDqfXPc2OriLobKXmPMvwa7Z8AKAD-18fnf0e4,8802
107
107
  qubx/resources/instruments/symbols-binance.cm.json,sha256=rNI3phNeeRY95_IE7_0Um9d5U4jUtEijZQ_PaYg5cdw,25127
108
108
  qubx/resources/instruments/symbols-binance.json,sha256=Qx_XckgsWNhmmV8_t5DpG0AeGkuTyt1uiif2EeeBDIg,939678
@@ -115,15 +115,15 @@ qubx/restarts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
115
  qubx/restarts/state_resolvers.py,sha256=GJ617qwpulqMp_-WhpmsLozQobxgt5lU4ZGOIUaUzas,5606
116
116
  qubx/restarts/time_finders.py,sha256=r7yyRhJByV2uqdgamDRX2XClwpWWI9BNpc80t9nk6c0,2448
117
117
  qubx/restorers/__init__.py,sha256=vrnZBPJHR0-6knAccj4bK0tkjUPNRl32qiLr5Mv4aR0,911
118
- qubx/restorers/balance.py,sha256=Oz-LY7s8tdSIJl83z9rII-DpX5xa8-qiqjcDYfW-KiE,6456
118
+ qubx/restorers/balance.py,sha256=yLV1vBki0XhBxrOhgaJBHuuL8VmIii82LAWgLxusbcE,6967
119
119
  qubx/restorers/factory.py,sha256=eoijcUHDaBVPHSfkjyo1AHvWTvvs0kj7jJbF_NE30aw,6737
120
120
  qubx/restorers/interfaces.py,sha256=CcjBWavKq8_GIMKTSPodMa-n3wJQwcQTwyvYyNo_J3c,1776
121
- qubx/restorers/position.py,sha256=xmaqaQQrmzF0VEHAZK35cXb6WKYRnDDapaN-EgZcH8U,8090
122
- qubx/restorers/signal.py,sha256=9TAaJOEKPjZXuciFFVn6Z8a-Z8CfVSjRGFRcwEgbPLY,10745
121
+ qubx/restorers/position.py,sha256=jMJjq2ZJwHpAlG45bMy49WvkYK5UylDiExt7nVpxCfg,8703
122
+ qubx/restorers/signal.py,sha256=x-VLSnb863U517sPeZhGvfuIOUfmYVhANg5P7lio_Mg,11630
123
123
  qubx/restorers/state.py,sha256=dLaVnUwRCNRkUqbYyi0RfZs3Q3AdglkI_qTtQ8GDD5Y,7289
124
124
  qubx/restorers/utils.py,sha256=We2gfqwQKWziUYhuUnjb-xo-5tSlbuHWpPQn0CEMTn0,1155
125
125
  qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
126
- qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=NK4SU3DKjt9hjTM0N2_8zuGDYH8lZiLEMtOL3c4saog,654440
126
+ qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=Qrr1VzZ4m5ATXGJQrf_D1hUdQib5TRUwRaMOC_0QoKY,654440
127
127
  qubx/ta/indicators.pxd,sha256=Goo0_N0Xnju8XGo3Xs-3pyg2qr_0Nh5C-_26DK8U_IE,4224
128
128
  qubx/ta/indicators.pyi,sha256=19W0uERft49In5bf9jkJHkzJYEyE9gzudN7_DJ5Vdv8,1963
129
129
  qubx/ta/indicators.pyx,sha256=Xgpew46ZxSXsdfSEWYn3A0Q35MLsopB9n7iyCsXTufs,25969
@@ -160,8 +160,8 @@ qubx/utils/runner/factory.py,sha256=8IxKvsEL0opx5OlO4XEQgAlmu05sgxXxkY4G2MQdLbg,
160
160
  qubx/utils/runner/runner.py,sha256=DhICMOfgE0i7VEC7pNMSEzIyZbb-TbOa6FbR1obZpyc,28901
161
161
  qubx/utils/time.py,sha256=J0ZFGjzFL5T6GA8RPAel8hKG0sg2LZXeQ5YfDCfcMHA,10055
162
162
  qubx/utils/version.py,sha256=e52fIHyxzCiIuH7svCF6pkHuDlqL64rklqz-2XjWons,5309
163
- qubx-0.6.42.dist-info/LICENSE,sha256=qwMHOSJ2TD0nx6VUJvFhu1ynJdBfNozRMt6tnSul-Ts,35140
164
- qubx-0.6.42.dist-info/METADATA,sha256=IimoSRSYNj-wJp_LKP7T4Gr0OVu_9Wuxo7Pm2unbjp4,4492
165
- qubx-0.6.42.dist-info/WHEEL,sha256=UckHTmFUCaLKpi4yFY8Dewu0c6XkY-KvEAGzGOnaWo8,110
166
- qubx-0.6.42.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
167
- qubx-0.6.42.dist-info/RECORD,,
163
+ qubx-0.6.44.dist-info/LICENSE,sha256=qwMHOSJ2TD0nx6VUJvFhu1ynJdBfNozRMt6tnSul-Ts,35140
164
+ qubx-0.6.44.dist-info/METADATA,sha256=YtXaFa6les1w_IjRpULYKfrhkc-4m_XGZhBYskcqPkA,4492
165
+ qubx-0.6.44.dist-info/WHEEL,sha256=UckHTmFUCaLKpi4yFY8Dewu0c6XkY-KvEAGzGOnaWo8,110
166
+ qubx-0.6.44.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
167
+ qubx-0.6.44.dist-info/RECORD,,
File without changes
File without changes