Qubx 0.1.5__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 +146 -30
- qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so +0 -0
- qubx/utils/_pyxreloader.py +8 -4
- qubx/utils/time.py +2 -2
- {qubx-0.1.5.dist-info → qubx-0.1.7.dist-info}/METADATA +9 -1
- {qubx-0.1.5.dist-info → qubx-0.1.7.dist-info}/RECORD +9 -9
- {qubx-0.1.5.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')
|
|
@@ -465,15 +531,26 @@ class QuestDBConnector(DataReader):
|
|
|
465
531
|
chunksize=0, # TODO: use self._cursor.fetchmany in this case !!!!
|
|
466
532
|
timeframe: str='1m') -> Any:
|
|
467
533
|
start, end = handle_start_stop(start, stop)
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
534
|
+
_req = self._prepare_data_sql(data_id, start, end, timeframe)
|
|
535
|
+
|
|
536
|
+
self._cursor.execute(_req) # type: ignore
|
|
537
|
+
records = self._cursor.fetchall() # TODO: for chunksize > 0 use fetchmany etc
|
|
538
|
+
|
|
539
|
+
names = [d.name for d in self._cursor.description] # type: ignore
|
|
540
|
+
transform.start_transform(data_id, names)
|
|
541
|
+
|
|
542
|
+
transform.process_data(records)
|
|
543
|
+
return transform.collect()
|
|
471
544
|
|
|
545
|
+
def _prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str) -> str:
|
|
472
546
|
# just a temp hack - actually we need to discuss symbology etc
|
|
473
547
|
symbol = data_id#.split('.')[-1]
|
|
474
548
|
|
|
475
|
-
|
|
476
|
-
|
|
549
|
+
w0 = f"timestamp >= '{start}'" if start else ''
|
|
550
|
+
w1 = f"timestamp <= '{end}'" if end else ''
|
|
551
|
+
where = f'where {w0} and {w1}' if (w0 and w1) else f"where {(w0 or w1)}"
|
|
552
|
+
|
|
553
|
+
return f"""
|
|
477
554
|
select timestamp,
|
|
478
555
|
first(open) as open,
|
|
479
556
|
max(high) as high,
|
|
@@ -485,21 +562,15 @@ class QuestDBConnector(DataReader):
|
|
|
485
562
|
sum(taker_buy_volume) as taker_buy_volume,
|
|
486
563
|
sum(taker_buy_quote_volume) as taker_buy_quote_volume
|
|
487
564
|
from "{symbol.upper()}" {where}
|
|
488
|
-
SAMPLE by {
|
|
489
|
-
"""
|
|
490
|
-
)
|
|
491
|
-
records = self._cursor.fetchall() # TODO: for chunksize > 0 use fetchmany etc
|
|
492
|
-
names = [d.name for d in self._cursor.description]
|
|
565
|
+
SAMPLE by {resample};
|
|
566
|
+
"""
|
|
493
567
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
# d = np.array(records)
|
|
497
|
-
transform.process_data(records)
|
|
498
|
-
return transform.collect()
|
|
568
|
+
def _prepare_names_sql(self) -> str:
|
|
569
|
+
return "select table_name from tables()"
|
|
499
570
|
|
|
500
571
|
@_retry
|
|
501
572
|
def get_names(self) -> List[str] :
|
|
502
|
-
self._cursor.execute(
|
|
573
|
+
self._cursor.execute(self._prepare_names_sql()) # type: ignore
|
|
503
574
|
records = self._cursor.fetchall()
|
|
504
575
|
return [r[0] for r in records]
|
|
505
576
|
|
|
@@ -511,3 +582,48 @@ class QuestDBConnector(DataReader):
|
|
|
511
582
|
except:
|
|
512
583
|
pass
|
|
513
584
|
|
|
585
|
+
|
|
586
|
+
class SnapshotsBuilder(DataTransformer):
|
|
587
|
+
"""
|
|
588
|
+
Snapshots assembler from OB updates
|
|
589
|
+
"""
|
|
590
|
+
def __init__(self,
|
|
591
|
+
levels: int=-1, # how many levels restore, 1 - TOB, -1 - all
|
|
592
|
+
as_frame=False # result is dataframe
|
|
593
|
+
):
|
|
594
|
+
self.buffer = []
|
|
595
|
+
self.levels = levels
|
|
596
|
+
self.as_frame = as_frame
|
|
597
|
+
|
|
598
|
+
def start_transform(self, name: str, column_names: List[str]):
|
|
599
|
+
# initialize buffer / series etc
|
|
600
|
+
# let's keep restored snapshots into some buffer etc
|
|
601
|
+
self.buffer = []
|
|
602
|
+
|
|
603
|
+
# do additional init stuff here
|
|
604
|
+
|
|
605
|
+
def process_data(self, rows_data:List[List]) -> Any:
|
|
606
|
+
for r in rows_data:
|
|
607
|
+
# restore snapshots and put into buffer or series
|
|
608
|
+
pass
|
|
609
|
+
|
|
610
|
+
def collect(self) -> Any:
|
|
611
|
+
# - may be convert it to pandas DataFrame ?
|
|
612
|
+
if self.as_frame:
|
|
613
|
+
return pd.DataFrame.from_records(self.buffer) # or custom transform
|
|
614
|
+
|
|
615
|
+
# - or just returns as plain list
|
|
616
|
+
return self.buffer
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
class QuestDBOrderBookConnector(QuestDBConnector):
|
|
620
|
+
"""
|
|
621
|
+
Example of custom OrderBook data connector
|
|
622
|
+
"""
|
|
623
|
+
|
|
624
|
+
def _prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str|None) -> str:
|
|
625
|
+
raise NotImplemented("TODO")
|
|
626
|
+
|
|
627
|
+
def _prepare_names_sql(self) -> str:
|
|
628
|
+
# return "select table_name from tables() where ..."
|
|
629
|
+
raise NotImplemented("TODO")
|
|
Binary file
|
qubx/utils/_pyxreloader.py
CHANGED
|
@@ -5,10 +5,6 @@ from importlib.util import spec_from_file_location
|
|
|
5
5
|
from importlib.machinery import ExtensionFileLoader, SourceFileLoader
|
|
6
6
|
from typing import List
|
|
7
7
|
|
|
8
|
-
# - disable warn about deprecation of imp module: after dev stage _pyxreloader will be removed
|
|
9
|
-
import warnings
|
|
10
|
-
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
|
11
|
-
import imp
|
|
12
8
|
|
|
13
9
|
PYX_EXT = ".pyx"
|
|
14
10
|
PYXDEP_EXT = ".pyxdep"
|
|
@@ -49,6 +45,10 @@ def handle_dependencies(pyxfilename):
|
|
|
49
45
|
|
|
50
46
|
|
|
51
47
|
def handle_special_build(modname, pyxfilename):
|
|
48
|
+
try:
|
|
49
|
+
import imp
|
|
50
|
+
except:
|
|
51
|
+
return None, None
|
|
52
52
|
special_build = os.path.splitext(pyxfilename)[0] + PYXBLD_EXT
|
|
53
53
|
ext = None
|
|
54
54
|
setup_args={}
|
|
@@ -135,6 +135,10 @@ def build_module(name, pyxfilename, user_setup_args, pyxbuild_dir=None, inplace=
|
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
def load_module(name, pyxfilename, pyxbuild_dir=None, is_package=False, build_inplace=False, language_level=None, so_path=None):
|
|
138
|
+
try:
|
|
139
|
+
import imp
|
|
140
|
+
except:
|
|
141
|
+
return None
|
|
138
142
|
try:
|
|
139
143
|
if so_path is None:
|
|
140
144
|
if is_package:
|
qubx/utils/time.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from typing import List, Optional, Union
|
|
2
|
+
from typing import List, Optional, Tuple, Union
|
|
3
3
|
import numpy as np
|
|
4
4
|
import re
|
|
5
5
|
|
|
@@ -115,7 +115,7 @@ def infer_series_frequency(series: Union[List, pd.DataFrame, pd.Series, pd.Datet
|
|
|
115
115
|
return np.timedelta64(max(freqs, key=freqs.get))
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
def handle_start_stop(s: Optional[str], e: Optional[str], convert=str) ->
|
|
118
|
+
def handle_start_stop(s: Optional[str], e: Optional[str], convert=str) -> Tuple[str|None, str|None]:
|
|
119
119
|
"""
|
|
120
120
|
Process start/stop times
|
|
121
121
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: Qubx
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Qubx - quantitative trading framework
|
|
5
5
|
Home-page: https://github.com/dmarienko/Qubx
|
|
6
6
|
Author: Dmitry Marienko
|
|
@@ -15,17 +15,25 @@ Requires-Dist: croniter (>=2.0.5,<3.0.0)
|
|
|
15
15
|
Requires-Dist: cython (==3.0.8)
|
|
16
16
|
Requires-Dist: importlib-metadata
|
|
17
17
|
Requires-Dist: loguru (>=0.7.2,<0.8.0)
|
|
18
|
+
Requires-Dist: matplotlib (>=3.8.4,<4.0.0)
|
|
18
19
|
Requires-Dist: ntplib (>=0.4.0,<0.5.0)
|
|
20
|
+
Requires-Dist: numba (>=0.59.1,<0.60.0)
|
|
19
21
|
Requires-Dist: numpy (>=1.26.3,<2.0.0)
|
|
22
|
+
Requires-Dist: pandas (>=2.2.2,<3.0.0)
|
|
23
|
+
Requires-Dist: plotly (>=5.22.0,<6.0.0)
|
|
20
24
|
Requires-Dist: psycopg (>=3.1.18,<4.0.0)
|
|
25
|
+
Requires-Dist: psycopg-binary (>=3.1.19,<4.0.0)
|
|
26
|
+
Requires-Dist: psycopg-pool (>=3.2.2,<4.0.0)
|
|
21
27
|
Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
|
|
22
28
|
Requires-Dist: pydantic (>=1.10.2,<2.0.0)
|
|
23
29
|
Requires-Dist: pymongo (>=4.6.1,<5.0.0)
|
|
24
30
|
Requires-Dist: pytest[lazyfixture] (>=7.2.0,<8.0.0)
|
|
25
31
|
Requires-Dist: python-binance (>=1.0.19,<2.0.0)
|
|
26
32
|
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
33
|
+
Requires-Dist: scikit-learn (>=1.4.2,<2.0.0)
|
|
27
34
|
Requires-Dist: scipy (>=1.12.0,<2.0.0)
|
|
28
35
|
Requires-Dist: stackprinter (>=0.2.10,<0.3.0)
|
|
36
|
+
Requires-Dist: statsmodels (>=0.14.2,<0.15.0)
|
|
29
37
|
Requires-Dist: tqdm
|
|
30
38
|
Project-URL: Repository, https://github.com/dmarienko/Qubx
|
|
31
39
|
Description-Content-Type: text/markdown
|
|
@@ -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,17 +23,17 @@ 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
|
|
30
30
|
qubx/utils/__init__.py,sha256=XJFje4jP69pnPTp7fpTUmqwXz9PKzGYtJf8-kBofum0,273
|
|
31
|
-
qubx/utils/_pyxreloader.py,sha256=
|
|
31
|
+
qubx/utils/_pyxreloader.py,sha256=FyqGzfSpZGYziB8JYS5AP3cLRAvJSIPAKgwQn0E4YQ0,12017
|
|
32
32
|
qubx/utils/charting/mpl_helpers.py,sha256=ZaBrF0yOBOoVEk4TCBFi9KPyL3O5GPoteDglIzL8uSs,35158
|
|
33
33
|
qubx/utils/marketdata/binance.py,sha256=36dl4rxOAGTeY3uoONmiPanj8BkP0oBdDiH-URJJo9A,10993
|
|
34
34
|
qubx/utils/misc.py,sha256=z5rdz5hbRu9-F2QgF47OCkMvhfIkRKs-PHR8L5DWkBM,9831
|
|
35
35
|
qubx/utils/runner.py,sha256=OY7SoRfxHwzn0rKTGB_lbg5zNASEL_49hQXWqs-LiMk,9306
|
|
36
|
-
qubx/utils/time.py,sha256=
|
|
37
|
-
qubx-0.1.
|
|
38
|
-
qubx-0.1.
|
|
39
|
-
qubx-0.1.
|
|
36
|
+
qubx/utils/time.py,sha256=_DjCdQditzZwMy_8rvPdWyw5tjw__2p24LMPgXdZ8i0,4911
|
|
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
|