Qubx 0.1.4__cp311-cp311-manylinux_2_35_x86_64.whl → 0.1.6__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/_nb_magic.py CHANGED
@@ -32,13 +32,17 @@ if runtime_env() in ['notebook', 'shell']:
32
32
  from tqdm.auto import tqdm
33
33
 
34
34
  # - - - - TA stuff and indicators - - - -
35
+ import qubx.pandaz.ta as pta
36
+
35
37
  # - - - - Portfolio analysis - - - -
36
38
  # - - - - Simulator stuff - - - -
37
39
  # - - - - Learn stuff - - - -
38
40
  # - - - - Charting stuff - - - -
39
41
  from matplotlib import pyplot as plt
40
42
  from qubx.utils.charting.mpl_helpers import fig, subplot, sbp
43
+
41
44
  # - - - - Utils - - - -
45
+ from qubx.pandaz.utils import scols, srows, ohlc_resample, continuous_periods, generate_equal_date_ranges
42
46
 
43
47
  # - setup short numpy output format
44
48
  np_fmt_short()
qubx/data/readers.py CHANGED
@@ -465,15 +465,26 @@ class QuestDBConnector(DataReader):
465
465
  chunksize=0, # TODO: use self._cursor.fetchmany in this case !!!!
466
466
  timeframe: str='1m') -> Any:
467
467
  start, end = handle_start_stop(start, stop)
468
- w0 = f"timestamp >= '{start}'" if start else ''
469
- w1 = f"timestamp <= '{end}'" if end else ''
470
- where = f'where {w0} and {w1}' if (w0 and w1) else f"where {(w0 or w1)}"
468
+ _req = self._prepare_data_sql(data_id, start, end, timeframe)
471
469
 
470
+ self._cursor.execute(_req) # type: ignore
471
+ records = self._cursor.fetchall() # TODO: for chunksize > 0 use fetchmany etc
472
+
473
+ names = [d.name for d in self._cursor.description] # type: ignore
474
+ transform.start_transform(data_id, names)
475
+
476
+ transform.process_data(records)
477
+ return transform.collect()
478
+
479
+ def _prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str) -> str:
472
480
  # just a temp hack - actually we need to discuss symbology etc
473
481
  symbol = data_id#.split('.')[-1]
474
482
 
475
- self._cursor.execute(
476
- f"""
483
+ w0 = f"timestamp >= '{start}'" if start else ''
484
+ w1 = f"timestamp <= '{end}'" if end else ''
485
+ where = f'where {w0} and {w1}' if (w0 and w1) else f"where {(w0 or w1)}"
486
+
487
+ return f"""
477
488
  select timestamp,
478
489
  first(open) as open,
479
490
  max(high) as high,
@@ -485,21 +496,15 @@ class QuestDBConnector(DataReader):
485
496
  sum(taker_buy_volume) as taker_buy_volume,
486
497
  sum(taker_buy_quote_volume) as taker_buy_quote_volume
487
498
  from "{symbol.upper()}" {where}
488
- SAMPLE by {timeframe};
489
- """ # type: ignore
490
- )
491
- records = self._cursor.fetchall() # TODO: for chunksize > 0 use fetchmany etc
492
- names = [d.name for d in self._cursor.description]
499
+ SAMPLE by {resample};
500
+ """
493
501
 
494
- transform.start_transform(data_id, names)
495
-
496
- # d = np.array(records)
497
- transform.process_data(records)
498
- return transform.collect()
502
+ def _prepare_names_sql(self) -> str:
503
+ return "select table_name from tables()"
499
504
 
500
505
  @_retry
501
506
  def get_names(self) -> List[str] :
502
- self._cursor.execute("select table_name from tables()")
507
+ self._cursor.execute(self._prepare_names_sql()) # type: ignore
503
508
  records = self._cursor.fetchall()
504
509
  return [r[0] for r in records]
505
510
 
@@ -511,3 +516,48 @@ class QuestDBConnector(DataReader):
511
516
  except:
512
517
  pass
513
518
 
519
+
520
+ class SnapshotsBuilder(DataTransformer):
521
+ """
522
+ Snapshots assembler from OB updates
523
+ """
524
+ def __init__(self,
525
+ levels: int=-1, # how many levels restore, 1 - TOB, -1 - all
526
+ as_frame=False # result is dataframe
527
+ ):
528
+ self.buffer = []
529
+ self.levels = levels
530
+ self.as_frame = as_frame
531
+
532
+ def start_transform(self, name: str, column_names: List[str]):
533
+ # initialize buffer / series etc
534
+ # let's keep restored snapshots into some buffer etc
535
+ self.buffer = []
536
+
537
+ # do additional init stuff here
538
+
539
+ def process_data(self, rows_data:List[List]) -> Any:
540
+ for r in rows_data:
541
+ # restore snapshots and put into buffer or series
542
+ pass
543
+
544
+ def collect(self) -> Any:
545
+ # - may be convert it to pandas DataFrame ?
546
+ if self.as_frame:
547
+ return pd.DataFrame.from_records(self.buffer) # or custom transform
548
+
549
+ # - or just returns as plain list
550
+ return self.buffer
551
+
552
+
553
+ class QuestDBOrderBookConnector(QuestDBConnector):
554
+ """
555
+ Example of custom OrderBook data connector
556
+ """
557
+
558
+ def _prepare_data_sql(self, data_id: str, start: str|None, end: str|None, resample: str|None) -> str:
559
+ raise NotImplemented("TODO")
560
+
561
+ def _prepare_names_sql(self) -> str:
562
+ # return "select table_name from tables() where ..."
563
+ raise NotImplemented("TODO")
@@ -0,0 +1,4 @@
1
+ from .utils import (
2
+ srows, scols, continuous_periods, ohlc_resample, retain_columns_and_join, dict_to_frame,
3
+ generate_equal_date_ranges, rolling_forward_test_split
4
+ )