Qubx 0.7.8__cp312-cp312-manylinux_2_39_x86_64.whl → 0.7.9__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/connectors/xlighter/reader.py +88 -1
- qubx/core/context.py +1 -2
- qubx/core/series.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/core/utils.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/ta/indicators.pxd +27 -1
- qubx/ta/indicators.pyi +11 -0
- qubx/ta/indicators.pyx +216 -1
- qubx/utils/hft/orderbook.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/utils/ringbuffer.cpython-312-x86_64-linux-gnu.so +0 -0
- {qubx-0.7.8.dist-info → qubx-0.7.9.dist-info}/METADATA +1 -1
- {qubx-0.7.8.dist-info → qubx-0.7.9.dist-info}/RECORD +15 -15
- {qubx-0.7.8.dist-info → qubx-0.7.9.dist-info}/WHEEL +0 -0
- {qubx-0.7.8.dist-info → qubx-0.7.9.dist-info}/entry_points.txt +0 -0
- {qubx-0.7.8.dist-info → qubx-0.7.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -262,7 +262,8 @@ class XLighterDataReader(DataReader):
|
|
|
262
262
|
max_history_start = stop_ts - self._max_history
|
|
263
263
|
if start_ts < max_history_start:
|
|
264
264
|
logger.debug(
|
|
265
|
-
f"Adjusting start time from {start_ts} to {max_history_start}
|
|
265
|
+
f"Adjusting start time from {start_ts} to {max_history_start} "
|
|
266
|
+
f"due to max_history={self._max_history}"
|
|
266
267
|
)
|
|
267
268
|
start_ts = max_history_start
|
|
268
269
|
|
|
@@ -337,6 +338,92 @@ class XLighterDataReader(DataReader):
|
|
|
337
338
|
logger.info(f"Fetched {len(df)} funding payment records for {len(instruments_to_fetch)} symbols")
|
|
338
339
|
return df
|
|
339
340
|
|
|
341
|
+
def get_candles(
|
|
342
|
+
self,
|
|
343
|
+
exchange: str,
|
|
344
|
+
symbols: list[str] | None = None,
|
|
345
|
+
start: str | pd.Timestamp | None = None,
|
|
346
|
+
stop: str | pd.Timestamp | None = None,
|
|
347
|
+
timeframe: str = "1d",
|
|
348
|
+
) -> pd.DataFrame:
|
|
349
|
+
"""
|
|
350
|
+
Get candlestick data for symbols within specified time range.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
exchange: Exchange name (should be "LIGHTER")
|
|
354
|
+
symbols: List of symbols in Qubx format (e.g., ["BTCUSDC", "ETHUSDC"]). If None, fetches all symbols.
|
|
355
|
+
start: Start time (ISO format or timestamp)
|
|
356
|
+
stop: Stop time (ISO format or timestamp)
|
|
357
|
+
timeframe: Timeframe for candles (e.g., "1m", "5m", "1h", "1d")
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
DataFrame with MultiIndex [timestamp, symbol] and columns:
|
|
361
|
+
- open: Opening price
|
|
362
|
+
- high: Highest price
|
|
363
|
+
- low: Lowest price
|
|
364
|
+
- close: Closing price
|
|
365
|
+
- volume: Trading volume
|
|
366
|
+
"""
|
|
367
|
+
if exchange.upper() != "LIGHTER":
|
|
368
|
+
logger.warning(f"Exchange {exchange} not supported by XLighterDataReader")
|
|
369
|
+
return pd.DataFrame(columns=["open", "high", "low", "close", "volume"])
|
|
370
|
+
|
|
371
|
+
# Handle time range
|
|
372
|
+
start_ts = pd.Timestamp(start) if start else pd.Timestamp.now() - pd.Timedelta(days=7)
|
|
373
|
+
stop_ts = pd.Timestamp(stop) if stop else pd.Timestamp.now()
|
|
374
|
+
|
|
375
|
+
# Apply max_history limitation
|
|
376
|
+
if self._max_history:
|
|
377
|
+
max_history_start = stop_ts - self._max_history
|
|
378
|
+
if start_ts < max_history_start:
|
|
379
|
+
logger.debug(
|
|
380
|
+
f"Adjusting start time from {start_ts} to {max_history_start} "
|
|
381
|
+
f"due to max_history={self._max_history}"
|
|
382
|
+
)
|
|
383
|
+
start_ts = max_history_start
|
|
384
|
+
|
|
385
|
+
# Get instruments to fetch
|
|
386
|
+
instruments_to_fetch = self._get_instruments_for_symbols(symbols)
|
|
387
|
+
if not instruments_to_fetch:
|
|
388
|
+
logger.warning("No instruments found for the specified symbols")
|
|
389
|
+
return pd.DataFrame(columns=["open", "high", "low", "close", "volume"])
|
|
390
|
+
|
|
391
|
+
# Fetch candle data for each instrument
|
|
392
|
+
all_candle_data = []
|
|
393
|
+
|
|
394
|
+
for instrument in instruments_to_fetch:
|
|
395
|
+
try:
|
|
396
|
+
# Fetch OHLCV data using existing method
|
|
397
|
+
ohlcv_list = self._fetch_ohlcv(instrument, timeframe, start_ts, stop_ts)
|
|
398
|
+
|
|
399
|
+
if not ohlcv_list:
|
|
400
|
+
logger.debug(f"No candle data found for {instrument.symbol}")
|
|
401
|
+
continue
|
|
402
|
+
|
|
403
|
+
# Convert to DataFrame
|
|
404
|
+
df = pd.DataFrame(
|
|
405
|
+
ohlcv_list,
|
|
406
|
+
columns=["timestamp", "open", "high", "low", "close", "volume"]
|
|
407
|
+
)
|
|
408
|
+
df["symbol"] = instrument.symbol
|
|
409
|
+
all_candle_data.append(df)
|
|
410
|
+
|
|
411
|
+
except Exception as e:
|
|
412
|
+
logger.error(f"Failed to fetch candle data for {instrument.symbol}: {e}")
|
|
413
|
+
continue
|
|
414
|
+
|
|
415
|
+
if not all_candle_data:
|
|
416
|
+
logger.info("No candle data found")
|
|
417
|
+
return pd.DataFrame(columns=["open", "high", "low", "close", "volume"])
|
|
418
|
+
|
|
419
|
+
# Combine all DataFrames
|
|
420
|
+
combined_df = pd.concat(all_candle_data, ignore_index=True)
|
|
421
|
+
combined_df = combined_df.sort_values("timestamp")
|
|
422
|
+
combined_df = combined_df.set_index(["timestamp", "symbol"])
|
|
423
|
+
|
|
424
|
+
logger.info(f"Fetched {len(combined_df)} candle records for {len(instruments_to_fetch)} symbols")
|
|
425
|
+
return combined_df
|
|
426
|
+
|
|
340
427
|
def _get_instrument(self, data_id: str) -> Instrument | None:
|
|
341
428
|
"""
|
|
342
429
|
Get instrument from data ID.
|
qubx/core/context.py
CHANGED
|
@@ -365,7 +365,6 @@ class StrategyContext(IStrategyContext):
|
|
|
365
365
|
{
|
|
366
366
|
"Exchanges": "|".join(self.exchanges),
|
|
367
367
|
"Total Capital": f"${self.get_total_capital():,.0f}",
|
|
368
|
-
"Net Leverage": f"{self.get_net_leverage():.1%}",
|
|
369
368
|
"Open Positions": len(open_positions),
|
|
370
369
|
"Instruments": len(self._initial_instruments),
|
|
371
370
|
},
|
|
@@ -414,7 +413,7 @@ class StrategyContext(IStrategyContext):
|
|
|
414
413
|
try:
|
|
415
414
|
self._notifier.notify_stop(
|
|
416
415
|
{
|
|
417
|
-
"Total Capital": f"{self.get_total_capital()
|
|
416
|
+
"Total Capital": f"{self.get_total_capital():,.0f}",
|
|
418
417
|
"Net Leverage": f"{self.get_net_leverage():.2%}",
|
|
419
418
|
"Positions": len([p for i, p in self.get_positions().items() if abs(p.quantity) > i.min_size]),
|
|
420
419
|
},
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
qubx/ta/indicators.pxd
CHANGED
|
@@ -223,4 +223,30 @@ cdef class Macd(Indicator):
|
|
|
223
223
|
cdef object macd_line_series
|
|
224
224
|
cdef object signal_line
|
|
225
225
|
|
|
226
|
-
cpdef double calculate(self, long long time, double value, short new_item_started)
|
|
226
|
+
cpdef double calculate(self, long long time, double value, short new_item_started)
|
|
227
|
+
|
|
228
|
+
cdef class SuperTrend(IndicatorOHLC):
|
|
229
|
+
cdef int length
|
|
230
|
+
cdef double mult
|
|
231
|
+
cdef str src
|
|
232
|
+
cdef short wicks
|
|
233
|
+
cdef str atr_smoother
|
|
234
|
+
|
|
235
|
+
cdef double _prev_longstop
|
|
236
|
+
cdef double _prev_shortstop
|
|
237
|
+
cdef double _prev_direction
|
|
238
|
+
|
|
239
|
+
cdef double prev_longstop
|
|
240
|
+
cdef double prev_shortstop
|
|
241
|
+
cdef double prev_direction
|
|
242
|
+
|
|
243
|
+
cdef TimeSeries tr
|
|
244
|
+
cdef object atr_ma
|
|
245
|
+
cdef public TimeSeries utl
|
|
246
|
+
cdef public TimeSeries dtl
|
|
247
|
+
|
|
248
|
+
cdef _store(self)
|
|
249
|
+
cdef _restore(self)
|
|
250
|
+
cdef double calc_src(self, Bar bar)
|
|
251
|
+
|
|
252
|
+
cpdef double calculate(self, long long time, Bar bar, short new_item_started)
|
qubx/ta/indicators.pyi
CHANGED
|
@@ -24,6 +24,7 @@ def rsi(series: TimeSeries, period: int = 13, smoother="ema") -> Indicator: ...
|
|
|
24
24
|
def stdema(series: TimeSeries, period: int) -> Indicator: ...
|
|
25
25
|
def cusum_filter(series: TimeSeries, target: TimeSeries) -> Indicator: ...
|
|
26
26
|
def macd(series: TimeSeries, fast=12, slow=26, signal=9, method="ema", signal_method="ema") -> Indicator: ...
|
|
27
|
+
def super_trend(series: OHLCV, length: int = 22, mult: float = 3.0, src: str = "hl2", wicks: bool = True, atr_smoother: str = "sma") -> Indicator: ...
|
|
27
28
|
|
|
28
29
|
class Sma(Indicator):
|
|
29
30
|
def __init__(self, name: str, series: TimeSeries, period: int): ...
|
|
@@ -84,3 +85,13 @@ class Macd(Indicator):
|
|
|
84
85
|
def __init__(
|
|
85
86
|
self, name: str, series: TimeSeries, fast: int, slow: int, signal: int, method: str, signal_method: str
|
|
86
87
|
): ...
|
|
88
|
+
|
|
89
|
+
class SuperTrend(IndicatorOHLC):
|
|
90
|
+
utl: TimeSeries
|
|
91
|
+
dtl: TimeSeries
|
|
92
|
+
length: int
|
|
93
|
+
mult: float
|
|
94
|
+
src: str
|
|
95
|
+
wicks: bool
|
|
96
|
+
atr_smoother: str
|
|
97
|
+
def __init__(self, name: str, series: OHLCV, length: int, mult: float, src: str, wicks: bool, atr_smoother: str): ...
|
qubx/ta/indicators.pyx
CHANGED
|
@@ -1553,4 +1553,219 @@ def macd(series: TimeSeries, fast=12, slow=26, signal=9, method="ema", signal_me
|
|
|
1553
1553
|
:param signal_method: used method for averaging signal (sma, ema, tema, dema, kama)
|
|
1554
1554
|
:return: macd indicator
|
|
1555
1555
|
"""
|
|
1556
|
-
return Macd.wrap(series, fast, slow, signal, method, signal_method) # type: ignore
|
|
1556
|
+
return Macd.wrap(series, fast, slow, signal, method, signal_method) # type: ignore
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
cdef class SuperTrend(IndicatorOHLC):
|
|
1560
|
+
"""
|
|
1561
|
+
SuperTrend indicator - a trend-following indicator based on ATR
|
|
1562
|
+
|
|
1563
|
+
The SuperTrend indicator provides trend direction and support/resistance levels.
|
|
1564
|
+
It uses Average True Range (ATR) to calculate dynamic bands around price.
|
|
1565
|
+
|
|
1566
|
+
Returns:
|
|
1567
|
+
trend: +1 for uptrend, -1 for downtrend
|
|
1568
|
+
utl (upper trend line): longstop values during uptrend
|
|
1569
|
+
dtl (down trend line): shortstop values during downtrend
|
|
1570
|
+
"""
|
|
1571
|
+
|
|
1572
|
+
def __init__(self, str name, OHLCV series, int length, double mult, str src, short wicks, str atr_smoother):
|
|
1573
|
+
self.length = length
|
|
1574
|
+
self.mult = mult
|
|
1575
|
+
self.src = src
|
|
1576
|
+
self.wicks = wicks
|
|
1577
|
+
self.atr_smoother = atr_smoother
|
|
1578
|
+
|
|
1579
|
+
# - working state variables (updated during calculation)
|
|
1580
|
+
self._prev_longstop = np.nan
|
|
1581
|
+
self._prev_shortstop = np.nan
|
|
1582
|
+
self._prev_direction = np.nan
|
|
1583
|
+
|
|
1584
|
+
# - saved state variables (for handling partial bar updates)
|
|
1585
|
+
self.prev_longstop = np.nan
|
|
1586
|
+
self.prev_shortstop = np.nan
|
|
1587
|
+
self.prev_direction = np.nan
|
|
1588
|
+
|
|
1589
|
+
# - create internal TR series and smooth it for ATR calculation
|
|
1590
|
+
self.tr = TimeSeries("tr", series.timeframe, series.max_series_length)
|
|
1591
|
+
self.atr_ma = smooth(self.tr, atr_smoother, length)
|
|
1592
|
+
|
|
1593
|
+
# - create output series for upper and down trend lines
|
|
1594
|
+
self.utl = TimeSeries("utl", series.timeframe, series.max_series_length)
|
|
1595
|
+
self.dtl = TimeSeries("dtl", series.timeframe, series.max_series_length)
|
|
1596
|
+
|
|
1597
|
+
super().__init__(name, series)
|
|
1598
|
+
|
|
1599
|
+
cdef _store(self):
|
|
1600
|
+
"""Store current working state to saved state"""
|
|
1601
|
+
self.prev_longstop = self._prev_longstop
|
|
1602
|
+
self.prev_shortstop = self._prev_shortstop
|
|
1603
|
+
self.prev_direction = self._prev_direction
|
|
1604
|
+
|
|
1605
|
+
cdef _restore(self):
|
|
1606
|
+
"""Restore saved state to working state"""
|
|
1607
|
+
self._prev_longstop = self.prev_longstop
|
|
1608
|
+
self._prev_shortstop = self.prev_shortstop
|
|
1609
|
+
self._prev_direction = self.prev_direction
|
|
1610
|
+
|
|
1611
|
+
cdef double calc_src(self, Bar bar):
|
|
1612
|
+
"""Calculate source value based on src parameter"""
|
|
1613
|
+
if self.src == "close":
|
|
1614
|
+
return bar.close
|
|
1615
|
+
elif self.src == "hl2":
|
|
1616
|
+
return (bar.high + bar.low) / 2.0
|
|
1617
|
+
elif self.src == "hlc3":
|
|
1618
|
+
return (bar.high + bar.low + bar.close) / 3.0
|
|
1619
|
+
elif self.src == "ohlc4":
|
|
1620
|
+
return (bar.open + bar.high + bar.low + bar.close) / 4.0
|
|
1621
|
+
else:
|
|
1622
|
+
return (bar.high + bar.low) / 2.0 # - default to hl2
|
|
1623
|
+
|
|
1624
|
+
cpdef double calculate(self, long long time, Bar bar, short new_item_started):
|
|
1625
|
+
cdef double atr_value, src_value, longstop, shortstop
|
|
1626
|
+
cdef double high_price, low_price, p_high_price, p_low_price
|
|
1627
|
+
cdef short is_doji4price
|
|
1628
|
+
cdef double direction
|
|
1629
|
+
cdef double saved_prev_longstop, saved_prev_shortstop
|
|
1630
|
+
cdef double tr_value
|
|
1631
|
+
|
|
1632
|
+
# - need at least 2 bars for prev calculations
|
|
1633
|
+
if len(self.series) < 2:
|
|
1634
|
+
# - initialize on first bar
|
|
1635
|
+
self._prev_longstop = np.nan
|
|
1636
|
+
self._prev_shortstop = np.nan
|
|
1637
|
+
self._prev_direction = np.nan
|
|
1638
|
+
self._store()
|
|
1639
|
+
return np.nan
|
|
1640
|
+
|
|
1641
|
+
# - handle store/restore for partial bar updates
|
|
1642
|
+
if new_item_started:
|
|
1643
|
+
self._store()
|
|
1644
|
+
else:
|
|
1645
|
+
self._restore()
|
|
1646
|
+
|
|
1647
|
+
# - calculate True Range
|
|
1648
|
+
cdef Bar prev_bar = self.series[1]
|
|
1649
|
+
cdef double c1 = prev_bar.close
|
|
1650
|
+
cdef double h_l = abs(bar.high - bar.low)
|
|
1651
|
+
cdef double h_pc = abs(bar.high - c1)
|
|
1652
|
+
cdef double l_pc = abs(bar.low - c1)
|
|
1653
|
+
tr_value = max(h_l, h_pc, l_pc)
|
|
1654
|
+
|
|
1655
|
+
# - update TR series (this will automatically update ATR via smooth)
|
|
1656
|
+
self.tr.update(time, tr_value)
|
|
1657
|
+
|
|
1658
|
+
# - get ATR value
|
|
1659
|
+
atr_value = self.atr_ma[0]
|
|
1660
|
+
if np.isnan(atr_value):
|
|
1661
|
+
return np.nan
|
|
1662
|
+
|
|
1663
|
+
atr_value = abs(self.mult) * atr_value
|
|
1664
|
+
|
|
1665
|
+
# - calculate source value
|
|
1666
|
+
src_value = self.calc_src(bar)
|
|
1667
|
+
|
|
1668
|
+
# - determine which prices to use for wicks
|
|
1669
|
+
if self.wicks:
|
|
1670
|
+
high_price = bar.high
|
|
1671
|
+
low_price = bar.low
|
|
1672
|
+
else:
|
|
1673
|
+
high_price = bar.close
|
|
1674
|
+
low_price = bar.close
|
|
1675
|
+
|
|
1676
|
+
# - get previous bar's prices (prev_bar already retrieved above for TR)
|
|
1677
|
+
if self.wicks:
|
|
1678
|
+
p_high_price = prev_bar.high
|
|
1679
|
+
p_low_price = prev_bar.low
|
|
1680
|
+
else:
|
|
1681
|
+
p_high_price = prev_bar.close
|
|
1682
|
+
p_low_price = prev_bar.close
|
|
1683
|
+
|
|
1684
|
+
# - check for doji4price (all prices equal)
|
|
1685
|
+
is_doji4price = (bar.open == bar.close) and (bar.open == bar.low) and (bar.open == bar.high)
|
|
1686
|
+
|
|
1687
|
+
# - calculate basic stops
|
|
1688
|
+
longstop = src_value - atr_value
|
|
1689
|
+
shortstop = src_value + atr_value
|
|
1690
|
+
|
|
1691
|
+
# - save previous bar's stops for direction comparison
|
|
1692
|
+
saved_prev_longstop = self._prev_longstop
|
|
1693
|
+
saved_prev_shortstop = self._prev_shortstop
|
|
1694
|
+
|
|
1695
|
+
# - adjust longstop based on previous value
|
|
1696
|
+
if np.isnan(self._prev_longstop):
|
|
1697
|
+
self._prev_longstop = longstop
|
|
1698
|
+
|
|
1699
|
+
if longstop > 0:
|
|
1700
|
+
if is_doji4price:
|
|
1701
|
+
longstop = self._prev_longstop
|
|
1702
|
+
else:
|
|
1703
|
+
if p_low_price > self._prev_longstop:
|
|
1704
|
+
longstop = max(longstop, self._prev_longstop)
|
|
1705
|
+
# - else: keep calculated longstop
|
|
1706
|
+
else:
|
|
1707
|
+
longstop = self._prev_longstop
|
|
1708
|
+
|
|
1709
|
+
# - adjust shortstop based on previous value
|
|
1710
|
+
if np.isnan(self._prev_shortstop):
|
|
1711
|
+
self._prev_shortstop = shortstop
|
|
1712
|
+
|
|
1713
|
+
if shortstop > 0:
|
|
1714
|
+
if is_doji4price:
|
|
1715
|
+
shortstop = self._prev_shortstop
|
|
1716
|
+
else:
|
|
1717
|
+
if p_high_price < self._prev_shortstop:
|
|
1718
|
+
shortstop = min(shortstop, self._prev_shortstop)
|
|
1719
|
+
# - else: keep calculated shortstop
|
|
1720
|
+
else:
|
|
1721
|
+
shortstop = self._prev_shortstop
|
|
1722
|
+
|
|
1723
|
+
# - determine direction based on price breaking PREVIOUS bar's stops
|
|
1724
|
+
# - only check for breaks if we have valid previous stops
|
|
1725
|
+
if np.isnan(saved_prev_longstop) or np.isnan(saved_prev_shortstop):
|
|
1726
|
+
# - not enough data yet, forward fill previous direction or return NaN
|
|
1727
|
+
direction = self._prev_direction if not np.isnan(self._prev_direction) else np.nan
|
|
1728
|
+
elif low_price < saved_prev_longstop:
|
|
1729
|
+
direction = -1.0
|
|
1730
|
+
elif high_price > saved_prev_shortstop:
|
|
1731
|
+
direction = 1.0
|
|
1732
|
+
else:
|
|
1733
|
+
# - no break, keep previous direction (forward fill)
|
|
1734
|
+
direction = self._prev_direction if not np.isnan(self._prev_direction) else np.nan
|
|
1735
|
+
|
|
1736
|
+
# - update working state for next iteration
|
|
1737
|
+
self._prev_longstop = longstop
|
|
1738
|
+
self._prev_shortstop = shortstop
|
|
1739
|
+
self._prev_direction = direction
|
|
1740
|
+
|
|
1741
|
+
# - update utl and dtl series based on direction
|
|
1742
|
+
# - only update when we have a valid direction
|
|
1743
|
+
if direction == 1.0:
|
|
1744
|
+
self.utl.update(time, longstop)
|
|
1745
|
+
elif direction == -1.0:
|
|
1746
|
+
self.dtl.update(time, shortstop)
|
|
1747
|
+
|
|
1748
|
+
# - return trend direction
|
|
1749
|
+
return direction
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
def super_trend(series: OHLCV, length: int = 22, mult: float = 3.0, src: str = "hl2",
|
|
1753
|
+
wicks: bool = True, atr_smoother: str = "sma"):
|
|
1754
|
+
"""
|
|
1755
|
+
SuperTrend indicator - a trend-following indicator based on ATR
|
|
1756
|
+
|
|
1757
|
+
The SuperTrend indicator uses Average True Range (ATR) to calculate dynamic support
|
|
1758
|
+
and resistance levels. It provides clear trend direction and can be used for
|
|
1759
|
+
entry/exit signals.
|
|
1760
|
+
|
|
1761
|
+
:param series: OHLCV input series
|
|
1762
|
+
:param length: ATR period (default 22)
|
|
1763
|
+
:param mult: ATR multiplier (default 3.0)
|
|
1764
|
+
:param src: source calculation - 'close', 'hl2', 'hlc3', 'ohlc4' (default 'hl2')
|
|
1765
|
+
:param wicks: whether to use high/low (True) or close (False) for calculations (default True)
|
|
1766
|
+
:param atr_smoother: smoothing method for ATR - 'sma', 'ema', etc (default 'sma')
|
|
1767
|
+
:return: SuperTrend indicator with trend, utl, and dtl series
|
|
1768
|
+
"""
|
|
1769
|
+
if not isinstance(series, OHLCV):
|
|
1770
|
+
raise ValueError("Series must be OHLCV !")
|
|
1771
|
+
return SuperTrend.wrap(series, length, mult, src, wicks, atr_smoother) # type: ignore
|
|
Binary file
|
|
Binary file
|
|
@@ -77,13 +77,13 @@ qubx/connectors/xlighter/instruments.py,sha256=eE-3XYBX51daU3-ul-MVS0m2p6LXPmvjV
|
|
|
77
77
|
qubx/connectors/xlighter/nonce.py,sha256=chsbFR9GPsl-09Q2JbbNqRBEd_5tUB3wFU_q8-KJcO0,532
|
|
78
78
|
qubx/connectors/xlighter/parsers.py,sha256=IRuSLaqgjeWgaBaYA522vyl1Q2SNVTvNQGVG0VUUbOc,21626
|
|
79
79
|
qubx/connectors/xlighter/rate_limits.py,sha256=qMp9c5Ffe22NKVfRHUhej7vFqPtuHpcARy0Oac-kv5Y,3670
|
|
80
|
-
qubx/connectors/xlighter/reader.py,sha256=
|
|
80
|
+
qubx/connectors/xlighter/reader.py,sha256=SWTYP_I0IqBACpI8oHiRRriUnT7TKojegcMkHJ98Tjw,19706
|
|
81
81
|
qubx/connectors/xlighter/utils.py,sha256=O0YNhkvJc8e1BVsSBG2G55r9YuTYknCPvbcJlI03JXQ,8157
|
|
82
82
|
qubx/connectors/xlighter/websocket.py,sha256=eEyBqG3K04VofEGZ_VvEyb9ZnJyAb1r3qDUqXmE_L0Q,18145
|
|
83
83
|
qubx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
84
84
|
qubx/core/account.py,sha256=7XmZiTaMwxN8dekJQN8zFBnwuXwOwIJ62TPtgHWXyso,26698
|
|
85
85
|
qubx/core/basics.py,sha256=gubYyeq3uHvPq1TLndJMP5QYvd4pnHgiwPbmREvSDrA,45540
|
|
86
|
-
qubx/core/context.py,sha256=
|
|
86
|
+
qubx/core/context.py,sha256=g_3ldRF4j2qKX0Ei5rick-4WQmr67WcZRXg4smmN88s,35914
|
|
87
87
|
qubx/core/deque.py,sha256=3PsmJ5LF76JpsK4Wp5LLogyE15rKn6EDCkNOOWT6EOk,6203
|
|
88
88
|
qubx/core/detectors/__init__.py,sha256=Jv9BC6UaJlHKQoGfmPURwYc4NxHbRsg9UDxsom8I83U,170
|
|
89
89
|
qubx/core/detectors/delisting.py,sha256=DZ9-XjkVB4cnEyNt05ZAGh9XAVN3VWB2rHtIu6lQVeo,2917
|
|
@@ -103,11 +103,11 @@ qubx/core/mixins/subscription.py,sha256=2nUikNNPsMExS9yO38kNt7jk1vKE-RPm0b3h1bU6
|
|
|
103
103
|
qubx/core/mixins/trading.py,sha256=jW4P6Gba0O1kaQIy5rl3UqwPwAmEJrMdGYoWj1AhleI,20422
|
|
104
104
|
qubx/core/mixins/universe.py,sha256=aj1Ai_WUccotBt419SMPgAf2xPZL5n0U9CdTD4tQGGI,10845
|
|
105
105
|
qubx/core/mixins/utils.py,sha256=P71cLuqKjId8989MwOL_BtvvCnnwOFMkZyB1SY-0Ork,147
|
|
106
|
-
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
106
|
+
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=dWFUsV8CwrW_1whGbRD1kHSw50IyI-mOX6D7mgBEmfg,1192328
|
|
107
107
|
qubx/core/series.pxd,sha256=DebCNOl7e7_OIZLTG-vSqubcgYuE0EC2_0-dov7QoIM,5195
|
|
108
108
|
qubx/core/series.pyi,sha256=5xJ0-_SOGhfGgbu1RGyjP4b0T6oRyckS9LoRePPAHqs,8050
|
|
109
109
|
qubx/core/series.pyx,sha256=A-6BbaweFmeuwNvcg-yMrLPQodAFbjZeHqrVfvE2x-o,63520
|
|
110
|
-
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
110
|
+
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=juRYF4MEhxyTSHGuiqEH2fAE3TCmrnFmKGr6zLljuzM,86568
|
|
111
111
|
qubx/core/utils.pyi,sha256=a-wS13V2p_dM1CnGq40JVulmiAhixTwVwt0ah5By0Hc,348
|
|
112
112
|
qubx/core/utils.pyx,sha256=UR9achMR-LARsztd2eelFsDsFH3n0gXACIKoGNPI9X4,1766
|
|
113
113
|
qubx/data/__init__.py,sha256=cCUJjuq0LCBeeOKXIvBh_YQI00je_IQmr9OcHARJCPE,896
|
|
@@ -188,10 +188,10 @@ qubx/restorers/signal.py,sha256=5nK5ji8AucyWrFBK9uW619YCI_vPRGFnuDu8JnG3B_Y,1451
|
|
|
188
188
|
qubx/restorers/state.py,sha256=I1VIN0ZcOjigc3WMHIYTNJeAAbN9YB21MDcMl04ZWmY,8018
|
|
189
189
|
qubx/restorers/utils.py,sha256=We2gfqwQKWziUYhuUnjb-xo-5tSlbuHWpPQn0CEMTn0,1155
|
|
190
190
|
qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
191
|
-
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
192
|
-
qubx/ta/indicators.pxd,sha256=
|
|
193
|
-
qubx/ta/indicators.pyi,sha256=
|
|
194
|
-
qubx/ta/indicators.pyx,sha256=
|
|
191
|
+
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=Kt1Ryy6sMewT2MSYBfXAb0iyhKaK7Ia6OFZIK9cJh4k,1004488
|
|
192
|
+
qubx/ta/indicators.pxd,sha256=LpUPTN5Ja2gCP2SNBstjzhll2lW4hFFWfiS_kw_ChHA,7045
|
|
193
|
+
qubx/ta/indicators.pyi,sha256=3sNsNlzU9VQWrEqTeI5ZMjq8-lSQgoWeYqIP0k6w92E,4149
|
|
194
|
+
qubx/ta/indicators.pyx,sha256=mKv8g9C1TYhnewQSz4bjOFRqst-wTpGfJp4oBW18oXI,63109
|
|
195
195
|
qubx/templates/__init__.py,sha256=L2U6tX5DGhtIDRarIo3tHT7ZVQKNJMlpWn_sinJPevk,153
|
|
196
196
|
qubx/templates/base.py,sha256=cY9Lnvs8hvuqyyBwMN-p7rXWGETrbAx0zmE6Px19Ym4,6844
|
|
197
197
|
qubx/templates/project/accounts.toml.j2,sha256=LlaYWqOalMimGf7n_4sIzJk9p28tNbhZFogg3SHplSQ,637
|
|
@@ -223,7 +223,7 @@ qubx/utils/charting/orderbook.py,sha256=NmeXxru3CUiKLtl1DzCBbQgSdL4qmTDIxV0u81p2
|
|
|
223
223
|
qubx/utils/collections.py,sha256=go2sH_q2TlXqI3Vxq8GHLfNGlYL4JwS3X1lwJWbpFLE,7425
|
|
224
224
|
qubx/utils/hft/__init__.py,sha256=rZjNmRtD1TWAEe7JPgiak9qJftf8yQavLviWReKQJ5w,101
|
|
225
225
|
qubx/utils/hft/numba_utils.py,sha256=C_C3MwEW5ZbLhOMSH6SSYbQ7BfnvuKhgOtY_N-U-ULM,146
|
|
226
|
-
qubx/utils/hft/orderbook.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
226
|
+
qubx/utils/hft/orderbook.cpython-312-x86_64-linux-gnu.so,sha256=U4gOB0lPI0bmrF4huPzczcGYPSN5QtMrNjaFqd7hmZk,316592
|
|
227
227
|
qubx/utils/hft/orderbook.pyi,sha256=F2P9kbh314wjCwfn6BivFWQMEDMLnZDQ2rmWbGoM7-o,5076
|
|
228
228
|
qubx/utils/hft/orderbook.pyx,sha256=gbNrtpNRZjZ8DjXjrIXsw20UixErDrLzN-8Qep8sSJg,15217
|
|
229
229
|
qubx/utils/marketdata/binance.py,sha256=hWX3noZj704JIMBqlwsXA5IzUP7EgiLiC2r12dJAKQA,11565
|
|
@@ -242,7 +242,7 @@ qubx/utils/plotting/renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
|
242
242
|
qubx/utils/plotting/renderers/plotly.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
243
243
|
qubx/utils/questdb.py,sha256=fIOMImSa3N3eZKMakHqs5q5ld4m5jkG6IkrTGfuvXFg,5191
|
|
244
244
|
qubx/utils/rate_limiter.py,sha256=nI4yJ2VjTGoHYPQvURyd7rtpfn37ms6xd0hLt6RJeDc,7008
|
|
245
|
-
qubx/utils/ringbuffer.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
245
|
+
qubx/utils/ringbuffer.cpython-312-x86_64-linux-gnu.so,sha256=UkbrxqK7zjjATiPiTItB37lBMlIWijI6OjRjXkBi6wY,108328
|
|
246
246
|
qubx/utils/ringbuffer.pxd,sha256=NiLNnVwSJuDZj6M99DnHt07OEhKVBlEEf80rNukJJeQ,374
|
|
247
247
|
qubx/utils/ringbuffer.pyi,sha256=H0MD68jctVlko09KfxI9-1MloapO5Ba6smaqx1_X5Zo,4580
|
|
248
248
|
qubx/utils/ringbuffer.pyx,sha256=3S8MQreAKMfhaMm3RwztfEQ2AJYDyfPQpfMAsb-JCWA,7069
|
|
@@ -270,8 +270,8 @@ qubx/utils/slack.py,sha256=jhos-5pNGomg3TvFZRVvF0b_FrzxfvnTqAEMlDIrgn8,12234
|
|
|
270
270
|
qubx/utils/time.py,sha256=SYOiz2UqX7dCUhO_vBeWcm42_LmDl-59wp7INu0R8is,15355
|
|
271
271
|
qubx/utils/version.py,sha256=e52fIHyxzCiIuH7svCF6pkHuDlqL64rklqz-2XjWons,5309
|
|
272
272
|
qubx/utils/websocket_manager.py,sha256=ld4jvwnWyIkdKpgpUzyfnXGT3Ul4bGemXjy4HX9XTKs,17182
|
|
273
|
-
qubx-0.7.
|
|
274
|
-
qubx-0.7.
|
|
275
|
-
qubx-0.7.
|
|
276
|
-
qubx-0.7.
|
|
277
|
-
qubx-0.7.
|
|
273
|
+
qubx-0.7.9.dist-info/METADATA,sha256=QBXAFLX51Co8jGvbGESwFjyO7t8XCeBmVA52H6TUqC4,6062
|
|
274
|
+
qubx-0.7.9.dist-info/WHEEL,sha256=RA6gLSyyVpI0R7d3ofBrM1iY5kDUsPwh15AF0XpvgQo,110
|
|
275
|
+
qubx-0.7.9.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
|
|
276
|
+
qubx-0.7.9.dist-info/licenses/LICENSE,sha256=qwMHOSJ2TD0nx6VUJvFhu1ynJdBfNozRMt6tnSul-Ts,35140
|
|
277
|
+
qubx-0.7.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|