Qubx 0.1.5__tar.gz → 0.1.6__tar.gz

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.

Files changed (37) hide show
  1. {qubx-0.1.5 → qubx-0.1.6}/PKG-INFO +9 -1
  2. {qubx-0.1.5 → qubx-0.1.6}/pyproject.toml +10 -1
  3. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/data/readers.py +66 -16
  4. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/_pyxreloader.py +8 -4
  5. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/time.py +2 -2
  6. {qubx-0.1.5 → qubx-0.1.6}/README.md +0 -0
  7. {qubx-0.1.5 → qubx-0.1.6}/build.py +0 -0
  8. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/__init__.py +0 -0
  9. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/_nb_magic.py +0 -0
  10. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/__init__.py +0 -0
  11. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/account.py +0 -0
  12. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/basics.py +0 -0
  13. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/helpers.py +0 -0
  14. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/loggers.py +0 -0
  15. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/lookups.py +0 -0
  16. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/series.pxd +0 -0
  17. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/series.pyx +0 -0
  18. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/strategy.py +0 -0
  19. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/core/utils.pyx +0 -0
  20. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/impl/ccxt_connector.py +0 -0
  21. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/impl/ccxt_customizations.py +0 -0
  22. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/impl/ccxt_trading.py +0 -0
  23. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/impl/ccxt_utils.py +0 -0
  24. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/math/__init__.py +0 -0
  25. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/math/stats.py +0 -0
  26. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/pandaz/__init__.py +0 -0
  27. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/pandaz/ta.py +0 -0
  28. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/pandaz/utils.py +0 -0
  29. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/ta/__init__.py +0 -0
  30. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/ta/indicators.pyx +0 -0
  31. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/trackers/__init__.py +0 -0
  32. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/trackers/rebalancers.py +0 -0
  33. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/__init__.py +0 -0
  34. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  35. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/marketdata/binance.py +0 -0
  36. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/misc.py +0 -0
  37. {qubx-0.1.5 → qubx-0.1.6}/src/qubx/utils/runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Qubx
3
- Version: 0.1.5
3
+ Version: 0.1.6
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "Qubx"
3
- version = "0.1.5"
3
+ version = "0.1.6"
4
4
  description = "Qubx - quantitative trading framework"
5
5
  authors = ["Dmitry Marienko <dmitry@gmail.com>"]
6
6
  readme = "README.md"
@@ -33,6 +33,15 @@ cython = "3.0.8"
33
33
  ccxt = "^4.2.68"
34
34
  croniter = "^2.0.5"
35
35
  psycopg = "^3.1.18"
36
+ pandas = "^2.2.2"
37
+ statsmodels = "^0.14.2"
38
+ matplotlib = "^3.8.4"
39
+ numba = "^0.59.1"
40
+ scikit-learn = "^1.4.2"
41
+ plotly = "^5.22.0"
42
+ psycopg-binary = "^3.1.19"
43
+ psycopg-pool = "^3.2.2"
44
+
36
45
 
37
46
  [tool.poetry.group.dev.dependencies]
38
47
  pre-commit = "^2.20.0"
@@ -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")
@@ -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:
@@ -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) -> tuple:
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
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes