Qubx 0.5.7__cp312-cp312-manylinux_2_39_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.

Files changed (100) hide show
  1. qubx/__init__.py +207 -0
  2. qubx/_nb_magic.py +100 -0
  3. qubx/backtester/__init__.py +5 -0
  4. qubx/backtester/account.py +145 -0
  5. qubx/backtester/broker.py +87 -0
  6. qubx/backtester/data.py +296 -0
  7. qubx/backtester/management.py +378 -0
  8. qubx/backtester/ome.py +296 -0
  9. qubx/backtester/optimization.py +201 -0
  10. qubx/backtester/simulated_data.py +558 -0
  11. qubx/backtester/simulator.py +362 -0
  12. qubx/backtester/utils.py +780 -0
  13. qubx/cli/__init__.py +0 -0
  14. qubx/cli/commands.py +67 -0
  15. qubx/connectors/ccxt/__init__.py +0 -0
  16. qubx/connectors/ccxt/account.py +495 -0
  17. qubx/connectors/ccxt/broker.py +132 -0
  18. qubx/connectors/ccxt/customizations.py +193 -0
  19. qubx/connectors/ccxt/data.py +612 -0
  20. qubx/connectors/ccxt/exceptions.py +17 -0
  21. qubx/connectors/ccxt/factory.py +93 -0
  22. qubx/connectors/ccxt/utils.py +307 -0
  23. qubx/core/__init__.py +0 -0
  24. qubx/core/account.py +251 -0
  25. qubx/core/basics.py +850 -0
  26. qubx/core/context.py +420 -0
  27. qubx/core/exceptions.py +38 -0
  28. qubx/core/helpers.py +480 -0
  29. qubx/core/interfaces.py +1150 -0
  30. qubx/core/loggers.py +514 -0
  31. qubx/core/lookups.py +475 -0
  32. qubx/core/metrics.py +1512 -0
  33. qubx/core/mixins/__init__.py +13 -0
  34. qubx/core/mixins/market.py +94 -0
  35. qubx/core/mixins/processing.py +428 -0
  36. qubx/core/mixins/subscription.py +203 -0
  37. qubx/core/mixins/trading.py +88 -0
  38. qubx/core/mixins/universe.py +270 -0
  39. qubx/core/series.cpython-312-x86_64-linux-gnu.so +0 -0
  40. qubx/core/series.pxd +125 -0
  41. qubx/core/series.pyi +118 -0
  42. qubx/core/series.pyx +988 -0
  43. qubx/core/utils.cpython-312-x86_64-linux-gnu.so +0 -0
  44. qubx/core/utils.pyi +6 -0
  45. qubx/core/utils.pyx +62 -0
  46. qubx/data/__init__.py +25 -0
  47. qubx/data/helpers.py +416 -0
  48. qubx/data/readers.py +1562 -0
  49. qubx/data/tardis.py +100 -0
  50. qubx/gathering/simplest.py +88 -0
  51. qubx/math/__init__.py +3 -0
  52. qubx/math/stats.py +129 -0
  53. qubx/pandaz/__init__.py +23 -0
  54. qubx/pandaz/ta.py +2757 -0
  55. qubx/pandaz/utils.py +638 -0
  56. qubx/resources/instruments/symbols-binance.cm.json +1 -0
  57. qubx/resources/instruments/symbols-binance.json +1 -0
  58. qubx/resources/instruments/symbols-binance.um.json +1 -0
  59. qubx/resources/instruments/symbols-bitfinex.f.json +1 -0
  60. qubx/resources/instruments/symbols-bitfinex.json +1 -0
  61. qubx/resources/instruments/symbols-kraken.f.json +1 -0
  62. qubx/resources/instruments/symbols-kraken.json +1 -0
  63. qubx/ta/__init__.py +0 -0
  64. qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so +0 -0
  65. qubx/ta/indicators.pxd +149 -0
  66. qubx/ta/indicators.pyi +41 -0
  67. qubx/ta/indicators.pyx +787 -0
  68. qubx/trackers/__init__.py +3 -0
  69. qubx/trackers/abvanced.py +236 -0
  70. qubx/trackers/composite.py +146 -0
  71. qubx/trackers/rebalancers.py +129 -0
  72. qubx/trackers/riskctrl.py +641 -0
  73. qubx/trackers/sizers.py +235 -0
  74. qubx/utils/__init__.py +5 -0
  75. qubx/utils/_pyxreloader.py +281 -0
  76. qubx/utils/charting/lookinglass.py +1057 -0
  77. qubx/utils/charting/mpl_helpers.py +1183 -0
  78. qubx/utils/marketdata/binance.py +284 -0
  79. qubx/utils/marketdata/ccxt.py +90 -0
  80. qubx/utils/marketdata/dukas.py +130 -0
  81. qubx/utils/misc.py +541 -0
  82. qubx/utils/ntp.py +63 -0
  83. qubx/utils/numbers_utils.py +7 -0
  84. qubx/utils/orderbook.py +491 -0
  85. qubx/utils/plotting/__init__.py +0 -0
  86. qubx/utils/plotting/dashboard.py +150 -0
  87. qubx/utils/plotting/data.py +137 -0
  88. qubx/utils/plotting/interfaces.py +25 -0
  89. qubx/utils/plotting/renderers/__init__.py +0 -0
  90. qubx/utils/plotting/renderers/plotly.py +0 -0
  91. qubx/utils/runner/__init__.py +1 -0
  92. qubx/utils/runner/_jupyter_runner.pyt +60 -0
  93. qubx/utils/runner/accounts.py +88 -0
  94. qubx/utils/runner/configs.py +65 -0
  95. qubx/utils/runner/runner.py +470 -0
  96. qubx/utils/time.py +312 -0
  97. qubx-0.5.7.dist-info/METADATA +105 -0
  98. qubx-0.5.7.dist-info/RECORD +100 -0
  99. qubx-0.5.7.dist-info/WHEEL +4 -0
  100. qubx-0.5.7.dist-info/entry_points.txt +3 -0
