Qubx 0.1.6__cp311-cp311-manylinux_2_35_x86_64.whl → 0.1.7__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/core/series.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/core/utils.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/data/readers.py +80 -14
- qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so +0 -0
- {qubx-0.1.6.dist-info → qubx-0.1.7.dist-info}/METADATA +1 -1
- {qubx-0.1.6.dist-info → qubx-0.1.7.dist-info}/RECORD +7 -7
- {qubx-0.1.6.dist-info → qubx-0.1.7.dist-info}/WHEEL +0 -0
|
Binary file
|
|
Binary file
|
qubx/data/readers.py
CHANGED
|
@@ -29,6 +29,13 @@ def _recognize_t(t: Union[int, str], defaultvalue, timeunit) -> int:
|
|
|
29
29
|
return defaultvalue
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
def _time(t, timestamp_units: str) -> int:
|
|
33
|
+
t = int(t) if isinstance(t, float) else t
|
|
34
|
+
if timestamp_units == 'ns':
|
|
35
|
+
return np.datetime64(t, 'ns').item()
|
|
36
|
+
return np.datetime64(t, timestamp_units).astype('datetime64[ns]').item()
|
|
37
|
+
|
|
38
|
+
|
|
32
39
|
def _find_column_index_in_list(xs, *args):
|
|
33
40
|
xs = [x.lower() for x in xs]
|
|
34
41
|
for a in args:
|
|
@@ -38,6 +45,9 @@ def _find_column_index_in_list(xs, *args):
|
|
|
38
45
|
raise IndexError(f"Can't find any from {args} in list: {xs}")
|
|
39
46
|
|
|
40
47
|
|
|
48
|
+
_FIND_TIME_COL_IDX = lambda column_names: _find_column_index_in_list(column_names, 'time', 'timestamp', 'datetime', 'date', 'open_time')
|
|
49
|
+
|
|
50
|
+
|
|
41
51
|
class DataTransformer:
|
|
42
52
|
|
|
43
53
|
def __init__(self) -> None:
|
|
@@ -121,9 +131,9 @@ class CsvStorageDataReader(DataReader):
|
|
|
121
131
|
# - try to find range to load
|
|
122
132
|
start_idx, stop_idx = 0, table.num_rows
|
|
123
133
|
try:
|
|
124
|
-
_time_field_idx =
|
|
134
|
+
_time_field_idx = _FIND_TIME_COL_IDX(fieldnames)
|
|
125
135
|
_time_type = table.field(_time_field_idx).type
|
|
126
|
-
_time_unit = _time_type.unit if hasattr(_time_type, 'unit') else '
|
|
136
|
+
_time_unit = _time_type.unit if hasattr(_time_type, 'unit') else 'ms'
|
|
127
137
|
_time_data = table[_time_field_idx]
|
|
128
138
|
|
|
129
139
|
# - check if need convert time to primitive types (i.e. Date32 -> timestamp[x])
|
|
@@ -181,9 +191,11 @@ class AsPandasFrame(DataTransformer):
|
|
|
181
191
|
"""
|
|
182
192
|
List of records to pandas dataframe transformer
|
|
183
193
|
"""
|
|
194
|
+
def __init__(self, timestamp_units=None) -> None:
|
|
195
|
+
self.timestamp_units = timestamp_units
|
|
184
196
|
|
|
185
197
|
def start_transform(self, name: str, column_names: List[str]):
|
|
186
|
-
self._time_idx =
|
|
198
|
+
self._time_idx = _FIND_TIME_COL_IDX(column_names)
|
|
187
199
|
self._column_names = column_names
|
|
188
200
|
self._frame = pd.DataFrame()
|
|
189
201
|
|
|
@@ -191,6 +203,8 @@ class AsPandasFrame(DataTransformer):
|
|
|
191
203
|
self._frame
|
|
192
204
|
p = pd.DataFrame.from_records(rows_data, columns=self._column_names)
|
|
193
205
|
p.set_index(self._column_names[self._time_idx], drop=True, inplace=True)
|
|
206
|
+
p.index = pd.to_datetime(p.index, unit=self.timestamp_units) if self.timestamp_units else p.index
|
|
207
|
+
p.index.rename('timestamp', inplace=True)
|
|
194
208
|
p.sort_index(inplace=True)
|
|
195
209
|
self._frame = pd.concat((self._frame, p), axis=0, sort=True)
|
|
196
210
|
return p
|
|
@@ -200,6 +214,17 @@ class AsPandasFrame(DataTransformer):
|
|
|
200
214
|
|
|
201
215
|
|
|
202
216
|
class AsOhlcvSeries(DataTransformer):
|
|
217
|
+
"""
|
|
218
|
+
Convert incoming data into OHLCV series.
|
|
219
|
+
|
|
220
|
+
Incoming data may have one of the following structures:
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
ohlcv: time,open,high,low,close,volume|quote_volume,(buy_volume)
|
|
224
|
+
quotes: time,bid,ask,bidsize,asksize
|
|
225
|
+
trades (TAS): time,price,size,(is_taker)
|
|
226
|
+
```
|
|
227
|
+
"""
|
|
203
228
|
|
|
204
229
|
def __init__(self, timeframe: str | None = None, timestamp_units='ns') -> None:
|
|
205
230
|
super().__init__()
|
|
@@ -209,7 +234,7 @@ class AsOhlcvSeries(DataTransformer):
|
|
|
209
234
|
self.timestamp_units = timestamp_units
|
|
210
235
|
|
|
211
236
|
def start_transform(self, name: str, column_names: List[str]):
|
|
212
|
-
self._time_idx =
|
|
237
|
+
self._time_idx = _FIND_TIME_COL_IDX(column_names)
|
|
213
238
|
self._volume_idx = None
|
|
214
239
|
self._b_volume_idx = None
|
|
215
240
|
try:
|
|
@@ -251,15 +276,10 @@ class AsOhlcvSeries(DataTransformer):
|
|
|
251
276
|
if self.timeframe:
|
|
252
277
|
self._series = OHLCV(self._name, self.timeframe)
|
|
253
278
|
|
|
254
|
-
def _time(self, t) -> int:
|
|
255
|
-
if self.timestamp_units == 'ns':
|
|
256
|
-
return np.datetime64(t, 'ns').item()
|
|
257
|
-
return np.datetime64(t, self.timestamp_units).astype('datetime64[ns]').item()
|
|
258
|
-
|
|
259
279
|
def _proc_ohlc(self, rows_data: List[List]):
|
|
260
280
|
for d in rows_data:
|
|
261
281
|
self._series.update_by_bar(
|
|
262
|
-
|
|
282
|
+
_time(d[self._time_idx], self.timestamp_units),
|
|
263
283
|
d[self._open_idx], d[self._high_idx], d[self._low_idx], d[self._close_idx],
|
|
264
284
|
d[self._volume_idx] if self._volume_idx else 0,
|
|
265
285
|
d[self._b_volume_idx] if self._b_volume_idx else 0
|
|
@@ -268,7 +288,7 @@ class AsOhlcvSeries(DataTransformer):
|
|
|
268
288
|
def _proc_quotes(self, rows_data: List[List]):
|
|
269
289
|
for d in rows_data:
|
|
270
290
|
self._series.update(
|
|
271
|
-
|
|
291
|
+
_time(d[self._time_idx], self.timestamp_units),
|
|
272
292
|
(d[self._ask_idx] + d[self._bid_idx])/2
|
|
273
293
|
)
|
|
274
294
|
|
|
@@ -277,7 +297,7 @@ class AsOhlcvSeries(DataTransformer):
|
|
|
277
297
|
a = d[self._taker_idx] if self._taker_idx else 0
|
|
278
298
|
s = d[self._size_idx]
|
|
279
299
|
b = s if a else 0
|
|
280
|
-
self._series.update(
|
|
300
|
+
self._series.update(_time(d[self._time_idx], self.timestamp_units), d[self._price_idx], s, b)
|
|
281
301
|
|
|
282
302
|
def process_data(self, rows_data: List[List]) -> Any:
|
|
283
303
|
if self._series is None:
|
|
@@ -302,10 +322,14 @@ class AsOhlcvSeries(DataTransformer):
|
|
|
302
322
|
|
|
303
323
|
|
|
304
324
|
class AsQuotes(DataTransformer):
|
|
325
|
+
"""
|
|
326
|
+
Tries to convert incoming data to list of Quote's
|
|
327
|
+
Data must have appropriate structure: bid, ask, bidsize, asksize and time
|
|
328
|
+
"""
|
|
305
329
|
|
|
306
330
|
def start_transform(self, name: str, column_names: List[str]):
|
|
307
331
|
self.buffer = list()
|
|
308
|
-
self._time_idx =
|
|
332
|
+
self._time_idx = _FIND_TIME_COL_IDX(column_names)
|
|
309
333
|
self._bid_idx = _find_column_index_in_list(column_names, 'bid')
|
|
310
334
|
self._ask_idx = _find_column_index_in_list(column_names, 'ask')
|
|
311
335
|
self._bidvol_idx = _find_column_index_in_list(column_names, 'bidvol', 'bid_vol', 'bidsize', 'bid_size')
|
|
@@ -320,6 +344,48 @@ class AsQuotes(DataTransformer):
|
|
|
320
344
|
bv = d[self._bidvol_idx]
|
|
321
345
|
av = d[self._askvol_idx]
|
|
322
346
|
self.buffer.append(Quote(t.as_unit('ns').asm8.item(), b, a, bv, av))
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class AsTimestampedRecords(DataTransformer):
|
|
350
|
+
"""
|
|
351
|
+
Convert incoming data to list or dictionaries with preprocessed timestamps ('timestamp_ns' and 'timestamp')
|
|
352
|
+
```
|
|
353
|
+
[
|
|
354
|
+
{
|
|
355
|
+
'open_time': 1711944240000.0,
|
|
356
|
+
'open': 203.219,
|
|
357
|
+
'high': 203.33,
|
|
358
|
+
'low': 203.134,
|
|
359
|
+
'close': 203.175,
|
|
360
|
+
'volume': 10060.0,
|
|
361
|
+
....
|
|
362
|
+
'timestamp_ns': 1711944240000000000,
|
|
363
|
+
'timestamp': Timestamp('2024-04-01 04:04:00')
|
|
364
|
+
},
|
|
365
|
+
...
|
|
366
|
+
] ```
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
def __init__(self, timestamp_units: str | None=None) -> None:
|
|
370
|
+
self.timestamp_units = timestamp_units
|
|
371
|
+
|
|
372
|
+
def start_transform(self, name: str, column_names: List[str]):
|
|
373
|
+
self.buffer = list()
|
|
374
|
+
self._time_idx = _FIND_TIME_COL_IDX(column_names)
|
|
375
|
+
self._column_names = column_names
|
|
376
|
+
|
|
377
|
+
def process_data(self, rows_data: Iterable) -> Any:
|
|
378
|
+
self.buffer.extend(rows_data)
|
|
379
|
+
|
|
380
|
+
def collect(self) -> Any:
|
|
381
|
+
res = []
|
|
382
|
+
for r in self.buffer:
|
|
383
|
+
t = r[self._time_idx]
|
|
384
|
+
if self.timestamp_units:
|
|
385
|
+
t = _time(t, self.timestamp_units)
|
|
386
|
+
di = dict(zip(self._column_names, r)) | { 'timestamp_ns': t, 'timestamp': pd.Timestamp(t) }
|
|
387
|
+
res.append(di)
|
|
388
|
+
return res
|
|
323
389
|
|
|
324
390
|
|
|
325
391
|
class RestoreTicksFromOHLC(DataTransformer):
|
|
@@ -344,7 +410,7 @@ class RestoreTicksFromOHLC(DataTransformer):
|
|
|
344
410
|
def start_transform(self, name: str, column_names: List[str]):
|
|
345
411
|
self.buffer = []
|
|
346
412
|
# - it will fail if receive data doesn't look as ohlcv
|
|
347
|
-
self._time_idx =
|
|
413
|
+
self._time_idx = _FIND_TIME_COL_IDX(column_names)
|
|
348
414
|
self._open_idx = _find_column_index_in_list(column_names, 'open')
|
|
349
415
|
self._high_idx = _find_column_index_in_list(column_names, 'high')
|
|
350
416
|
self._low_idx = _find_column_index_in_list(column_names, 'low')
|
|
Binary file
|
|
@@ -6,13 +6,13 @@ qubx/core/basics.py,sha256=2u7WV5KX-RbTmzoKfi1yT4HNLDPfQcFMCUZ1pVsM_VE,14777
|
|
|
6
6
|
qubx/core/helpers.py,sha256=gPE78dO718NBY0-JbfqNGCzIvr4BVatFntNIy2RUrEY,11559
|
|
7
7
|
qubx/core/loggers.py,sha256=HpgavBZegoDv9ssihtqX0pitXKULVAPHUpoE_volJw0,11910
|
|
8
8
|
qubx/core/lookups.py,sha256=4aEC7b2AyEXFqHHGDenex3Z1FZGrpDSb8IwzBZrSqIA,13688
|
|
9
|
-
qubx/core/series.cpython-311-x86_64-linux-gnu.so,sha256=
|
|
9
|
+
qubx/core/series.cpython-311-x86_64-linux-gnu.so,sha256=Wpec9yDlhedIs11mCYl8pVf30bghhwL4UHBxgMesiak,698952
|
|
10
10
|
qubx/core/series.pxd,sha256=IS89NQ5FYp3T0YIHe1lELKZIAKrNvX8K6WlLyac44I4,2847
|
|
11
11
|
qubx/core/series.pyx,sha256=WEAjn4j3zn540Cxx68X5gRXilvwa7NGdbki6myzZbIM,28108
|
|
12
12
|
qubx/core/strategy.py,sha256=Fs4fFyHaEGYuz7mBeQHBWFu3Ipg0yFzcxXhskgsPxJE,30330
|
|
13
|
-
qubx/core/utils.cpython-311-x86_64-linux-gnu.so,sha256=
|
|
13
|
+
qubx/core/utils.cpython-311-x86_64-linux-gnu.so,sha256=nLncQM5F9XMpCda8IWifgSYWtoL0MCrQg27fPxK9Z2I,74216
|
|
14
14
|
qubx/core/utils.pyx,sha256=6dQ8R02bl8V3f-W3Wk9-e86D9OvDz-5-4NA_dlF_xwc,1368
|
|
15
|
-
qubx/data/readers.py,sha256=
|
|
15
|
+
qubx/data/readers.py,sha256=wQc3tsLoNcvO9c2YFDxrN8jyXtPMbR3XrA_NBA38zp8,23350
|
|
16
16
|
qubx/impl/ccxt_connector.py,sha256=NqF-tgxfTATnmVqKUonNXCAzECrDU8YrgqM3Nq06fw8,9150
|
|
17
17
|
qubx/impl/ccxt_customizations.py,sha256=kK_4KmOyKvDVgd4MTkVg4CyqdjE-6r41siZIvLj-A-Q,3488
|
|
18
18
|
qubx/impl/ccxt_trading.py,sha256=cmg4P-zd78w-V8j3-IGS2LFxikGhxFPgmCvz3sr065Q,9097
|
|
@@ -23,7 +23,7 @@ qubx/pandaz/__init__.py,sha256=Iw5uzicYGSC3FEKZ-W1O5-7cXq_P0kH11-EcXV0zZhs,175
|
|
|
23
23
|
qubx/pandaz/ta.py,sha256=TUvjrvmk4EQvDcXoRp6Os08-HUap-ZvpSDGawhViOgg,85271
|
|
24
24
|
qubx/pandaz/utils.py,sha256=FyLKQy8spkqxhBij_nPFC_ZzI_L3-IgB9O53MqWKmq0,19109
|
|
25
25
|
qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so,sha256=
|
|
26
|
+
qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so,sha256=HFcrtnfX2BiiqymRwZ5lftBsqrF-TEmZKchPVzhbUbM,284552
|
|
27
27
|
qubx/ta/indicators.pyx,sha256=P-GEYUks2lSHo6hbtUFAB7TWE1AunjLR4jIjwqPHrwU,7708
|
|
28
28
|
qubx/trackers/__init__.py,sha256=1y_yvIy0OQwBqfhAW_EY33NxFzFSWvI0qNAPU6zchYc,60
|
|
29
29
|
qubx/trackers/rebalancers.py,sha256=QCzANCooZBi2VMCBjjCPMq_Dt1h1zrBelATnfmVve74,5522
|
|
@@ -34,6 +34,6 @@ qubx/utils/marketdata/binance.py,sha256=36dl4rxOAGTeY3uoONmiPanj8BkP0oBdDiH-URJJ
|
|
|
34
34
|
qubx/utils/misc.py,sha256=z5rdz5hbRu9-F2QgF47OCkMvhfIkRKs-PHR8L5DWkBM,9831
|
|
35
35
|
qubx/utils/runner.py,sha256=OY7SoRfxHwzn0rKTGB_lbg5zNASEL_49hQXWqs-LiMk,9306
|
|
36
36
|
qubx/utils/time.py,sha256=_DjCdQditzZwMy_8rvPdWyw5tjw__2p24LMPgXdZ8i0,4911
|
|
37
|
-
qubx-0.1.
|
|
38
|
-
qubx-0.1.
|
|
39
|
-
qubx-0.1.
|
|
37
|
+
qubx-0.1.7.dist-info/METADATA,sha256=gjq_-njDfPiu_li6ID5hClbIvZL3NsVARvM6NRNZd9U,2490
|
|
38
|
+
qubx-0.1.7.dist-info/WHEEL,sha256=MLOa6LysROdjgj4FVxsHitAnIh8Be2D_c9ZSBHKrz2M,110
|
|
39
|
+
qubx-0.1.7.dist-info/RECORD,,
|
|
File without changes
|