Qubx 0.1.81__cp311-cp311-manylinux_2_35_x86_64.whl → 0.1.82__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 +84 -54
- qubx/ta/indicators.cpython-311-x86_64-linux-gnu.so +0 -0
- {qubx-0.1.81.dist-info → qubx-0.1.82.dist-info}/METADATA +1 -1
- {qubx-0.1.81.dist-info → qubx-0.1.82.dist-info}/RECORD +7 -7
- {qubx-0.1.81.dist-info → qubx-0.1.82.dist-info}/WHEEL +0 -0
|
Binary file
|
|
Binary file
|
qubx/data/readers.py
CHANGED
|
@@ -503,56 +503,27 @@ def _retry(fn):
|
|
|
503
503
|
return wrapper
|
|
504
504
|
|
|
505
505
|
|
|
506
|
-
class
|
|
506
|
+
class QuestDBSqlBuilder:
|
|
507
507
|
"""
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
### Connect to an existing QuestDB instance
|
|
511
|
-
>>> db = QuestDBConnector()
|
|
512
|
-
>>> db.read('BINANCE.UM:ETHUSDT', '2024-01-01', transform=AsPandasFrame())
|
|
508
|
+
Generic sql builder for QuestDB data
|
|
513
509
|
"""
|
|
514
|
-
_reconnect_tries = 5
|
|
515
|
-
_reconnect_idle = 0.1 # wait seconds before retying
|
|
516
510
|
|
|
517
|
-
def
|
|
518
|
-
|
|
519
|
-
self._cursor = None
|
|
520
|
-
self._host = host
|
|
521
|
-
self._port = port
|
|
522
|
-
self.connection_url = f'user={user} password={password} host={host} port={port}'
|
|
523
|
-
self._connect()
|
|
524
|
-
|
|
525
|
-
def _connect(self):
|
|
526
|
-
self._connection = pg.connect(self.connection_url, autocommit=True)
|
|
527
|
-
self._cursor = self._connection.cursor()
|
|
528
|
-
logger.debug(f"Connected to QuestDB at {self._host}:{self._port}")
|
|
529
|
-
|
|
530
|
-
@_retry
|
|
531
|
-
def read(self, data_id: str, start: str|None=None, stop: str|None=None,
|
|
532
|
-
transform: DataTransformer = DataTransformer(),
|
|
533
|
-
chunksize=0, # TODO: use self._cursor.fetchmany in this case !!!!
|
|
534
|
-
timeframe: str='1m', suffix='candles_1m') -> Any:
|
|
535
|
-
start, end = handle_start_stop(start, stop)
|
|
536
|
-
_req = self._prepare_data_sql(data_id, start, end, timeframe, suffix)
|
|
511
|
+
def get_table_name(self, data_id: str, sfx: str='') -> str | None:
|
|
512
|
+
pass
|
|
537
513
|
|
|
538
|
-
|
|
539
|
-
|
|
514
|
+
def prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str, suffix: str) -> str | None:
|
|
515
|
+
pass
|
|
540
516
|
|
|
541
|
-
|
|
542
|
-
|
|
517
|
+
def prepare_names_sql(self) -> str:
|
|
518
|
+
return "select table_name from tables()"
|
|
543
519
|
|
|
544
|
-
transform.process_data(records)
|
|
545
|
-
return transform.collect()
|
|
546
520
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
if _t and len(_t.groups()) > 1:
|
|
552
|
-
c_tf = f"{_t[1]}{_t[2][0].lower()}"
|
|
553
|
-
return c_tf
|
|
521
|
+
class QuestDBSqlCandlesBuilder(QuestDBSqlBuilder):
|
|
522
|
+
"""
|
|
523
|
+
Sql builder for candles data
|
|
524
|
+
"""
|
|
554
525
|
|
|
555
|
-
def
|
|
526
|
+
def get_table_name(self, data_id: str, sfx: str='') -> str:
|
|
556
527
|
"""
|
|
557
528
|
Get table name for data_id
|
|
558
529
|
data_id can have format <exchange>.<type>:<symbol>
|
|
@@ -573,7 +544,15 @@ class QuestDBConnector(DataReader):
|
|
|
573
544
|
table_name = '.'.join(filter(lambda x: x, [_exch.lower(), _aliases.get(_mktype, _mktype), symb.lower(), sfx]))
|
|
574
545
|
return table_name
|
|
575
546
|
|
|
576
|
-
|
|
547
|
+
@staticmethod
|
|
548
|
+
def _convert_time_delta_to_qdb_resample_format(c_tf: str):
|
|
549
|
+
if c_tf:
|
|
550
|
+
_t = re.match(r'(\d+)(\w+)', c_tf)
|
|
551
|
+
if _t and len(_t.groups()) > 1:
|
|
552
|
+
c_tf = f"{_t[1]}{_t[2][0].lower()}"
|
|
553
|
+
return c_tf
|
|
554
|
+
|
|
555
|
+
def prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str, suffix: str) -> str:
|
|
577
556
|
where = ''
|
|
578
557
|
w0 = f"timestamp >= '{start}'" if start else ''
|
|
579
558
|
w1 = f"timestamp <= '{end}'" if end else ''
|
|
@@ -583,10 +562,10 @@ class QuestDBConnector(DataReader):
|
|
|
583
562
|
where = f'where {w0} and {w1}' if (w0 and w1) else f"where {(w0 or w1)}"
|
|
584
563
|
|
|
585
564
|
# - check resample format
|
|
586
|
-
resample =
|
|
565
|
+
resample = QuestDBSqlCandlesBuilder._convert_time_delta_to_qdb_resample_format(resample) if resample else resample
|
|
587
566
|
_rsmpl = f"SAMPLE by {resample}" if resample else ''
|
|
588
567
|
|
|
589
|
-
table_name = self.
|
|
568
|
+
table_name = self.get_table_name(data_id, suffix)
|
|
590
569
|
return f"""
|
|
591
570
|
select timestamp,
|
|
592
571
|
first(open) as open,
|
|
@@ -601,12 +580,54 @@ class QuestDBConnector(DataReader):
|
|
|
601
580
|
from "{table_name}" {where} {_rsmpl};
|
|
602
581
|
"""
|
|
603
582
|
|
|
604
|
-
|
|
605
|
-
|
|
583
|
+
|
|
584
|
+
class QuestDBConnector(DataReader):
|
|
585
|
+
"""
|
|
586
|
+
Very first version of QuestDB connector
|
|
587
|
+
|
|
588
|
+
### Connect to an existing QuestDB instance
|
|
589
|
+
>>> db = QuestDBConnector()
|
|
590
|
+
>>> db.read('BINANCE.UM:ETHUSDT', '2024-01-01', transform=AsPandasFrame())
|
|
591
|
+
"""
|
|
592
|
+
_reconnect_tries = 5
|
|
593
|
+
_reconnect_idle = 0.1 # wait seconds before retying
|
|
594
|
+
_builder: QuestDBSqlBuilder
|
|
595
|
+
|
|
596
|
+
def __init__(self, builder: QuestDBSqlBuilder = QuestDBSqlCandlesBuilder(),
|
|
597
|
+
host='localhost', user='admin', password='quest', port=8812) -> None:
|
|
598
|
+
self._connection = None
|
|
599
|
+
self._cursor = None
|
|
600
|
+
self._host = host
|
|
601
|
+
self._port = port
|
|
602
|
+
self.connection_url = f'user={user} password={password} host={host} port={port}'
|
|
603
|
+
self._builder = builder
|
|
604
|
+
self._connect()
|
|
605
|
+
|
|
606
|
+
def _connect(self):
|
|
607
|
+
self._connection = pg.connect(self.connection_url, autocommit=True)
|
|
608
|
+
self._cursor = self._connection.cursor()
|
|
609
|
+
logger.debug(f"Connected to QuestDB at {self._host}:{self._port}")
|
|
610
|
+
|
|
611
|
+
@_retry
|
|
612
|
+
def read(self, data_id: str, start: str|None=None, stop: str|None=None,
|
|
613
|
+
transform: DataTransformer = DataTransformer(),
|
|
614
|
+
chunksize=0, # TODO: use self._cursor.fetchmany in this case !!!!
|
|
615
|
+
timeframe: str='1m', suffix='candles_1m') -> Any:
|
|
616
|
+
start, end = handle_start_stop(start, stop)
|
|
617
|
+
_req = self._builder.prepare_data_sql(data_id, start, end, timeframe, suffix)
|
|
618
|
+
|
|
619
|
+
self._cursor.execute(_req) # type: ignore
|
|
620
|
+
records = self._cursor.fetchall() # TODO: for chunksize > 0 use fetchmany etc
|
|
621
|
+
|
|
622
|
+
names = [d.name for d in self._cursor.description] # type: ignore
|
|
623
|
+
transform.start_transform(data_id, names)
|
|
624
|
+
|
|
625
|
+
transform.process_data(records)
|
|
626
|
+
return transform.collect()
|
|
606
627
|
|
|
607
628
|
@_retry
|
|
608
629
|
def get_names(self) -> List[str] :
|
|
609
|
-
self._cursor.execute(self.
|
|
630
|
+
self._cursor.execute(self._builder.prepare_names_sql()) # type: ignore
|
|
610
631
|
records = self._cursor.fetchall()
|
|
611
632
|
return [r[0] for r in records]
|
|
612
633
|
|
|
@@ -652,14 +673,23 @@ class SnapshotsBuilder(DataTransformer):
|
|
|
652
673
|
return self.buffer
|
|
653
674
|
|
|
654
675
|
|
|
676
|
+
class QuestDBSqlOrderBookBilder(QuestDBSqlBuilder):
|
|
677
|
+
"""
|
|
678
|
+
Sql builder for snapshot data
|
|
679
|
+
"""
|
|
680
|
+
|
|
681
|
+
def get_table_name(self, data_id: str, sfx: str='') -> str:
|
|
682
|
+
return ''
|
|
683
|
+
|
|
684
|
+
def prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str, suffix: str) -> str:
|
|
685
|
+
return ''
|
|
686
|
+
|
|
687
|
+
|
|
655
688
|
class QuestDBOrderBookConnector(QuestDBConnector):
|
|
656
689
|
"""
|
|
657
690
|
Example of custom OrderBook data connector
|
|
658
691
|
"""
|
|
659
692
|
|
|
660
|
-
def
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
def _prepare_names_sql(self) -> str:
|
|
664
|
-
# return "select table_name from tables() where ..."
|
|
665
|
-
raise NotImplemented("TODO")
|
|
693
|
+
def __init__(self, host='localhost', user='admin', password='quest', port=8812) -> None:
|
|
694
|
+
super().__init__(QuestDBSqlOrderBookBilder(), host, user, password, port)
|
|
695
|
+
|
|
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=FKD447WQCDiib-wBliVN0amtMroO_iEvVnRsg22n73U,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=dFR1VwEHg4biWv-vrn9nf-JPKMs3L4-lf_4EXMQFb8I,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=HDUoXNjpObtbfxrMW3PB4ypyB7WvJUvCg2Ulww4NChs,25600
|
|
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=v9kiNK0VWcOhllotwWfPPZ3De2CLpWlvDbVSUxqeuHQ,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.82.dist-info/METADATA,sha256=MXKLJx9nRdbg1BE5emc8ovNDC7HoB78N0BYhWKR5Wfk,2491
|
|
38
|
+
qubx-0.1.82.dist-info/WHEEL,sha256=MLOa6LysROdjgj4FVxsHitAnIh8Be2D_c9ZSBHKrz2M,110
|
|
39
|
+
qubx-0.1.82.dist-info/RECORD,,
|
|
File without changes
|