qubx/utils/time.py ADDED
@@ -0,0 +1,312 @@
1
+ import re
2
+ from datetime import datetime
3
+ from typing import Callable
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ UNIX_T0 = np.datetime64("1970-01-01T00:00:00")
9
+
10
+
11
+ time_to_str = lambda t, u="us": np.datetime_as_string( # noqa: E731
12
+ t if isinstance(t, np.datetime64) else np.datetime64(t, u), unit=u
13
+ )
14
+
15
+
16
+ def convert_tf_str_td64(c_tf: str) -> np.timedelta64:
17
+ """
18
+ Convert string timeframe to timedelta64
19
+
20
+ '15Min' -> timedelta64(15, 'm') etc
21
+ """
22
+ _t = re.findall(r"(\d+)([A-Za-z]+)", c_tf)
23
+ _dt = 0
24
+ for g in _t:
25
+ unit = g[1].lower()
26
+ n = int(g[0])
27
+ u1 = unit[0]
28
+ u2 = unit[:2]
29
+ unit = u1
30
+
31
+ if u1 in ["d", "w"]:
32
+ unit = u1.upper()
33
+
34
+ if u1 in ["y"]:
35
+ n = 356 * n
36
+ unit = "D"
37
+
38
+ if u2 in ["ms", "ns", "us", "ps"]:
39
+ unit = u2
40
+
41
+ _dt += np.timedelta64(n, unit)
42
+
43
+ return _dt
44
+
45
+
46
+ def convert_seconds_to_str(seconds: int, convert_months=False) -> str:
47
+ """
48
+ Convert seconds to string representation: 310 -> '5Min10S' etc
49
+ """
50
+ r = ""
51
+
52
+ if convert_months:
53
+ months, seconds = divmod(seconds, 4 * 7 * 86400)
54
+ if months > 0:
55
+ r += "%dmonth" % months
56
+
57
+ weeks, seconds = divmod(seconds, 7 * 86400)
58
+ if weeks > 0:
59
+ r += "%dw" % weeks
60
+
61
+ days, seconds = divmod(seconds, 86400)
62
+ if days > 0:
63
+ r += "%dd" % days
64
+
65
+ hours, seconds = divmod(seconds, 3600)
66
+ if hours > 0:
67
+ r += "%dh" % hours
68
+
69
+ minutes, seconds = divmod(seconds, 60)
70
+ if minutes > 0:
71
+ r += "%dmin" % minutes
72
+
73
+ if seconds > 0:
74
+ r += "%ds" % seconds
75
+ return r
76
+
77
+
78
+ def floor_t64(time: np.datetime64 | datetime, dt: np.timedelta64 | int | str):
79
+ """
80
+ Floor timestamp by dt
81
+ """
82
+ if isinstance(dt, int):
83
+ dt = np.timedelta64(dt, "s")
84
+
85
+ if isinstance(dt, str):
86
+ dt = convert_tf_str_td64(dt)
87
+
88
+ if isinstance(time, datetime):
89
+ time = np.datetime64(time)
90
+
91
+ return time - (time - UNIX_T0) % dt
92
+
93
+
94
+ def infer_series_frequency(series: list | pd.DataFrame | pd.Series | pd.DatetimeIndex) -> np.timedelta64:
95
+ """
96
+ Infer frequency of given timeseries
97
+
98
+ :param series: Series, DataFrame, DatetimeIndex or list of timestamps object
99
+ :return: timedelta for found frequency
100
+ """
101
+ if isinstance(series, (pd.DataFrame, pd.Series, pd.DatetimeIndex)):
102
+ times_index = (series if isinstance(series, pd.DatetimeIndex) else series.index).to_pydatetime()
103
+ elif isinstance(series, (set, list, tuple)):
104
+ times_index = np.array(series)
105
+ elif isinstance(series, np.ndarray):
106
+ times_index = series
107
+ else:
108
+ raise ValueError("Can't recognize input data")
109
+
110
+ if times_index.shape[0] < 2:
111
+ raise ValueError("Series must have at least 2 points to determ frequency")
112
+
113
+ values = np.array(
114
+ sorted(
115
+ [
116
+ (
117
+ x
118
+ if isinstance(x, (np.timedelta64, int, np.int64))
119
+ else int(x)
120
+ if isinstance(x, float)
121
+ else int(1e9 * x.total_seconds())
122
+ )
123
+ for x in np.abs(np.diff(times_index))
124
+ ]
125
+ )
126
+ )
127
+ diff = np.concatenate(([1], np.diff(values)))
128
+ idx = np.concatenate((np.where(diff)[0], [len(values)]))
129
+ freqs = dict(zip(values[idx[:-1]], np.diff(idx)))
130
+ return np.timedelta64(max(freqs, key=freqs.get))
131
+
132
+
133
+ def handle_start_stop(
134
+ s: str | pd.Timestamp | None, e: str | pd.Timestamp | None, convert: Callable = str
135
+ ) -> tuple[str | pd.Timestamp | None, str | pd.Timestamp | None]:
136
+ """
137
+ Process start/stop times
138
+
139
+ >>> handle_start_stop('2020-01-01', '2020-02-01') # 2020-01-01, 2020-02-01
140
+ >>> handle_start_stop('2020-02-01', '2020-01-01') # 2020-01-01, 2020-02-01
141
+ >>> handle_start_stop('2020-01-01', '1w') # 2020-01-01, 2020-01-01 + 1week
142
+ >>> handle_start_stop('1w', '2020-01-01') # 2020-01-01 - 1week, '2020-01-01'
143
+ >>> handle_start_stop('2020-01-01', '-1w') # 2020-01-01 - 1week, 2020-01-01,
144
+ >>> handle_start_stop(None, '2020-01-01') # None, '2020-01-01'
145
+ >>> handle_start_stop('2020-01-01', None) # '2020-01-01', None
146
+ >>> handle_start_stop(None, None) # None, None
147
+
148
+ """
149
+
150
+ def _h_time_like(x):
151
+ try:
152
+ return pd.Timestamp(x), False
153
+ except:
154
+ try:
155
+ return pd.Timedelta(x), True
156
+ except:
157
+ pass
158
+ return None, None
159
+
160
+ t0, d0 = _h_time_like(s) if s else (None, False)
161
+ t1, d1 = _h_time_like(e) if e else (None, False)
162
+
163
+ def _converts(xs):
164
+ return (convert(xs[0]) if xs[0] else None, convert(xs[1]) if xs[1] else None)
165
+
166
+ if not t1 and not t0:
167
+ return None, None
168
+
169
+ if d0 and d1:
170
+ raise ValueError("Start and stop can't both be deltas !")
171
+
172
+ if d0:
173
+ if not t1:
174
+ raise ValueError("First argument is delta but stop time is not defined !")
175
+ return _converts(sorted([t1 - abs(t0), t1]))
176
+ if d1:
177
+ if not t0:
178
+ raise ValueError("Second argument is delta but start time is not defined !")
179
+ return _converts(sorted([t0, t0 + t1]))
180
+
181
+ if t0 and t1:
182
+ return _converts(sorted([t0, t1]))
183
+
184
+ return _converts([t0, t1])
185
+
186
+
187
+ def timedelta_to_crontab(td: pd.Timedelta) -> str:
188
+ """
189
+ Convert a pandas Timedelta to a crontab specification string.
190
+
191
+ Args:
192
+ td (pd.Timedelta): Timedelta to convert to crontab spec
193
+
194
+ Returns:
195
+ str: Crontab specification string
196
+
197
+ Examples:
198
+ >>> timedelta_to_crontab(pd.Timedelta('4h'))
199
+ '0 */4 * * *'
200
+ >>> timedelta_to_crontab(pd.Timedelta('2d'))
201
+ '59 23 */2 * *'
202
+ >>> timedelta_to_crontab(pd.Timedelta('1d23h50Min10Sec'))
203
+ '50 23 */2 * * 10'
204
+ """
205
+ days = td.days
206
+ hours = td.components.hours
207
+ minutes = td.components.minutes
208
+ seconds = td.components.seconds
209
+
210
+ if days > 0:
211
+ if hours == 0 and minutes == 0 and seconds == 0:
212
+ hours, minutes, seconds = 23, 59, 59
213
+ _sched = f"{minutes} {hours} */{days} * *"
214
+ return _sched + f" {seconds}" if seconds > 0 else _sched
215
+
216
+ if hours > 0:
217
+ _sched = f"{minutes} */{hours} * * *"
218
+ return _sched + f" {seconds}" if seconds > 0 else _sched
219
+
220
+ if minutes > 0:
221
+ _sched = f"*/{minutes} * * * *"
222
+ return _sched + f" {seconds}" if seconds > 0 else _sched
223
+
224
+ if seconds > 0:
225
+ return f"* * * * * */{seconds}"
226
+
227
+ raise ValueError("Timedelta must specify a non-zero period of days, hours, minutes or seconds")
228
+
229
+
230
+ def interval_to_cron(inv: str) -> str:
231
+ """
232
+ Convert a custom schedule format to a cron expression.
233
+
234
+ Args:
235
+ inv (str): Custom schedule format string. Can be either:
236
+ - A pandas Timedelta string (e.g. "4h", "2d", "1d12h")
237
+ - A custom schedule format "<interval>@<time>" where:
238
+ interval: Optional number + unit (Q=quarter, M=month, Y=year, D=day, SUN=Sunday, MON=Monday, etc.)
239
+ time: HH:MM or HH:MM:SS
240
+
241
+ Returns:
242
+ str: Cron expression
243
+
244
+ Examples:
245
+ >>> interval_to_cron("4h") # Pandas Timedelta
246
+ '0 */4 * * *'
247
+ >>> interval_to_cron("2d") # Pandas Timedelta
248
+ '59 23 */2 * *'
249
+ >>> interval_to_cron("@10:30") # Daily at 10:30
250
+ '30 10 * * *'
251
+ >>> interval_to_cron("1M@15:00") # Monthly at 15:00
252
+ '0 15 1 */1 * *'
253
+ >>> interval_to_cron("2Q@09:30:15") # Every 2 quarters at 9:30:15
254
+ '30 9 1 */6 * 15'
255
+ >>> interval_to_cron("Y@00:00") # Annually at midnight
256
+ '0 0 1 1 * *'
257
+ >>> interval_to_cron("TUE @ 23:59")
258
+ '59 23 * * 2'
259
+ """
260
+ # - first try parsing as pandas Timedelta
261
+ try:
262
+ _td_inv = pd.Timedelta(inv)
263
+ return timedelta_to_crontab(_td_inv)
264
+ except Exception:
265
+ pass
266
+
267
+ # - parse custom schedule format
268
+ try:
269
+ # - split into interval and time parts
270
+ interval, time = inv.split("@")
271
+ interval = interval.strip()
272
+ time = time.strip()
273
+
274
+ # - parse time
275
+ time_parts = time.split(":")
276
+ if len(time_parts) == 2:
277
+ hour, minute = time_parts
278
+ second = "0"
279
+ elif len(time_parts) == 3:
280
+ hour, minute, second = time_parts
281
+ else:
282
+ raise ValueError("Invalid time format")
283
+
284
+ # - parse interval
285
+ if not interval: # Default to 1 day if no interval specified
286
+ return f"{minute} {hour} * * * {second}"
287
+
288
+ match = re.match(r"^(\d+)?([A-Za-z]+)$", interval)
289
+ if not match:
290
+ raise ValueError(f"Invalid interval format: {interval}")
291
+ number = match.group(1) or "1"
292
+ unit = match.group(2).upper()
293
+
294
+ dow = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"]
295
+
296
+ # - convert to cron expression
297
+ match unit:
298
+ case "Q": # Quarter
299
+ return f"{minute} {hour} 1 */{3 * int(number)} * {second}"
300
+ case "M": # Month
301
+ return f"{minute} {hour} 1 */{number} * {second}"
302
+ case "Y": # Year
303
+ return f"{minute} {hour} 1 1 * {second}"
304
+ case "SUN" | "MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT": # Day of Week
305
+ return f"{minute} {hour} * * {dow.index(unit)} {second}"
306
+ case "D": # Day
307
+ return f"{minute} {hour} */{number} * * {second}"
308
+ case _:
309
+ raise ValueError(f"Invalid interval unit: {unit}")
310
+
311
+ except Exception as e:
312
+ raise ValueError(f"Invalid schedule format: {inv}") from e
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.3
2
+ Name: Qubx
3
+ Version: 0.5.7
4
+ Summary: Qubx - Quantitative Trading Framework
5
+ Author: Dmitry Marienko
6
+ Author-email: dmitry.marienko@xlydian.com
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Requires-Dist: ccxt (>=4.2.68,<5.0.0)
14
+ Requires-Dist: croniter (>=2.0.5,<3.0.0)
15
+ Requires-Dist: cython (==3.0.8)
16
+ Requires-Dist: dash (>=2.18.2,<3.0.0)
17
+ Requires-Dist: dash-bootstrap-components (>=1.6.0,<2.0.0)
18
+ Requires-Dist: importlib-metadata
19
+ Requires-Dist: jupyter-console (>=6.6.3,<7.0.0)
20
+ Requires-Dist: loguru (>=0.7.2,<0.8.0)
21
+ Requires-Dist: matplotlib (>=3.8.4,<4.0.0)
22
+ Requires-Dist: msgspec (>=0.18.6,<0.19.0)
23
+ Requires-Dist: ntplib (>=0.4.0,<0.5.0)
24
+ Requires-Dist: numba (>=0.59.1,<0.60.0)
25
+ Requires-Dist: numpy (>=1.26.3,<2.0.0)
26
+ Requires-Dist: pandas (>=2.2.2,<3.0.0)
27
+ Requires-Dist: plotly (>=5.22.0,<6.0.0)
28
+ Requires-Dist: psycopg (>=3.1.18,<4.0.0)
29
+ Requires-Dist: psycopg-binary (>=3.1.19,<4.0.0)
30
+ Requires-Dist: psycopg-pool (>=3.2.2,<4.0.0)
31
+ Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
32
+ Requires-Dist: pydantic (>=2.9.2,<3.0.0)
33
+ Requires-Dist: pymongo (>=4.6.1,<5.0.0)
34
+ Requires-Dist: python-binance (>=1.0.19,<2.0.0)
35
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
36
+ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
37
+ Requires-Dist: scikit-learn (>=1.4.2,<2.0.0)
38
+ Requires-Dist: scipy (>=1.12.0,<2.0.0)
39
+ Requires-Dist: sortedcontainers (>=2.4.0,<3.0.0)
40
+ Requires-Dist: stackprinter (>=0.2.10,<0.3.0)
41
+ Requires-Dist: statsmodels (>=0.14.2,<0.15.0)
42
+ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
43
+ Requires-Dist: toml (>=0.10.2,<0.11.0)
44
+ Requires-Dist: tqdm
45
+ Project-URL: Repository, https://github.com/xLydianSoftware/Qubx
46
+ Description-Content-Type: text/markdown
47
+
48
+ # Qubx
49
+
50
+ [![CI](https://github.com/xLydianSoftware/Qubx/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/xLydianSoftware/Qubx/actions/workflows/ci.yml)
51
+
52
+ ## Next generation of Qube quantitative backtesting framework (QUBX)
53
+ ```
54
+ ⠀⠀⡰⡖⠒⠒⢒⢦⠀⠀
55
+ ⠀⢠⠃⠈⢆⣀⣎⣀⣱⡀ QUBX | Quantitative Backtesting Environment
56
+ ⠀⢳⠒⠒⡞⠚⡄⠀⡰⠁ (c) 2024, by Dmytro Mariienko
57
+ ⠀⠀⠱⣜⣀⣀⣈⣦⠃⠀⠀⠀
58
+ ```
59
+
60
+ ## Documentation
61
+
62
+ See [Qubx Documentation](https://xlydiansoftware.github.io/Qubx/en/latest/)
63
+
64
+ ## Installation
65
+ > pip install qubx
66
+
67
+ ## How to run live trading (Only Binance spot tested)
68
+ 1. cd experiments/
69
+ 2. Edit strategy config file (zero_test.yaml). Testing strategy is just doing flip / flop trading once per minute (trading_allowed should be set for trading)
70
+ 3. Modify accounts config file under ./configs/.env and provide your API binance credentials (see example in example-accounts.cfg):
71
+ ```
72
+ [binance-mde]
73
+ apiKey = ...
74
+ secret = ...
75
+ base_currency = USDT
76
+ ```
77
+ 4. Run in console (-j key if want to run under jupyter console)
78
+
79
+ ```
80
+ > python ..\src\qubx\utils\runner.py configs\zero_test.yaml -a configs\.env -j
81
+ ```
82
+
83
+ ## Running tests
84
+ We use `pytest` for running tests. For running unit tests execute
85
+ ```
86
+ just test
87
+ ```
88
+
89
+ We also have several integration tests (marked with `@pytest.mark.integration`), which mainly make sure that the exchange connectors function properly. We test them on the corresponding testnets, so you will need to generate api credentials for the exchange testnets that you want to verify.
90
+
91
+ Once you have the testnet credentials store them in an `.env.integration` file in the root of the Qubx directory
92
+ ```
93
+ # BINANCE SPOT test credentials
94
+ BINANCE_SPOT_API_KEY=...
95
+ BINANCE_SPOT_SECRET=...
96
+
97
+ # BINANCE FUTURES test credentials
98
+ BINANCE_FUTURES_API_KEY=...
99
+ BINANCE_FUTURES_SECRET=...
100
+ ```
101
+
102
+ To run the tests simply call
103
+ ```
104
+ just test-integration
105
+ ```
@@ -0,0 +1,100 @@
1
+ qubx/__init__.py,sha256=pfxwsCedCQJRMyLurWZGccVlUytAPNonVRa_cyBSbmw,7145
2
+ qubx/_nb_magic.py,sha256=r1Qd2khQhwIqgbuf2oALobEGNw0pGh_sBU3XSpK76UA,3025
3
+ qubx/backtester/__init__.py,sha256=OhXhLmj2x6sp6k16wm5IPATvv-E2qRZVIcvttxqPgcg,176
4
+ qubx/backtester/account.py,sha256=VBFiUMS3So1wVJCmQ3NtZ6Px1zMyi9hVjiq5Cn7sfm8,5838
5
+ qubx/backtester/broker.py,sha256=9Xm85OyLf-1hc2G1CcIPnatTMvFcdUTZSClJWc4quKU,2759
6
+ qubx/backtester/data.py,sha256=ArY8EDbgws_34Or1eHkgZgzU_QRNJrH3PaGXH7x3CfM,11967
7
+ qubx/backtester/management.py,sha256=HuyzFsBPgR7j-ei78Ngcx34CeSn65c9atmaii1aTsYg,14900
8
+ qubx/backtester/ome.py,sha256=BPb8iLJ-YpBhS4XJrrPzcj2RN8hmTNjkOjdAzDkNfXY,11055
9
+ qubx/backtester/optimization.py,sha256=HHUIYA6Y66rcOXoePWFOuOVX9iaHGKV0bGt_4d5e6FM,7619
10
+ qubx/backtester/simulated_data.py,sha256=xy4zDIF8bwum5F3mEachdIaQu9DOIfsBcR1AogF3CH0,22176
11
+ qubx/backtester/simulator.py,sha256=nkoCD3JQ6eUPxyo1e1lB7lLpd5_IwtB4oR7VpKaE0sI,14380
12
+ qubx/backtester/utils.py,sha256=V8ethHIUhs3o85q1ssWwJj1s6NplwVpdzOFIjluUd3A,30483
13
+ qubx/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ qubx/cli/commands.py,sha256=SMl7Zax3OiWjB5M4fFh5w0bIVI4OLJrYUDsamjCe7_w,2276
15
+ qubx/connectors/ccxt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ qubx/connectors/ccxt/account.py,sha256=0-NyqDVEu6vim9rBgO4L9Ek3EKHmq2A82eTKpoOSyFM,21630
17
+ qubx/connectors/ccxt/broker.py,sha256=I91BRQBbVrZm9YGp6AkW_qHSQv-6Qf0H2Rt53Pmh4rk,4114
18
+ qubx/connectors/ccxt/customizations.py,sha256=K5MoNuatjmyOcDhQ_54vdp8D1cb_QgfkoeHdBGJxiOQ,7709
19
+ qubx/connectors/ccxt/data.py,sha256=RekxCqjRBOTY1IEkNM2aNvdXwm-rHoRs7hT2vk4lrI0,25291
20
+ qubx/connectors/ccxt/exceptions.py,sha256=OfZc7iMdEG8uLorcZta2NuEuJrSIqi0FG7IICmwF54M,262
21
+ qubx/connectors/ccxt/factory.py,sha256=KROJ9-7zfoKZuess99UZMzgsZakISbN3XDOkEB-Ev4s,2818
22
+ qubx/connectors/ccxt/utils.py,sha256=Hn1gK3BCmwbivVjAmwaBy4zQPqwZl0jWbNwdV5_E0po,10612
23
+ qubx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ qubx/core/account.py,sha256=MOrllpuZLyaJ1EwsEJst0GaxcC7Z7XMT-VF7OR-1NMQ,10213
25
+ qubx/core/basics.py,sha256=7CaER2uM73840CUNe9ej9I6BzSkwgydM-RQwVsL5LZ0,27780
26
+ qubx/core/context.py,sha256=nOzB_FFzGwjtYo7o8lwBEnJASr1fkd9B_Cc3SCcy7Kw,15616
27
+ qubx/core/exceptions.py,sha256=Jidp6v8rF6bCGB4SDNPt5CMHltkd9tbVkHzOvM29KdU,477
28
+ qubx/core/helpers.py,sha256=7nhO-CgleU6RTXpSwCdMwb0ZwLCYi5hJWnag8kfFDXo,17701
29
+ qubx/core/interfaces.py,sha256=giiZAZpNsj5cUCEJMRv9IY1LKqTkbKS41xYksAI24uE,34369
30
+ qubx/core/loggers.py,sha256=STXvRvDsi9NTHdEzQFsedbvg71aB0ixjNfNZ2QvIT9w,17595
31
+ qubx/core/lookups.py,sha256=UN136wkw-51MBm61WAMaEvFfhjM63oCRkEsoELd8BIU,15686
32
+ qubx/core/metrics.py,sha256=7b9kza1Fu3aGSf4llUiNTIGT1wsRDOaProK5lGk_a5M,57877
33
+ qubx/core/mixins/__init__.py,sha256=AMCLvfNuIb1kkQl3bhCj9jIOEl2eKcVPJeyLgrkB-rk,329
34
+ qubx/core/mixins/market.py,sha256=s1NQDUjex7LR_ShnbSA3VnPMZpP7NmCgax5cmHdTmh4,3251
35
+ qubx/core/mixins/processing.py,sha256=dOERoe2TkNPihuXpb1lhawU78gCIdUukZNWThc-JeJY,18097
36
+ qubx/core/mixins/subscription.py,sha256=J_SX0CNw2bPy4bhxe0vswvDXY4LCkwXSaj_1PepKRLY,8540
37
+ qubx/core/mixins/trading.py,sha256=CQQIp1t1LJiFph5CiHQR4k4vxTymjFqrkA0awKYn4Dw,3224
38
+ qubx/core/mixins/universe.py,sha256=1ya2P3QZrsAVXmMXqq0t6CHGAC5iMGVD2ARUAtSfv04,10062
39
+ qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=mpLWRTkmp3hepypAn87T4_b21k86StgccuOHRbxm-P0,882248
40
+ qubx/core/series.pxd,sha256=EqgYT41FrpVB274mDG3jpLCSqK_ykkL-d-1IH8DE1ik,3301
41
+ qubx/core/series.pyi,sha256=zBt8DQCiIdTU3MLJz_9MlrONo7UCVYh2xYUltAcAj6c,3247
42
+ qubx/core/series.pyx,sha256=4XCRdH3otXsU8EJ-g4_zLQfhqR8TVjtEq_e4oDz5mZ4,33836
43
+ qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=zoDD-UQ8Je50_INgdV0PK7CzKTQQ9nSPgs3nZo60obg,86568
44
+ qubx/core/utils.pyi,sha256=DAjyRVPJSxK4Em-9wui2F0yYHfP5tI5DjKavXNOnHa8,276
45
+ qubx/core/utils.pyx,sha256=k5QHfEFvqhqWfCob89ANiJDKNG8gGbOh-O4CVoneZ8M,1696
46
+ qubx/data/__init__.py,sha256=CTbEWfMC3eVfD4v6OdhEH4AXGNybrnJJ-mxOM-n2e_M,482
47
+ qubx/data/helpers.py,sha256=GZIQJk5m1rbCX-_heZmJrMZeTpElPT88vGosUIWDuKI,16660
48
+ qubx/data/readers.py,sha256=RedH9MyOzrYjS3EXNwM_y4nRKbYJtU0Gs6---RFdrBA,55528
49
+ qubx/data/tardis.py,sha256=LzKSjCEhAupMYlB46SWUo71zSKhSwh26GnGHHxhb9MQ,3769
50
+ qubx/gathering/simplest.py,sha256=2BXyzj0wHohVYT1E4Rqwdf9K_gZPoZ_eW9MSe0uliBo,3959
51
+ qubx/math/__init__.py,sha256=ltHSQj40sCBm3owcvtoZp34h6ws7pZCFcSZgUkTsUCY,114
52
+ qubx/math/stats.py,sha256=dLfomw5uBYolurxNPKxcGoL27pTEqiTnjI5cZ_-9-gU,4021
53
+ qubx/pandaz/__init__.py,sha256=vSUWqD3XhPq96Kc3Q_msjdRFEjFB-moSnFWxlCf5gkw,460
54
+ qubx/pandaz/ta.py,sha256=ONqPOeqtAkjKWolO9gWbbfrS2bDDB_kzV8aBu_yDVEE,91608
55
+ qubx/pandaz/utils.py,sha256=zAHUIAApSRrlQa5AjpIbiQ9ftSGIBOu_ppDg0c3gXaE,23380
56
+ qubx/resources/instruments/symbols-binance.cm.json,sha256=rNI3phNeeRY95_IE7_0Um9d5U4jUtEijZQ_PaYg5cdw,25127
57
+ qubx/resources/instruments/symbols-binance.json,sha256=Qx_XckgsWNhmmV8_t5DpG0AeGkuTyt1uiif2EeeBDIg,939678
58
+ qubx/resources/instruments/symbols-binance.um.json,sha256=eroAZmpc_Iez0uDxsk1rcnSmznuQ9eEoCPQHlNyTfI8,227785
59
+ qubx/resources/instruments/symbols-bitfinex.f.json,sha256=URpMkOM4hB4-6-RY1yJU-fSPADwE7F-EOGmxWEjqspo,34758
60
+ qubx/resources/instruments/symbols-bitfinex.json,sha256=CpzoVgWzGZRN6RpUNhtJVxa3SeSvLVx5Q8GYHfYwd8s,263231
61
+ qubx/resources/instruments/symbols-kraken.f.json,sha256=lwNqml3H7lNUl1h3siySSyE1MRcGfqfhb6BcxLsiKr0,212258
62
+ qubx/resources/instruments/symbols-kraken.json,sha256=RjUTvkQuuu7V1HfSQREvnA4qqkdkB3-rzykDaQds2rQ,456544
63
+ qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=EIsiwKN8_U6jxWISbKLKfmrrXMBY5ZUswPuLM-slv-g,654440
65
+ qubx/ta/indicators.pxd,sha256=eCJ9paOxtxbDFx4U5CUhcgB1jjCQAfVqMF2FnbJ03Lo,4222
66
+ qubx/ta/indicators.pyi,sha256=NJlvN_774UV1U3_lvaYYbCEikLR8sOUo0TdcUGR5GBM,1940
67
+ qubx/ta/indicators.pyx,sha256=FVkv5ld04TpZMT3a_kR1MU3IUuWfijzjJnh_lG78JxM,26029
68
+ qubx/trackers/__init__.py,sha256=Df2YGR6SM9ANfMQDV21Q6Nh0MO-tLIt4Yt42v6HR3EI,175
69
+ qubx/trackers/abvanced.py,sha256=vo4DuX6sYzsXLcp5z1UYuGowlJEE47vzmSoKsMLBPu4,10307
70
+ qubx/trackers/composite.py,sha256=W-n1vd4l-RZEoojj6lICqvJ8EgTV2kE6JUUmZUkZ1cI,6339
71
+ qubx/trackers/rebalancers.py,sha256=5Dx39QZ67iZVx-cfpYx4IoMgDd7-fCHvGkwtezL7ofY,5269
72
+ qubx/trackers/riskctrl.py,sha256=QyYbXZ7NGJYpNK1i92z9PlCvWbiKMb-TTuj6xs1PzbA,26799
73
+ qubx/trackers/sizers.py,sha256=r2w8HOS2_LRZEi_WjU0KRXqxmfhi2JNhbtOpfqmywRk,9608
74
+ qubx/utils/__init__.py,sha256=pIS1ulI6Hj8btZlPd5P9To7DlyEY20bEVvFREAZkR0A,384
75
+ qubx/utils/_pyxreloader.py,sha256=FyqGzfSpZGYziB8JYS5AP3cLRAvJSIPAKgwQn0E4YQ0,12017
76
+ qubx/utils/charting/lookinglass.py,sha256=m7lWU8c0E8tXzGbkN0GB8CL-kd92MnH_wD8cATX067k,39232
77
+ qubx/utils/charting/mpl_helpers.py,sha256=e9XNnEvUpFJtB3zpgJCyMSeUkKbBfumJhnWLCXmU1k0,36085
78
+ qubx/utils/marketdata/binance.py,sha256=_Hm2KtMFrUOguHlT3ZhRZFmoszG8ivRh72vCUZWhssU,11224
79
+ qubx/utils/marketdata/ccxt.py,sha256=IhTT8prs42x_pIhFKv2AweFGIdEh2kGZYacbjXSmxV0,3466
80
+ qubx/utils/marketdata/dukas.py,sha256=yz4dfOM4UDuz2BYeM8vlTzaZX83VPx_OW-mGwGr-L4E,3237
81
+ qubx/utils/misc.py,sha256=xwAPcU9H50jc3NEOJizOfrZD9unrtVFR16QApS66xGM,16218
82
+ qubx/utils/ntp.py,sha256=yNurgbdiqKhq_dVrJ5PRnho9SzT3ijQG-Bi2sDnFSLs,1904
83
+ qubx/utils/numbers_utils.py,sha256=pAXZsurOOXwoFdPJPm0muSY1RkFhFHYjuB-Dzx6Ed48,240
84
+ qubx/utils/orderbook.py,sha256=Lz9TqYRiHmfUA1HcmKgtmiZKKvOtn-ugX8d81s4xyMU,18258
85
+ qubx/utils/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ qubx/utils/plotting/dashboard.py,sha256=NB236RONucjcPr3NWAMzUGs9sIY6eKsPdBXi8PkXODc,5547
87
+ qubx/utils/plotting/data.py,sha256=ZOg8rHAq4NVmfsyhvzFHtey4HaXywAHufxhv1IExRqg,4773
88
+ qubx/utils/plotting/interfaces.py,sha256=mtRcoWIMt2xkv-Tc2ZgXZQpr5HRiWhPcqkIslzZTeig,493
89
+ qubx/utils/plotting/renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
+ qubx/utils/plotting/renderers/plotly.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ qubx/utils/runner/__init__.py,sha256=axs9MF78BYk30jhHBu0gSXIr-IN5ZOzoprlJ_N85yN8,77
92
+ qubx/utils/runner/_jupyter_runner.pyt,sha256=0SSc9F6caok_uRy9Qzy3L7hEuebZykH6U5QEM9YnhZU,2321
93
+ qubx/utils/runner/accounts.py,sha256=3D9bqqG4MWVRw2YJ5iT1RgmyGRdTEBr7BDk1UephIUo,3237
94
+ qubx/utils/runner/configs.py,sha256=nQXU1oqtSSGpGHw4cqk1dVpcojibj7bzjWZbDAHRxNc,1741
95
+ qubx/utils/runner/runner.py,sha256=As5tMRilyK9Eh2_NlQdEibXBxhEF3QR1fOidjvrwrPg,17894
96
+ qubx/utils/time.py,sha256=1Cvh077Uqf-XjcE5nWp_T9JzFVT6i39kU7Qz-ssHKIo,9630
97
+ qubx-0.5.7.dist-info/METADATA,sha256=YO2DNAvYGdPWm-2r8SJOr-8S0Goskz1tKIpPiNzhYy0,3853
98
+ qubx-0.5.7.dist-info/WHEEL,sha256=h1DdjcD2ZFnKGsDLjEycQhNNPJ5l-R8qdFdDSXHrAGY,110
99
+ qubx-0.5.7.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
100
+ qubx-0.5.7.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.1.1
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-manylinux_2_39_x86_64
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ qubx=qubx.cli.commands:main
3
+