Qubx 0.1.86__tar.gz → 0.1.88__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.
- {qubx-0.1.86 → qubx-0.1.88}/PKG-INFO +1 -1
- {qubx-0.1.86 → qubx-0.1.88}/build.py +12 -17
- {qubx-0.1.86 → qubx-0.1.88}/pyproject.toml +2 -2
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/ta/indicators.pyx +85 -55
- {qubx-0.1.86 → qubx-0.1.88}/README.md +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/_nb_magic.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/account.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/basics.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/helpers.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/loggers.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/lookups.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/series.pxd +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/series.pyx +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/strategy.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/core/utils.pyx +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/data/readers.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/impl/ccxt_connector.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/impl/ccxt_customizations.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/impl/ccxt_trading.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/impl/ccxt_utils.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/math/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/math/stats.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/pandaz/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/pandaz/ta.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/pandaz/utils.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/ta/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/trackers/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/trackers/rebalancers.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/__init__.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/_pyxreloader.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/charting/mpl_helpers.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/marketdata/binance.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/misc.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/runner.py +0 -0
- {qubx-0.1.86 → qubx-0.1.88}/src/qubx/utils/time.py +0 -0
|
@@ -17,6 +17,8 @@ from Cython.Compiler.Version import version as cython_compiler_version
|
|
|
17
17
|
from setuptools import Distribution
|
|
18
18
|
from setuptools import Extension
|
|
19
19
|
|
|
20
|
+
RED, BLUE, GREEN, YLW, RES = "\033[31m", "\033[36m", "\033[32m", "\033[33m", "\033[0m"
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
BUILD_MODE = os.getenv("BUILD_MODE", "release")
|
|
22
24
|
PROFILE_MODE = bool(os.getenv("PROFILE_MODE", ""))
|
|
@@ -95,13 +97,13 @@ def _build_extensions() -> list[Extension]:
|
|
|
95
97
|
"WS2_32.Lib",
|
|
96
98
|
]
|
|
97
99
|
|
|
98
|
-
print("Creating C extension modules...")
|
|
100
|
+
print(f">> {GREEN} Creating C extension modules...{RES}")
|
|
99
101
|
print(f"define_macros={define_macros}")
|
|
100
102
|
print(f"extra_compile_args={extra_compile_args}")
|
|
101
103
|
|
|
102
104
|
return [
|
|
103
105
|
Extension(
|
|
104
|
-
name=str(pyx.relative_to("
|
|
106
|
+
name=str(pyx.relative_to("src")).replace(os.path.sep, ".")[:-4],
|
|
105
107
|
sources=[str(pyx)],
|
|
106
108
|
include_dirs=[np.get_include()], # , *RUST_INCLUDES],
|
|
107
109
|
define_macros=define_macros,
|
|
@@ -138,7 +140,7 @@ def _build_distribution(extensions: list[Extension]) -> Distribution:
|
|
|
138
140
|
def _copy_build_dir_to_project(cmd: build_ext) -> None:
|
|
139
141
|
# Copy built extensions back to the project tree
|
|
140
142
|
for output in cmd.get_outputs():
|
|
141
|
-
relative_extension = Path(output).relative_to(cmd.build_lib)
|
|
143
|
+
relative_extension = Path("src") / Path(output).relative_to(cmd.build_lib)
|
|
142
144
|
if not Path(output).exists():
|
|
143
145
|
continue
|
|
144
146
|
|
|
@@ -148,21 +150,19 @@ def _copy_build_dir_to_project(cmd: build_ext) -> None:
|
|
|
148
150
|
mode |= (mode & 0o444) >> 2
|
|
149
151
|
relative_extension.chmod(mode)
|
|
150
152
|
|
|
151
|
-
print("Copied all compiled dynamic library files into source")
|
|
153
|
+
print(f" >> {GREEN}Copied all compiled dynamic library files into source{RES}")
|
|
152
154
|
|
|
153
155
|
|
|
154
156
|
def _strip_unneeded_symbols() -> None:
|
|
155
157
|
try:
|
|
156
|
-
print("Stripping unneeded symbols from binaries...")
|
|
158
|
+
print(f" >> {YLW}Stripping unneeded symbols from binaries...{RES}")
|
|
157
159
|
for so in itertools.chain(Path("src/qubx").rglob("*.so")):
|
|
158
160
|
if platform.system() == "Linux":
|
|
159
161
|
strip_cmd = ["strip", "--strip-unneeded", so]
|
|
160
162
|
elif platform.system() == "Darwin":
|
|
161
163
|
strip_cmd = ["strip", "-x", so]
|
|
162
164
|
else:
|
|
163
|
-
raise RuntimeError(
|
|
164
|
-
f"Cannot strip symbols for platform {platform.system()}"
|
|
165
|
-
)
|
|
165
|
+
raise RuntimeError(f"Cannot strip symbols for platform {platform.system()}")
|
|
166
166
|
subprocess.run(
|
|
167
167
|
strip_cmd, # type: ignore [arg-type] # noqa
|
|
168
168
|
check=True,
|
|
@@ -185,7 +185,7 @@ def build() -> None:
|
|
|
185
185
|
distribution = _build_distribution(extensions)
|
|
186
186
|
|
|
187
187
|
# Build and run the command
|
|
188
|
-
print("Compiling C extension modules...")
|
|
188
|
+
print(f">> {GREEN} Compiling C extension modules...{RES}")
|
|
189
189
|
cmd: build_ext = build_ext(distribution)
|
|
190
190
|
# if PARALLEL_BUILD:
|
|
191
191
|
# cmd.parallel = os.cpu_count()
|
|
@@ -201,15 +201,12 @@ def build() -> None:
|
|
|
201
201
|
_strip_unneeded_symbols()
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
RED, BLUE, GREEN, YLW, RES = "\033[31m", "\033[36m", "\033[32m", "\033[33m", "\033[0m"
|
|
205
204
|
if __name__ == "__main__":
|
|
206
205
|
qubx_platform = toml.load("pyproject.toml")["tool"]["poetry"]["version"]
|
|
207
206
|
print(BLUE)
|
|
208
207
|
print("=====================================================================")
|
|
209
208
|
print(f"Qubx Builder {qubx_platform}")
|
|
210
|
-
print(
|
|
211
|
-
"=====================================================================\033[0m"
|
|
212
|
-
)
|
|
209
|
+
print("=====================================================================\033[0m")
|
|
213
210
|
print(f"System: {GREEN}{platform.system()} {platform.machine()}{RES}")
|
|
214
211
|
# print(f"Clang: {GREEN}{_get_clang_version()}{RES}")
|
|
215
212
|
# print(f"Rust: {GREEN}{_get_rustc_version()}{RES}")
|
|
@@ -225,12 +222,10 @@ if __name__ == "__main__":
|
|
|
225
222
|
print(f"COPY_TO_SOURCE={COPY_TO_SOURCE}")
|
|
226
223
|
# print(f"PYO3_ONLY={PYO3_ONLY}\n")
|
|
227
224
|
|
|
228
|
-
print("Starting build...")
|
|
225
|
+
print(f">> {GREEN}Starting build...{RES}")
|
|
229
226
|
ts_start = datetime.datetime.now(datetime.timezone.utc)
|
|
230
227
|
build()
|
|
231
|
-
print(
|
|
232
|
-
f"Build time: {YLW}{datetime.datetime.now(datetime.timezone.utc) - ts_start}{RES}"
|
|
233
|
-
)
|
|
228
|
+
print(f"Build time: {YLW}{datetime.datetime.now(datetime.timezone.utc) - ts_start}{RES}")
|
|
234
229
|
print(GREEN + "Build completed" + RES)
|
|
235
230
|
|
|
236
231
|
# # See if Cython is installed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "Qubx"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.88"
|
|
4
4
|
description = "Qubx - quantitative trading framework"
|
|
5
5
|
authors = ["Dmitry Marienko <dmitry@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -66,4 +66,4 @@ pytest-mock = "*"
|
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
[tool.pytest.ini_options]
|
|
69
|
-
pythonpath = ["src"]
|
|
69
|
+
pythonpath = ["src"]
|
|
@@ -274,7 +274,8 @@ cdef class Pewma(Indicator):
|
|
|
274
274
|
cdef double alpha, beta
|
|
275
275
|
cdef int T
|
|
276
276
|
|
|
277
|
-
cdef double _mean,
|
|
277
|
+
cdef double _mean, _vstd, _var
|
|
278
|
+
cdef double mean, vstd, var
|
|
278
279
|
cdef long _i
|
|
279
280
|
|
|
280
281
|
def __init__(self, str name, TimeSeries series, double alpha, double beta, int T):
|
|
@@ -287,34 +288,51 @@ cdef class Pewma(Indicator):
|
|
|
287
288
|
self.std = TimeSeries('std', series.timeframe, series.max_series_length)
|
|
288
289
|
super().__init__(name, series)
|
|
289
290
|
|
|
291
|
+
def _store(self):
|
|
292
|
+
self.mean = self._mean
|
|
293
|
+
self.vstd = self._vstd
|
|
294
|
+
self.var = self._var
|
|
295
|
+
|
|
296
|
+
def _restore(self):
|
|
297
|
+
self._mean = self.mean
|
|
298
|
+
self._vstd = self.vstd
|
|
299
|
+
self._var = self.var
|
|
300
|
+
|
|
301
|
+
def _get_alpha(self, p_t):
|
|
302
|
+
if self._i - 1 > self.T:
|
|
303
|
+
return self.alpha * (1.0 - self.beta * p_t)
|
|
304
|
+
return 1.0 - 1.0 / self._i
|
|
305
|
+
|
|
290
306
|
cpdef double calculate(self, long long time, double x, short new_item_started):
|
|
291
|
-
cdef double diff,
|
|
307
|
+
cdef double diff, p_t, a_t, incr
|
|
292
308
|
|
|
293
|
-
if self.
|
|
309
|
+
if len(self.series) <= 1:
|
|
294
310
|
self._mean = x
|
|
295
|
-
self.
|
|
311
|
+
self._vstd = 0.0
|
|
296
312
|
self._var = 0.0
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
diff = x - self._mean
|
|
301
|
-
# prob of observing diff
|
|
302
|
-
p = norm_pdf(diff / self._std) if self._std != 0.0 else 0.0
|
|
303
|
-
|
|
304
|
-
# weight to give to this point
|
|
305
|
-
a_t = self.alpha * (1 - self.beta * p) if self._i > self.T else (1.0 - 1.0 / self._i)
|
|
306
|
-
incr = (1.0 - a_t) * diff
|
|
307
|
-
v = a_t * (self._var + diff * incr)
|
|
308
|
-
self.std.update(time, np.sqrt(v))
|
|
313
|
+
self._store()
|
|
314
|
+
self.std.update(time, self.vstd)
|
|
315
|
+
return self.mean
|
|
309
316
|
|
|
310
317
|
if new_item_started:
|
|
311
|
-
self._mean += incr
|
|
312
318
|
self._i += 1
|
|
313
|
-
self.
|
|
314
|
-
|
|
315
|
-
self.
|
|
319
|
+
self._restore()
|
|
320
|
+
else:
|
|
321
|
+
self._store()
|
|
322
|
+
|
|
323
|
+
diff = x - self.mean
|
|
324
|
+
# prob of observing diff
|
|
325
|
+
p_t = norm_pdf(diff / self.vstd) if self.vstd != 0.0 else 0.0
|
|
326
|
+
|
|
327
|
+
# weight to give to this point
|
|
328
|
+
a_t = self._get_alpha(p_t)
|
|
329
|
+
incr = (1.0 - a_t) * diff
|
|
330
|
+
self.mean += incr
|
|
331
|
+
self.var = a_t * (self.var + diff * incr)
|
|
332
|
+
self.vstd = np.sqrt(self.var)
|
|
333
|
+
self.std.update(time, self.vstd)
|
|
316
334
|
|
|
317
|
-
return self.
|
|
335
|
+
return self.mean
|
|
318
336
|
|
|
319
337
|
|
|
320
338
|
def pewma(series:TimeSeries, alpha: float, beta: float, T:int=30):
|
|
@@ -326,14 +344,13 @@ def pewma(series:TimeSeries, alpha: float, beta: float, T:int=30):
|
|
|
326
344
|
|
|
327
345
|
|
|
328
346
|
cdef class PewmaOutliersDetector(Indicator):
|
|
329
|
-
cdef public TimeSeries upper
|
|
330
|
-
cdef public TimeSeries lower
|
|
331
|
-
cdef public TimeSeries outliers
|
|
347
|
+
cdef public TimeSeries upper, lower, outliers, std
|
|
332
348
|
cdef double alpha, beta, threshold
|
|
333
349
|
cdef int T
|
|
334
350
|
|
|
335
351
|
cdef long _i
|
|
336
|
-
cdef double
|
|
352
|
+
cdef double mean, vstd, variance
|
|
353
|
+
cdef double _mean, _vstd, _variance, _z_thr
|
|
337
354
|
|
|
338
355
|
def __init__(self, str name, TimeSeries series, double alpha, double beta, int T, double threshold):
|
|
339
356
|
self.alpha = alpha
|
|
@@ -344,44 +361,43 @@ cdef class PewmaOutliersDetector(Indicator):
|
|
|
344
361
|
# - series
|
|
345
362
|
self.upper = TimeSeries('uba', series.timeframe, series.max_series_length)
|
|
346
363
|
self.lower = TimeSeries('lba', series.timeframe, series.max_series_length)
|
|
364
|
+
self.std = TimeSeries('std', series.timeframe, series.max_series_length)
|
|
347
365
|
self.outliers = TimeSeries('outliers', series.timeframe, series.max_series_length)
|
|
348
366
|
|
|
349
367
|
# - local variables
|
|
350
368
|
self._i = 0
|
|
351
369
|
self._z_thr = ndtri(1 - threshold / 2)
|
|
352
370
|
|
|
353
|
-
self._mean = 0.0
|
|
354
|
-
self._variance = 0.0
|
|
355
|
-
self._std = 0.0
|
|
356
371
|
super().__init__(name, series)
|
|
357
372
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
373
|
+
def _store(self):
|
|
374
|
+
self.mean = self._mean
|
|
375
|
+
self.vstd = self._vstd
|
|
376
|
+
self.variance = self._variance
|
|
361
377
|
|
|
362
|
-
|
|
363
|
-
|
|
378
|
+
def _restore(self):
|
|
379
|
+
self._mean = self.mean
|
|
380
|
+
self._vstd = self.vstd
|
|
381
|
+
self._variance = self.variance
|
|
364
382
|
|
|
365
|
-
|
|
383
|
+
cdef double _get_alpha(self, double p_t):
|
|
384
|
+
if self._i + 1 >= self.T:
|
|
385
|
+
return self.alpha * (1.0 - self.beta * p_t)
|
|
386
|
+
return 1.0 - 1.0 / (self._i + 1.0)
|
|
366
387
|
|
|
367
388
|
cdef double _get_mean(self, double x, double alpha_t):
|
|
368
|
-
return alpha_t * self.
|
|
389
|
+
return alpha_t * self.mean + (1.0 - alpha_t) * x
|
|
369
390
|
|
|
370
391
|
cdef double _get_variance(self, double x, double alpha_t):
|
|
371
|
-
return alpha_t * self.
|
|
392
|
+
return alpha_t * self.variance + (1.0 - alpha_t) * np.square(x)
|
|
372
393
|
|
|
373
394
|
cdef double _get_std(self, double variance, double mean):
|
|
374
395
|
return np.sqrt(max(variance - np.square(mean), 0.0))
|
|
375
396
|
|
|
376
397
|
cdef double _get_p(self, double x):
|
|
377
|
-
cdef double z_t = 0.0
|
|
378
|
-
cdef double p_t
|
|
379
|
-
|
|
380
|
-
if self._i != 1:
|
|
381
|
-
z_t = ((x - self._mean) / self._std) if (self._std != 0 and not np.isnan(x)) else 0.0
|
|
382
|
-
|
|
398
|
+
cdef double z_t = ((x - self.mean) / self.vstd) if (self.vstd != 0 and not np.isnan(x)) else 0.0
|
|
383
399
|
# if self.dist == 'normal':
|
|
384
|
-
p_t = norm_pdf(z_t)
|
|
400
|
+
# p_t = norm_pdf(z_t)
|
|
385
401
|
# elif self.dist == 'cauchy':
|
|
386
402
|
# p_t = (1 / (np.pi * (1 + np.square(z_t))))
|
|
387
403
|
# elif self.dist == 'student_t':
|
|
@@ -389,31 +405,45 @@ cdef class PewmaOutliersDetector(Indicator):
|
|
|
389
405
|
# (np.sqrt(self.count - 1) * np.sqrt(np.pi) * np.exp(np.math.lgamma(0.5 * (self.count - 1))))
|
|
390
406
|
# else:
|
|
391
407
|
# raise ValueError('Invalid distribution type')
|
|
392
|
-
return
|
|
408
|
+
return norm_pdf(z_t)
|
|
393
409
|
|
|
394
410
|
cpdef double calculate(self, long long time, double x, short new_item_started):
|
|
411
|
+
# - first bar - just use it as initial value
|
|
412
|
+
if len(self.series) <= 1:
|
|
413
|
+
self._mean = x
|
|
414
|
+
self._variance = x ** 2
|
|
415
|
+
self._vstd = 0.0
|
|
416
|
+
self._store()
|
|
417
|
+
self.std.update(time, self.vstd)
|
|
418
|
+
self.upper.update(time, x)
|
|
419
|
+
self.lower.update(time, x)
|
|
420
|
+
return self._mean
|
|
421
|
+
|
|
422
|
+
# - new bar is started use n-1 values for calculate innovations
|
|
423
|
+
if new_item_started:
|
|
424
|
+
self._i += 1
|
|
425
|
+
self._restore()
|
|
426
|
+
else:
|
|
427
|
+
self._store()
|
|
428
|
+
|
|
395
429
|
cdef double p_t = self._get_p(x)
|
|
396
430
|
cdef double alpha_t = self._get_alpha(p_t)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
cdef double ub = mean + self._z_thr *
|
|
401
|
-
cdef double lb = mean - self._z_thr *
|
|
431
|
+
self.mean = self._get_mean(x, alpha_t)
|
|
432
|
+
self.variance = self._get_variance(x, alpha_t)
|
|
433
|
+
self.vstd = self._get_std(self.variance, self.mean)
|
|
434
|
+
cdef double ub = self.mean + self._z_thr * self.vstd
|
|
435
|
+
cdef double lb = self.mean - self._z_thr * self.vstd
|
|
402
436
|
|
|
403
437
|
self.upper.update(time, ub)
|
|
404
438
|
self.lower.update(time, lb)
|
|
405
|
-
|
|
406
|
-
self._mean = mean
|
|
407
|
-
self._i += 1
|
|
408
|
-
self._variance = variance
|
|
409
|
-
self._std = std
|
|
439
|
+
self.std.update(time, self.vstd)
|
|
410
440
|
|
|
411
441
|
# - check if it's outlier
|
|
412
442
|
if p_t < self.threshold:
|
|
413
443
|
self.outliers.update(time, x)
|
|
414
444
|
else:
|
|
415
445
|
self.outliers.update(time, np.nan)
|
|
416
|
-
return mean
|
|
446
|
+
return self.mean
|
|
417
447
|
|
|
418
448
|
|
|
419
449
|
def pewma_outliers_detector(series:TimeSeries, alpha: float, beta: float, T:int=30, threshold=0.05):
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|