Qubx 0.2.72__cp311-cp311-manylinux_2_35_x86_64.whl → 0.2.74__cp311-cp311-manylinux_2_35_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/ome.py +12 -3
- qubx/backtester/optimization.py +41 -5
- qubx/backtester/simulator.py +100 -7
- qubx/core/helpers.py +3 -3
- qubx/core/series.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/core/series.pyi +6 -1
- qubx/core/utils.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/data/readers.py +0 -3
- qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/trackers/riskctrl.py +10 -1
- qubx/utils/time.py +1 -1
- {qubx-0.2.72.dist-info → qubx-0.2.74.dist-info}/METADATA +1 -1
- {qubx-0.2.72.dist-info → qubx-0.2.74.dist-info}/RECORD +14 -14
- {qubx-0.2.72.dist-info → qubx-0.2.74.dist-info}/WHEEL +0 -0
qubx/backtester/ome.py
CHANGED
|
@@ -43,9 +43,15 @@ class OrdersManagementEngine:
|
|
|
43
43
|
bbo: Quote | None # current best bid/ask order book (simplest impl)
|
|
44
44
|
__order_id: int
|
|
45
45
|
__trade_id: int
|
|
46
|
+
_fill_stops_at_price: bool
|
|
46
47
|
|
|
47
48
|
def __init__(
|
|
48
|
-
self,
|
|
49
|
+
self,
|
|
50
|
+
instrument: Instrument,
|
|
51
|
+
time_provider: ITimeProvider,
|
|
52
|
+
tcc: TransactionCostsCalculator,
|
|
53
|
+
fill_stop_order_at_price: bool = False, # emulate stop orders execution at order's exact limit price
|
|
54
|
+
debug: bool = True,
|
|
49
55
|
) -> None:
|
|
50
56
|
self.instrument = instrument
|
|
51
57
|
self.time_service = time_provider
|
|
@@ -57,6 +63,7 @@ class OrdersManagementEngine:
|
|
|
57
63
|
self.bbo = None
|
|
58
64
|
self.__order_id = 100000
|
|
59
65
|
self.__trade_id = 100000
|
|
66
|
+
self._fill_stops_at_price = fill_stop_order_at_price
|
|
60
67
|
if not debug:
|
|
61
68
|
self._dbg = lambda message, **kwargs: None
|
|
62
69
|
|
|
@@ -96,12 +103,14 @@ class OrdersManagementEngine:
|
|
|
96
103
|
# - processing stop orders
|
|
97
104
|
for soid in list(self.stop_orders.keys()):
|
|
98
105
|
so = self.stop_orders[soid]
|
|
106
|
+
_emulate_price_exec = self._fill_stops_at_price or so.options.get(OPTION_FILL_AT_SIGNAL_PRICE, False)
|
|
107
|
+
|
|
99
108
|
if so.side == "BUY" and quote.ask >= so.price:
|
|
100
|
-
_exec_price = quote.ask if not
|
|
109
|
+
_exec_price = quote.ask if not _emulate_price_exec else so.price
|
|
101
110
|
self.stop_orders.pop(soid)
|
|
102
111
|
rep.append(self._execute_order(timestamp, _exec_price, so, True))
|
|
103
112
|
elif so.side == "SELL" and quote.bid <= so.price:
|
|
104
|
-
_exec_price = quote.bid if not
|
|
113
|
+
_exec_price = quote.bid if not _emulate_price_exec else so.price
|
|
105
114
|
self.stop_orders.pop(soid)
|
|
106
115
|
rep.append(self._execute_order(timestamp, _exec_price, so, True))
|
|
107
116
|
|
qubx/backtester/optimization.py
CHANGED
|
@@ -90,7 +90,41 @@ def permutate_params(
|
|
|
90
90
|
return _wrap_single_list(result) if wrap_as_list else result
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def
|
|
93
|
+
def dicts_product(d1: dict, d2: dict) -> dict:
|
|
94
|
+
"""
|
|
95
|
+
Product of two dictionaries.
|
|
96
|
+
|
|
97
|
+
Example:
|
|
98
|
+
-------
|
|
99
|
+
|
|
100
|
+
dicts_product({
|
|
101
|
+
'A': 1,
|
|
102
|
+
'B': 2,
|
|
103
|
+
}, {
|
|
104
|
+
'C': 3,
|
|
105
|
+
'D': 4,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
Output:
|
|
109
|
+
------
|
|
110
|
+
{
|
|
111
|
+
'A + C': [1, 3],
|
|
112
|
+
'A + D': [1, 4],
|
|
113
|
+
'B + C': [2, 3],
|
|
114
|
+
'B + D': [2, 4]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
flatten = lambda l: [item for sublist in l for item in (sublist if isinstance(sublist, list) else [sublist])]
|
|
119
|
+
return {(a + " + " + b): flatten([d1[a], d2[b]]) for a, b in product(d1.keys(), d2.keys())}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class _dict(dict):
|
|
123
|
+
def __add__(self, other: dict) -> dict:
|
|
124
|
+
return _dict(dicts_product(self, other))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def variate(clz: Type[Any] | List[Type[Any]], *args, conditions=None, **kwargs) -> _dict:
|
|
94
128
|
"""
|
|
95
129
|
Make variations of parameters for simulations (micro optimizer)
|
|
96
130
|
|
|
@@ -149,7 +183,9 @@ def variate(clz: Type[Any] | List[Type[Any]], *args, conditions=None, **kwargs)
|
|
|
149
183
|
to_excl = [s for s, v in kwargs.items() if not isinstance(v, (list, set, tuple, range))]
|
|
150
184
|
dic2str = lambda ds: [_cmprss(k) + "=" + str(v) for k, v in ds.items() if k not in to_excl]
|
|
151
185
|
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
186
|
+
return _dict(
|
|
187
|
+
{
|
|
188
|
+
f"{sfx}_({ ','.join(dic2str(z)) })": _mk(clz, *args, **z)
|
|
189
|
+
for z in permutate_params(kwargs, conditions=conditions)
|
|
190
|
+
}
|
|
191
|
+
)
|
qubx/backtester/simulator.py
CHANGED
|
@@ -142,8 +142,8 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
142
142
|
First implementation of a simulated broker.
|
|
143
143
|
TODO:
|
|
144
144
|
1. Add margin control
|
|
145
|
-
2. Need to solve problem with _get_ohlcv_data_sync (actually this method must be removed from here)
|
|
146
|
-
3. Add support for stop orders (not urgent)
|
|
145
|
+
2. Need to solve problem with _get_ohlcv_data_sync (actually this method must be removed from here) [DONE]
|
|
146
|
+
3. Add support for stop orders (not urgent) [DONE]
|
|
147
147
|
"""
|
|
148
148
|
|
|
149
149
|
_current_time: dt_64
|
|
@@ -152,13 +152,40 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
152
152
|
_fees_calculator: TransactionCostsCalculator | None
|
|
153
153
|
_order_to_symbol: Dict[str, str]
|
|
154
154
|
_half_tick_size: Dict[str, float]
|
|
155
|
+
_fill_stop_order_at_price: bool
|
|
155
156
|
|
|
156
157
|
def __init__(
|
|
157
158
|
self,
|
|
158
159
|
name: str,
|
|
159
160
|
commissions: str | None = None,
|
|
160
161
|
simulation_initial_time: dt_64 | str = np.datetime64(0, "ns"),
|
|
162
|
+
accurate_stop_orders_execution: bool = False,
|
|
161
163
|
) -> None:
|
|
164
|
+
"""
|
|
165
|
+
This function sets up a simulated trading environment with following parameters.
|
|
166
|
+
|
|
167
|
+
Parameters:
|
|
168
|
+
-----------
|
|
169
|
+
name : str
|
|
170
|
+
The name of the simulated trading environment.
|
|
171
|
+
commissions : str | None, optional
|
|
172
|
+
The commission structure to be used. If None, no commissions will be applied.
|
|
173
|
+
Default is None.
|
|
174
|
+
simulation_initial_time : dt_64 | str, optional
|
|
175
|
+
The initial time for the simulation. Can be a dt_64 object or a string.
|
|
176
|
+
Default is np.datetime64(0, "ns").
|
|
177
|
+
accurate_stop_orders_execution : bool, optional
|
|
178
|
+
If True, stop orders will be executed at the exact stop order's price.
|
|
179
|
+
If False, they may be executed at the next quote that could lead to
|
|
180
|
+
significant slippage especially if simuation run on OHLC data.
|
|
181
|
+
Default is False.
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
-------
|
|
185
|
+
ValueError
|
|
186
|
+
If the fees configuration is not found for the given name.
|
|
187
|
+
|
|
188
|
+
"""
|
|
162
189
|
self._current_time = (
|
|
163
190
|
np.datetime64(simulation_initial_time, "ns")
|
|
164
191
|
if isinstance(simulation_initial_time, str)
|
|
@@ -168,6 +195,7 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
168
195
|
self._ome = {}
|
|
169
196
|
self._fees_calculator = lookup.fees.find(name.lower(), commissions)
|
|
170
197
|
self._half_tick_size = {}
|
|
198
|
+
self._fill_stop_order_at_price = accurate_stop_orders_execution
|
|
171
199
|
|
|
172
200
|
self._order_to_symbol = {}
|
|
173
201
|
if self._fees_calculator is None:
|
|
@@ -177,6 +205,8 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
177
205
|
|
|
178
206
|
# - we want to see simulate time in log messages
|
|
179
207
|
QubxLogConfig.setup_logger(QubxLogConfig.get_log_level(), _SimulatedLogFormatter(self).formatter)
|
|
208
|
+
if self._fill_stop_order_at_price:
|
|
209
|
+
logger.info(f"SimulatedExchangeService emulates stop orders executions at exact price")
|
|
180
210
|
|
|
181
211
|
def send_order(
|
|
182
212
|
self,
|
|
@@ -195,8 +225,8 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
195
225
|
|
|
196
226
|
# - try to place order in OME
|
|
197
227
|
report = ome.place_order(
|
|
198
|
-
order_side.upper(),
|
|
199
|
-
order_type.upper(),
|
|
228
|
+
order_side.upper(), # type: ignore
|
|
229
|
+
order_type.upper(), # type: ignore
|
|
200
230
|
amount,
|
|
201
231
|
price,
|
|
202
232
|
client_id,
|
|
@@ -254,7 +284,12 @@ class SimulatedTrading(ITradingServiceProvider):
|
|
|
254
284
|
|
|
255
285
|
if symbol not in self.acc._positions:
|
|
256
286
|
# - initiolize OME for this instrument
|
|
257
|
-
self._ome[instrument.symbol] = OrdersManagementEngine(
|
|
287
|
+
self._ome[instrument.symbol] = OrdersManagementEngine(
|
|
288
|
+
instrument=instrument,
|
|
289
|
+
time_provider=self,
|
|
290
|
+
tcc=self._fees_calculator, # type: ignore
|
|
291
|
+
fill_stop_order_at_price=self._fill_stop_order_at_price,
|
|
292
|
+
)
|
|
258
293
|
|
|
259
294
|
# - initiolize empty position
|
|
260
295
|
position = Position(instrument) # type: ignore
|
|
@@ -521,7 +556,7 @@ class SimulatedExchange(IBrokerServiceProvider):
|
|
|
521
556
|
# we have to schedule possible crons before sending the data event itself
|
|
522
557
|
if self._scheduler.check_and_run_tasks():
|
|
523
558
|
# - push nothing - it will force to process last event
|
|
524
|
-
cc.send((None, "
|
|
559
|
+
cc.send((None, "service_time", None))
|
|
525
560
|
|
|
526
561
|
cc.send((symbol, data_type, data))
|
|
527
562
|
|
|
@@ -693,8 +728,57 @@ def simulate(
|
|
|
693
728
|
n_jobs: int = 1,
|
|
694
729
|
silent: bool = False,
|
|
695
730
|
enable_event_batching: bool = True,
|
|
731
|
+
accurate_stop_orders_execution: bool = False,
|
|
696
732
|
debug: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = "WARNING",
|
|
697
733
|
) -> list[TradingSessionResult]:
|
|
734
|
+
"""
|
|
735
|
+
Backtest utility for trading strategies or signals using historical data.
|
|
736
|
+
|
|
737
|
+
Parameters:
|
|
738
|
+
----------
|
|
739
|
+
|
|
740
|
+
config (StrategyOrSignals | Dict | List[StrategyOrSignals | PositionsTracker]):
|
|
741
|
+
Trading strategy or signals configuration.
|
|
742
|
+
data (Dict[str, pd.DataFrame] | DataReader):
|
|
743
|
+
Historical data for simulation, either as a dictionary of DataFrames or a DataReader object.
|
|
744
|
+
capital (float):
|
|
745
|
+
Initial capital for the simulation.
|
|
746
|
+
instruments (List[str] | Dict[str, List[str]] | None):
|
|
747
|
+
List of trading instruments or a dictionary mapping exchanges to instrument lists.
|
|
748
|
+
subscription (Dict[str, Any]):
|
|
749
|
+
Subscription details for market data.
|
|
750
|
+
trigger (str | list[str]):
|
|
751
|
+
Trigger specification for strategy execution.
|
|
752
|
+
commissions (str):
|
|
753
|
+
Commission structure for trades.
|
|
754
|
+
start (str | pd.Timestamp):
|
|
755
|
+
Start time of the simulation.
|
|
756
|
+
stop (str | pd.Timestamp | None):
|
|
757
|
+
End time of the simulation. If None, simulates until the last accessible data.
|
|
758
|
+
fit (str | None):
|
|
759
|
+
Specification for strategy fitting, if applicable.
|
|
760
|
+
exchange (str | None):
|
|
761
|
+
Exchange name if not specified in the instruments list.
|
|
762
|
+
base_currency (str):
|
|
763
|
+
Base currency for the simulation, default is "USDT".
|
|
764
|
+
leverage (float):
|
|
765
|
+
Leverage factor for trading, default is 1.0.
|
|
766
|
+
n_jobs (int):
|
|
767
|
+
Number of parallel jobs for simulation, default is 1.
|
|
768
|
+
silent (bool):
|
|
769
|
+
If True, suppresses output during simulation.
|
|
770
|
+
enable_event_batching (bool):
|
|
771
|
+
If True, enables event batching for optimization.
|
|
772
|
+
accurate_stop_orders_execution (bool):
|
|
773
|
+
If True, enables more accurate stop order execution simulation.
|
|
774
|
+
debug (Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None):
|
|
775
|
+
Logging level for debugging.
|
|
776
|
+
|
|
777
|
+
Returns:
|
|
778
|
+
--------
|
|
779
|
+
list[TradingSessionResult]:
|
|
780
|
+
A list of TradingSessionResult objects containing the results of each simulation setup.
|
|
781
|
+
"""
|
|
698
782
|
|
|
699
783
|
# - setup logging
|
|
700
784
|
QubxLogConfig.set_log_level(debug.upper() if debug else "WARNING")
|
|
@@ -755,6 +839,7 @@ def simulate(
|
|
|
755
839
|
n_jobs=n_jobs,
|
|
756
840
|
silent=silent,
|
|
757
841
|
enable_event_batching=enable_event_batching,
|
|
842
|
+
accurate_stop_orders_execution=accurate_stop_orders_execution,
|
|
758
843
|
)
|
|
759
844
|
|
|
760
845
|
|
|
@@ -818,6 +903,7 @@ def _run_setups(
|
|
|
818
903
|
n_jobs: int = -1,
|
|
819
904
|
silent: bool = False,
|
|
820
905
|
enable_event_batching: bool = True,
|
|
906
|
+
accurate_stop_orders_execution: bool = False,
|
|
821
907
|
) -> List[TradingSessionResult]:
|
|
822
908
|
# loggers don't work well with joblib and multiprocessing in general because they contain
|
|
823
909
|
# open file handlers that cannot be pickled. I found a solution which requires the usage of enqueue=True
|
|
@@ -839,6 +925,7 @@ def _run_setups(
|
|
|
839
925
|
fit=fit,
|
|
840
926
|
silent=silent,
|
|
841
927
|
enable_event_batching=enable_event_batching,
|
|
928
|
+
accurate_stop_orders_execution=accurate_stop_orders_execution,
|
|
842
929
|
)
|
|
843
930
|
for id, s in enumerate(setups)
|
|
844
931
|
)
|
|
@@ -856,13 +943,19 @@ def _run_setup(
|
|
|
856
943
|
fit: str | None,
|
|
857
944
|
silent: bool = False,
|
|
858
945
|
enable_event_batching: bool = True,
|
|
946
|
+
accurate_stop_orders_execution: bool = False,
|
|
859
947
|
) -> TradingSessionResult:
|
|
860
948
|
_trigger = trigger
|
|
861
949
|
_stop = stop
|
|
862
950
|
logger.debug(
|
|
863
951
|
f"<red>{pd.Timestamp(start)}</red> Initiating simulated trading for {setup.exchange} for {setup.capital} x {setup.leverage} in {setup.base_currency}..."
|
|
864
952
|
)
|
|
865
|
-
broker = SimulatedTrading(
|
|
953
|
+
broker = SimulatedTrading(
|
|
954
|
+
setup.exchange,
|
|
955
|
+
setup.commissions,
|
|
956
|
+
np.datetime64(start, "ns"),
|
|
957
|
+
accurate_stop_orders_execution=accurate_stop_orders_execution,
|
|
958
|
+
)
|
|
866
959
|
exchange = SimulatedExchange(setup.exchange, broker, data_reader)
|
|
867
960
|
|
|
868
961
|
# - it will store simulation results into memory
|
qubx/core/helpers.py
CHANGED
|
@@ -300,9 +300,9 @@ class BasicScheduler:
|
|
|
300
300
|
next_time = iter.get_next(start_time=start_time)
|
|
301
301
|
if next_time:
|
|
302
302
|
self._scdlr.enterabs(next_time, 1, self._trigger, (event, prev_time, next_time))
|
|
303
|
-
logger.debug(
|
|
304
|
-
|
|
305
|
-
)
|
|
303
|
+
# logger.debug(
|
|
304
|
+
# f"Now is <red>{_SEC2TS(self.time_sec())}</red> next ({event}) at <cyan>{_SEC2TS(next_time)}</cyan>"
|
|
305
|
+
# )
|
|
306
306
|
return True
|
|
307
307
|
logger.debug(f"({event}) task is not scheduled")
|
|
308
308
|
return False
|
|
Binary file
|
qubx/core/series.pyi
CHANGED
|
@@ -4,12 +4,16 @@ from typing import Any, Tuple
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
|
|
6
6
|
class Bar:
|
|
7
|
+
time: int
|
|
7
8
|
open: float
|
|
8
9
|
high: float
|
|
9
10
|
low: float
|
|
10
11
|
close: float
|
|
11
12
|
volume: float
|
|
13
|
+
bought_volume: float
|
|
12
14
|
def __init__(self, time, open, high, low, close, volume, bought_volume=0): ...
|
|
15
|
+
def update(self, price: float, volume: float, bought_volume: float = 0) -> Bar: ...
|
|
16
|
+
def to_dict(self, skip_time: bool = False) -> dict: ...
|
|
13
17
|
|
|
14
18
|
class Quote:
|
|
15
19
|
time: int
|
|
@@ -44,8 +48,9 @@ class TimeSeries:
|
|
|
44
48
|
max_series_length: int
|
|
45
49
|
times: Indexed
|
|
46
50
|
values: Indexed
|
|
47
|
-
def __init__(self, name, timeframe, max_series_length, process_every_update=True) -> None: ...
|
|
51
|
+
def __init__(self, name, timeframe, max_series_length=np.inf, process_every_update=True) -> None: ...
|
|
48
52
|
def __getitem__(self, idx): ...
|
|
53
|
+
def __len__(self) -> int: ...
|
|
49
54
|
def update(self, time: int, value: float) -> bool: ...
|
|
50
55
|
def copy(self, start: int, stop: int) -> "TimeSeries": ...
|
|
51
56
|
def shift(self, period: int) -> TimeSeries: ...
|
|
Binary file
|
qubx/data/readers.py
CHANGED
|
@@ -1027,7 +1027,6 @@ class QuestDBSqlOrderBookBuilder(QuestDBSqlCandlesBuilder):
|
|
|
1027
1027
|
Sql builder for snapshot data
|
|
1028
1028
|
"""
|
|
1029
1029
|
|
|
1030
|
-
MAX_TIME_DELTA = pd.Timedelta("5h")
|
|
1031
1030
|
SNAPSHOT_DELTA = pd.Timedelta("1h")
|
|
1032
1031
|
MIN_DELTA = pd.Timedelta("1s")
|
|
1033
1032
|
|
|
@@ -1043,8 +1042,6 @@ class QuestDBSqlOrderBookBuilder(QuestDBSqlCandlesBuilder):
|
|
|
1043
1042
|
raise ValueError("Start and end dates must be provided for orderbook data!")
|
|
1044
1043
|
start_dt, end_dt = pd.Timestamp(start), pd.Timestamp(end)
|
|
1045
1044
|
delta = end_dt - start_dt
|
|
1046
|
-
if delta > self.MAX_TIME_DELTA:
|
|
1047
|
-
raise ValueError(f"Time range is too big for orderbook data: {delta}, max allowed: {self.MAX_TIME_DELTA}")
|
|
1048
1045
|
|
|
1049
1046
|
raw_start_dt = start_dt.floor(self.SNAPSHOT_DELTA) - self.MIN_DELTA
|
|
1050
1047
|
|
|
Binary file
|
qubx/trackers/riskctrl.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import Dict, List, Literal
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
7
7
|
from qubx import logger
|
|
8
|
-
from qubx.core.basics import Deal, Instrument, Signal, TargetPosition
|
|
8
|
+
from qubx.core.basics import Deal, Instrument, OrderStatus, Signal, TargetPosition
|
|
9
9
|
from qubx.core.series import Bar, Quote, Trade
|
|
10
10
|
from qubx.core.strategy import IPositionSizer, PositionsTracker, StrategyContext
|
|
11
11
|
from qubx.trackers.sizers import FixedRiskSizer, FixedSizer
|
|
@@ -270,6 +270,15 @@ class BrokerSideRiskController(RiskController):
|
|
|
270
270
|
)
|
|
271
271
|
order = ctx.trade(instrument, -pos, c_w.target.take)
|
|
272
272
|
c_w.take_order_id = order.id
|
|
273
|
+
|
|
274
|
+
# - if order was executed immediately we don't need to send stop order
|
|
275
|
+
if order.status == "CLOSED":
|
|
276
|
+
c_w.status = State.RISK_TRIGGERED
|
|
277
|
+
logger.debug(
|
|
278
|
+
f"<yellow>{self.__class__.__name__}</yellow> <g>TAKE PROFIT</g> was exected immediately for <green>{instrument.symbol}</green> at {c_w.target.take}"
|
|
279
|
+
)
|
|
280
|
+
return
|
|
281
|
+
|
|
273
282
|
except Exception as e:
|
|
274
283
|
logger.error(
|
|
275
284
|
f"<yellow>{self.__class__.__name__}</yellow> couldn't send take limit order for <green>{instrument.symbol}</green>: {str(e)}"
|
qubx/utils/time.py
CHANGED
|
@@ -113,7 +113,7 @@ def infer_series_frequency(series: Union[List, pd.DataFrame, pd.Series, pd.Datet
|
|
|
113
113
|
[
|
|
114
114
|
(
|
|
115
115
|
x
|
|
116
|
-
if isinstance(x, (np.timedelta64, int))
|
|
116
|
+
if isinstance(x, (np.timedelta64, int, np.int64))
|
|
117
117
|
else int(x) if isinstance(x, float) else int(1e9 * x.total_seconds())
|
|
118
118
|
)
|
|
119
119
|
for x in np.abs(np.diff(times_index))
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
qubx/__init__.py,sha256=dIHcfXv3uDX-kJ6qRGrH5OUW7evnGFf6A2VsLQlr2jc,6047
|
|
2
2
|
qubx/_nb_magic.py,sha256=vfV892I5rkA_Zbno5Dsl9osPTGiXTCV3afZRDrTlcOQ,1915
|
|
3
3
|
qubx/backtester/__init__.py,sha256=g9K4pp4ieY4rRKE0eA_02LMo-c4vnk-QqtVn_ff9F5U,66
|
|
4
|
-
qubx/backtester/ome.py,sha256=
|
|
5
|
-
qubx/backtester/optimization.py,sha256=
|
|
4
|
+
qubx/backtester/ome.py,sha256=FmtRMDCeEo8ZZP-yLswLilX6zx6SjJeieMiaLS7zrn0,11145
|
|
5
|
+
qubx/backtester/optimization.py,sha256=ATHoiEGwbDIk0-lbFIxvVDmH_f-vtS10YV41pfOTCBA,7297
|
|
6
6
|
qubx/backtester/queue.py,sha256=ys9tHyrqx3NKbcoTAoOn0m0caIk5F0GpS2x7_sCikro,14997
|
|
7
|
-
qubx/backtester/simulator.py,sha256=
|
|
7
|
+
qubx/backtester/simulator.py,sha256=t4VBrE4lSqn2LfZddtZ6X5CZ9FfJe3xuZpF34R9bkF0,38188
|
|
8
8
|
qubx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
qubx/core/account.py,sha256=uIU-EUMuH5owWhHTmU1pZ0WrkQkiv9YiFqSZW9dFDK8,9066
|
|
10
10
|
qubx/core/basics.py,sha256=WA6LrmCG1si6pfyvezLRkfts575912AhGJMVbwBWSa0,21802
|
|
11
11
|
qubx/core/context.py,sha256=WnHsItJ1OQ2jD0cHbYOMQ9ck4txLTwtf8Dp-zCLsUww,37759
|
|
12
12
|
qubx/core/exceptions.py,sha256=W1gG_0fE3o2EMGUfOeOl3vVJDp8Z1iHLv4iZ0ThNkTs,306
|
|
13
|
-
qubx/core/helpers.py,sha256=
|
|
13
|
+
qubx/core/helpers.py,sha256=R-xi4lgmYvWpUARIYcbcrNrRlEap5wc-GQ5sE4riUxQ,12663
|
|
14
14
|
qubx/core/loggers.py,sha256=zpehm2-RdKG1ISe6t3DiM3RrL_zzGni3YFcxfgDkV24,16575
|
|
15
15
|
qubx/core/lookups.py,sha256=qGOSb2SIxmgVPGJFLJnPDI1P9hCzFMVipRDcVLUm8qk,14599
|
|
16
16
|
qubx/core/metrics.py,sha256=pL1obxnk8I7bDF41bQcOZ7MDsq4Wmj6g5cRiV7cFZKQ,38657
|
|
17
|
-
qubx/core/series.cpython-311-x86_64-linux-gnu.so,sha256=
|
|
17
|
+
qubx/core/series.cpython-311-x86_64-linux-gnu.so,sha256=bga9gkSEn5IAUqeZLygh0kmiszqDvRu9D0bHjlXLaz4,779016
|
|
18
18
|
qubx/core/series.pxd,sha256=kF7QeLFgCM-C2hDxVvJM97ZOmyw1v7JEI9WfPKtQ6xs,3002
|
|
19
|
-
qubx/core/series.pyi,sha256=
|
|
19
|
+
qubx/core/series.pyi,sha256=bRBWOaDUBe4Hm2SvraoVeT-n5NFLA92fi8ezrArx9nY,2831
|
|
20
20
|
qubx/core/series.pyx,sha256=UhZsnT7R3-UED05Fnp3mGxr4RSdMpWAHB4lkcz46MFo,32598
|
|
21
21
|
qubx/core/strategy.py,sha256=tTXhDbFTH63yj53mLgVEDBZxYOxC51prcsyXWkdTgLs,10991
|
|
22
|
-
qubx/core/utils.cpython-311-x86_64-linux-gnu.so,sha256=
|
|
22
|
+
qubx/core/utils.cpython-311-x86_64-linux-gnu.so,sha256=nNrBMQLcCCa3s9k8LvVAiQzLyA0aehqeJDl4Un5o8zs,82504
|
|
23
23
|
qubx/core/utils.pyi,sha256=DAjyRVPJSxK4Em-9wui2F0yYHfP5tI5DjKavXNOnHa8,276
|
|
24
24
|
qubx/core/utils.pyx,sha256=-8ek58CrbqWZq0-OY7WSREsCXBoBeWrD_wEYbIBS9rI,1696
|
|
25
25
|
qubx/data/helpers.py,sha256=A0NGzhpXYWD92-GeB8TghwMnR0NW8bjcNJOCXybQw3g,782
|
|
26
|
-
qubx/data/readers.py,sha256=
|
|
26
|
+
qubx/data/readers.py,sha256=ACs-6R2F_WXB1nw5azVYPLK5NgwJete4mCMoo16mXNY,39324
|
|
27
27
|
qubx/gathering/simplest.py,sha256=Ez3YFZMKH3o0jV0Qbg1SuZiuFNs_5No_C7wZ6vOeqfo,3814
|
|
28
28
|
qubx/impl/ccxt_connector.py,sha256=ja_0WJDyZfkzqhNvoV-c5CCg15YnbRIThxw0TTNdwcc,13066
|
|
29
29
|
qubx/impl/ccxt_customizations.py,sha256=WUhDT9x2SYuFrOyBIbk2D9Q_U_5QZhtLomLq88Egf_c,6230
|
|
@@ -35,14 +35,14 @@ qubx/pandaz/__init__.py,sha256=Iw5uzicYGSC3FEKZ-W1O5-7cXq_P0kH11-EcXV0zZhs,175
|
|
|
35
35
|
qubx/pandaz/ta.py,sha256=NthiiueUoqWGRcjovcKKThcCcdImZn3JRdWDA2vL28k,85075
|
|
36
36
|
qubx/pandaz/utils.py,sha256=XB28Zwv3cXWbKFXbcV5QGj_d6w-i8Yo4LYkX8aPuCHo,19613
|
|
37
37
|
qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so,sha256
|
|
38
|
+
qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so,sha256=q6UuYHbUdnt7DX0iwsZsIGU5I-tIZdwmB4ugpGw3mW4,576168
|
|
39
39
|
qubx/ta/indicators.pxd,sha256=YzPDhbbNPmy3m4NafwIRF5sNFsmkq-MM1gbeAygtBwM,4007
|
|
40
40
|
qubx/ta/indicators.pyi,sha256=mM_7ISmGQDgjhwxCoZXDw7Rm9fynQSYjevV7fRoLdNc,1683
|
|
41
41
|
qubx/ta/indicators.pyx,sha256=GuxB63YApFnA9IWNJDbBt90J1sOoxTf3jDWYQ3uD9So,24306
|
|
42
42
|
qubx/trackers/__init__.py,sha256=-Hmlc8Mpdi_t6kyeW4ZtmYkHzrULaIb6gUsAkhUxA-4,169
|
|
43
43
|
qubx/trackers/composite.py,sha256=rYQCaxu4IKLf5sS3DCyUUJaSUQwbCy6UMoVjsS-481A,6222
|
|
44
44
|
qubx/trackers/rebalancers.py,sha256=dp-jemxczT8ndkjjzljsIgGnnA6lZQhsf5c4YdmHKCw,6048
|
|
45
|
-
qubx/trackers/riskctrl.py,sha256=
|
|
45
|
+
qubx/trackers/riskctrl.py,sha256=URRZmYgb1-jcW4RTb2QXUozTnBiGhFEWHtTEjaqow5Q,23491
|
|
46
46
|
qubx/trackers/sizers.py,sha256=vh49p2I_5LxYfznOQxlM6f0K1wadgtz7y9NSxg3WdNQ,5953
|
|
47
47
|
qubx/utils/__init__.py,sha256=AL2YibJ3tqBKsZZLUjM9N2J5yy-Kq__k_44oTODQ5sM,321
|
|
48
48
|
qubx/utils/_pyxreloader.py,sha256=FyqGzfSpZGYziB8JYS5AP3cLRAvJSIPAKgwQn0E4YQ0,12017
|
|
@@ -52,7 +52,7 @@ qubx/utils/marketdata/binance.py,sha256=36dl4rxOAGTeY3uoONmiPanj8BkP0oBdDiH-URJJ
|
|
|
52
52
|
qubx/utils/misc.py,sha256=Av0mhrPCy5NZRrRmjOAhTKusa8wVdL7vCQtEy9bVnz4,10450
|
|
53
53
|
qubx/utils/ntp.py,sha256=LZo4FPVY3rqLUV9VWkLcZaPOpUDFC8Qleynmfggg9No,1758
|
|
54
54
|
qubx/utils/runner.py,sha256=Czo01KUCc9Oj9TIcs03d6Qh7fOpQV5w8oH6UDZ6Yqn0,9539
|
|
55
|
-
qubx/utils/time.py,sha256=
|
|
56
|
-
qubx-0.2.
|
|
57
|
-
qubx-0.2.
|
|
58
|
-
qubx-0.2.
|
|
55
|
+
qubx/utils/time.py,sha256=fIVWYRmqRT1zkLIWy9jo_Fpfpc03S0sYyOcrHZcfF74,5198
|
|
56
|
+
qubx-0.2.74.dist-info/METADATA,sha256=E13FYFtRhfp4cgM5WA25tF5WgSfeaCb_HlYAaz7gKyc,2573
|
|
57
|
+
qubx-0.2.74.dist-info/WHEEL,sha256=MLOa6LysROdjgj4FVxsHitAnIh8Be2D_c9ZSBHKrz2M,110
|
|
58
|
+
qubx-0.2.74.dist-info/RECORD,,
|
|
File without changes
|