Qubx 0.6.10__cp312-cp312-manylinux_2_39_x86_64.whl → 0.6.12__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.
- qubx/core/basics.py +14 -2
- qubx/core/loggers.py +22 -12
- qubx/core/series.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/core/utils.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/restarts/state_resolvers.py +1 -1
- qubx/restorers/signal.py +6 -1
- qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so +0 -0
- {qubx-0.6.10.dist-info → qubx-0.6.12.dist-info}/METADATA +1 -1
- {qubx-0.6.10.dist-info → qubx-0.6.12.dist-info}/RECORD +11 -11
- {qubx-0.6.10.dist-info → qubx-0.6.12.dist-info}/WHEEL +0 -0
- {qubx-0.6.10.dist-info → qubx-0.6.12.dist-info}/entry_points.txt +0 -0
qubx/core/basics.py
CHANGED
|
@@ -475,6 +475,7 @@ class Position:
|
|
|
475
475
|
self.quantity = quantity
|
|
476
476
|
self.position_avg_price = pos_average_price
|
|
477
477
|
self.r_pnl = r_pnl
|
|
478
|
+
self.__pos_incr_qty = abs(quantity)
|
|
478
479
|
|
|
479
480
|
def reset(self) -> None:
|
|
480
481
|
"""
|
|
@@ -539,6 +540,7 @@ class Position:
|
|
|
539
540
|
deal_pnl = 0
|
|
540
541
|
quantity = self.quantity
|
|
541
542
|
comms = 0
|
|
543
|
+
# logger.info(f"{self.instrument.symbol} exec_price={exec_price} fee_amount={fee_amount} position={position}")
|
|
542
544
|
|
|
543
545
|
if quantity != position:
|
|
544
546
|
pos_change = position - quantity
|
|
@@ -550,13 +552,17 @@ class Position:
|
|
|
550
552
|
qty_opening = pos_change if prev_direction == direction else pos_change - qty_closing
|
|
551
553
|
|
|
552
554
|
# - extract realized part of PnL
|
|
553
|
-
if qty_closing
|
|
555
|
+
if not np.isclose(qty_closing, 0.0):
|
|
554
556
|
_abs_qty_close = abs(qty_closing)
|
|
555
557
|
deal_pnl = qty_closing * (self.position_avg_price - exec_price)
|
|
556
558
|
|
|
557
559
|
quantity += qty_closing
|
|
558
560
|
self.__pos_incr_qty -= _abs_qty_close
|
|
559
561
|
|
|
562
|
+
# logger.info(
|
|
563
|
+
# f"{self.instrument.symbol} qty_closing={qty_closing} deal_pnl={deal_pnl} quantity={quantity} pos_incr_qty={self.__pos_incr_qty} position_avg_price={self.position_avg_price}"
|
|
564
|
+
# )
|
|
565
|
+
|
|
560
566
|
# - reset average price to 0 if smaller than minimal price change to avoid cumulative error
|
|
561
567
|
if abs(quantity) < self.instrument.lot_size:
|
|
562
568
|
quantity = 0.0
|
|
@@ -564,11 +570,17 @@ class Position:
|
|
|
564
570
|
self.__pos_incr_qty = 0
|
|
565
571
|
|
|
566
572
|
# - if it has something to add to position let's update price and cost
|
|
567
|
-
if qty_opening
|
|
573
|
+
if not np.isclose(qty_opening, 0.0):
|
|
568
574
|
_abs_qty_open = abs(qty_opening)
|
|
575
|
+
|
|
576
|
+
# logger.info(
|
|
577
|
+
# f"{self.instrument.symbol} qty_opening={qty_opening} exec_price={exec_price} pos_incr_qty={self.__pos_incr_qty} position_avg_price={self.position_avg_price}"
|
|
578
|
+
# )
|
|
579
|
+
|
|
569
580
|
pos_avg_price_raw = (_abs_qty_open * exec_price + self.__pos_incr_qty * self.position_avg_price) / (
|
|
570
581
|
self.__pos_incr_qty + _abs_qty_open
|
|
571
582
|
)
|
|
583
|
+
|
|
572
584
|
# - round position average price to be in line with how it's calculated by broker
|
|
573
585
|
self.position_avg_price = self.instrument.round_price_down(pos_avg_price_raw)
|
|
574
586
|
self.__pos_incr_qty += _abs_qty_open
|
qubx/core/loggers.py
CHANGED
|
@@ -216,8 +216,10 @@ class _BaseIntervalDumper:
|
|
|
216
216
|
def store(self, timestamp: np.datetime64):
|
|
217
217
|
_t_ns = time_as_nsec(timestamp)
|
|
218
218
|
if self._freq:
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
# Convert freq to nanoseconds for calculation
|
|
220
|
+
_freq_ns = self._freq.astype("int64")
|
|
221
|
+
_interval_start_time = int(_t_ns - (_t_ns % _freq_ns))
|
|
222
|
+
if _t_ns - self._last_log_time_ns >= _freq_ns:
|
|
221
223
|
self.dump(np.datetime64(_interval_start_time, "ns"), timestamp)
|
|
222
224
|
self._last_log_time_ns = _interval_start_time
|
|
223
225
|
else:
|
|
@@ -412,22 +414,29 @@ class SignalsLogger(_BaseIntervalDumper):
|
|
|
412
414
|
|
|
413
415
|
class BalanceLogger(_BaseIntervalDumper):
|
|
414
416
|
"""
|
|
415
|
-
Balance logger -
|
|
417
|
+
Balance logger - save balance information at regular intervals similar to positions
|
|
416
418
|
"""
|
|
417
419
|
|
|
418
420
|
_writer: LogsWriter
|
|
421
|
+
_balance: dict[str, AssetBalance]
|
|
419
422
|
|
|
420
|
-
def __init__(self, writer: LogsWriter) -> None:
|
|
421
|
-
super().__init__(
|
|
423
|
+
def __init__(self, writer: LogsWriter, interval: str) -> None:
|
|
424
|
+
super().__init__(interval)
|
|
422
425
|
self._writer = writer
|
|
426
|
+
self._balance = {}
|
|
423
427
|
|
|
424
|
-
def record_balance(self, timestamp: np.datetime64, balance:
|
|
428
|
+
def record_balance(self, timestamp: np.datetime64, balance: dict[str, AssetBalance]):
|
|
425
429
|
if balance:
|
|
430
|
+
self._balance = balance
|
|
431
|
+
self.dump(timestamp, timestamp)
|
|
432
|
+
|
|
433
|
+
def dump(self, interval_start_time: np.datetime64, actual_timestamp: np.datetime64):
|
|
434
|
+
if self._balance:
|
|
426
435
|
data = []
|
|
427
|
-
for s, d in
|
|
436
|
+
for s, d in self._balance.items():
|
|
428
437
|
data.append(
|
|
429
438
|
{
|
|
430
|
-
"timestamp":
|
|
439
|
+
"timestamp": str(interval_start_time),
|
|
431
440
|
"currency": s,
|
|
432
441
|
"total": d.total,
|
|
433
442
|
"locked": d.locked,
|
|
@@ -435,9 +444,6 @@ class BalanceLogger(_BaseIntervalDumper):
|
|
|
435
444
|
)
|
|
436
445
|
self._writer.write_data("balance", data)
|
|
437
446
|
|
|
438
|
-
def store(self, timestamp: np.datetime64):
|
|
439
|
-
pass
|
|
440
|
-
|
|
441
447
|
def close(self):
|
|
442
448
|
self._writer.flush_data()
|
|
443
449
|
|
|
@@ -484,7 +490,7 @@ class StrategyLogging:
|
|
|
484
490
|
self.signals_logger = SignalsLogger(logs_writer, num_signals_records_to_write)
|
|
485
491
|
|
|
486
492
|
# - balance logger
|
|
487
|
-
self.balance_logger = BalanceLogger(logs_writer)
|
|
493
|
+
self.balance_logger = BalanceLogger(logs_writer, positions_log_freq)
|
|
488
494
|
else:
|
|
489
495
|
logger.warning("Log writer is not defined - strategy activity will not be saved !")
|
|
490
496
|
|
|
@@ -534,6 +540,10 @@ class StrategyLogging:
|
|
|
534
540
|
if self.portfolio_logger:
|
|
535
541
|
self.portfolio_logger.store(timestamp)
|
|
536
542
|
|
|
543
|
+
# - notify balance logger
|
|
544
|
+
if self.balance_logger:
|
|
545
|
+
self.balance_logger.store(timestamp)
|
|
546
|
+
|
|
537
547
|
# - log heartbeat
|
|
538
548
|
self._log_heartbeat(timestamp)
|
|
539
549
|
|
|
Binary file
|
|
Binary file
|
qubx/restarts/state_resolvers.py
CHANGED
|
@@ -43,7 +43,7 @@ class StateResolver:
|
|
|
43
43
|
ctx.trade(instrument, -live_qty)
|
|
44
44
|
|
|
45
45
|
# If live position is larger than sim position (same direction), reduce it
|
|
46
|
-
elif abs(live_qty) > abs(sim_qty) and abs(
|
|
46
|
+
elif abs(live_qty) > abs(sim_qty) and abs(live_qty) > instrument.lot_size:
|
|
47
47
|
qty_diff = sim_qty - live_qty
|
|
48
48
|
logger.info(
|
|
49
49
|
f"Reducing position for {instrument.symbol}: {live_qty} -> {sim_qty} (diff: {qty_diff})"
|
qubx/restorers/signal.py
CHANGED
|
@@ -78,7 +78,12 @@ class CsvSignalRestorer(ISignalRestorer):
|
|
|
78
78
|
|
|
79
79
|
try:
|
|
80
80
|
# Read the CSV file
|
|
81
|
-
|
|
81
|
+
try:
|
|
82
|
+
df = pd.read_csv(file_path)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.info(f"Could not read signal file {file_path}: {e}")
|
|
85
|
+
return {}
|
|
86
|
+
|
|
82
87
|
if df.empty:
|
|
83
88
|
logger.info(f"No signals found in {file_path}")
|
|
84
89
|
return {}
|
|
Binary file
|
|
@@ -27,13 +27,13 @@ qubx/connectors/ccxt/reader.py,sha256=qaZIaOZkRf3Rz31ZrEqqAv4kATk5zDlSq-LK1jziBs
|
|
|
27
27
|
qubx/connectors/ccxt/utils.py,sha256=kWeYQ1Z9TxFTbgJgBh5o77mGB1g09l2AkiFdR6guDQY,11141
|
|
28
28
|
qubx/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
qubx/core/account.py,sha256=Ewzmr1jxyLROnWshtx_ngi7fna1cH42NJ5wVRyP4dmQ,10411
|
|
30
|
-
qubx/core/basics.py,sha256=
|
|
30
|
+
qubx/core/basics.py,sha256=sPB3dL0FYF_bYALySnUrOwGLQfKb7B9dkK3PIV1MCFM,29364
|
|
31
31
|
qubx/core/context.py,sha256=t4A1sWM6dn4t-LSKOC-66x4Y-_5aGduEedO_Gmd3Yrg,20593
|
|
32
32
|
qubx/core/exceptions.py,sha256=ONFzWISjWfb2S0kEIorq-3L4MdhNR-xkHftHQALOZ0U,533
|
|
33
33
|
qubx/core/helpers.py,sha256=9nl9L_ZzT1HsMC9VthMqXfmuRS_37crB-9bVfIRHeOs,19631
|
|
34
34
|
qubx/core/initializer.py,sha256=PUiD_cIjvGpuPjYyRpUjpwm3xNQ2Kipa8bAhbtxCQRo,3935
|
|
35
35
|
qubx/core/interfaces.py,sha256=5ldBmncZHonf5ymSUbcIDjZx68127v9wEnppMSjhWow,49122
|
|
36
|
-
qubx/core/loggers.py,sha256=
|
|
36
|
+
qubx/core/loggers.py,sha256=eYhJANHYwz1heeFMa5V7jYCL196wkTSvj6c-8lkPj1Y,19567
|
|
37
37
|
qubx/core/lookups.py,sha256=KBE0ab4eheA6C5C-RIND_svYhE7Glb4CSlLRjMhPNRc,15906
|
|
38
38
|
qubx/core/metrics.py,sha256=2AocZUYwoZE8OvScN3ULa-wyVregzlCn722QIZUe7Q8,57784
|
|
39
39
|
qubx/core/mixins/__init__.py,sha256=AMCLvfNuIb1kkQl3bhCj9jIOEl2eKcVPJeyLgrkB-rk,329
|
|
@@ -42,11 +42,11 @@ qubx/core/mixins/processing.py,sha256=Ny9EyrTuF_YBmPsAebykV54OfGMBGE1gSam9VFJJKa
|
|
|
42
42
|
qubx/core/mixins/subscription.py,sha256=J_SX0CNw2bPy4bhxe0vswvDXY4LCkwXSaj_1PepKRLY,8540
|
|
43
43
|
qubx/core/mixins/trading.py,sha256=KApWQE0zIh1jg_9HezLdR-mp3UEYIdylSyX9MajHmCc,3618
|
|
44
44
|
qubx/core/mixins/universe.py,sha256=1ya2P3QZrsAVXmMXqq0t6CHGAC5iMGVD2ARUAtSfv04,10062
|
|
45
|
-
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
45
|
+
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=oGjkxetdjaacB1CRU3AZ09xbh8T8AsNhl5DswDeWs9Q,970056
|
|
46
46
|
qubx/core/series.pxd,sha256=ZA9mBrZ-ha112ZMZnBIun1kNrKjxzlaOoq4D_cDZYJw,3923
|
|
47
47
|
qubx/core/series.pyi,sha256=r6o2SnYIBujmJuuoM8oEc3tbVg2Blz2CfSIdRKn9VMo,4547
|
|
48
48
|
qubx/core/series.pyx,sha256=Y6GbCihO3zgUWOF9UvmyXisWLnGcVOcFl2u1ZtvM1zI,44909
|
|
49
|
-
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
49
|
+
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=WIcuOQ9itXm60-ItviKaUZHRSlARcCz0e-925ZpzSio,86568
|
|
50
50
|
qubx/core/utils.pyi,sha256=a-wS13V2p_dM1CnGq40JVulmiAhixTwVwt0ah5By0Hc,348
|
|
51
51
|
qubx/core/utils.pyx,sha256=k5QHfEFvqhqWfCob89ANiJDKNG8gGbOh-O4CVoneZ8M,1696
|
|
52
52
|
qubx/data/__init__.py,sha256=ELZykvpPGWc5rX7QoNyNQwMLgdKMG8MACOByA4pM5hA,549
|
|
@@ -93,18 +93,18 @@ qubx/resources/instruments/symbols-bitfinex.json,sha256=CpzoVgWzGZRN6RpUNhtJVxa3
|
|
|
93
93
|
qubx/resources/instruments/symbols-kraken.f.json,sha256=lwNqml3H7lNUl1h3siySSyE1MRcGfqfhb6BcxLsiKr0,212258
|
|
94
94
|
qubx/resources/instruments/symbols-kraken.json,sha256=RjUTvkQuuu7V1HfSQREvnA4qqkdkB3-rzykDaQds2rQ,456544
|
|
95
95
|
qubx/restarts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
|
-
qubx/restarts/state_resolvers.py,sha256=
|
|
96
|
+
qubx/restarts/state_resolvers.py,sha256=nWdGgMXNIZbnadmAh1-cTvT5KXRKbQxXv-2Kgvp67qY,5132
|
|
97
97
|
qubx/restarts/time_finders.py,sha256=r7yyRhJByV2uqdgamDRX2XClwpWWI9BNpc80t9nk6c0,2448
|
|
98
98
|
qubx/restorers/__init__.py,sha256=vrnZBPJHR0-6knAccj4bK0tkjUPNRl32qiLr5Mv4aR0,911
|
|
99
99
|
qubx/restorers/balance.py,sha256=ipkrRSVAscC_if6jaFtNMexHK6Z2teds2IzWdcS9yAI,3964
|
|
100
100
|
qubx/restorers/factory.py,sha256=vq78vvf_ASKa-rGsV9UZlob7HCHMkiKIlLYUeCfB16g,6431
|
|
101
101
|
qubx/restorers/interfaces.py,sha256=CcjBWavKq8_GIMKTSPodMa-n3wJQwcQTwyvYyNo_J3c,1776
|
|
102
102
|
qubx/restorers/position.py,sha256=_I_LNPXXTshxlI9hQS2ANO54JwDwseXU_PJgMmZmFCY,4764
|
|
103
|
-
qubx/restorers/signal.py,sha256=
|
|
103
|
+
qubx/restorers/signal.py,sha256=DBLqA7vDhoMTAzUC4N9UerrO0GbjeHdTeMoCz7U7iI8,6621
|
|
104
104
|
qubx/restorers/state.py,sha256=ePmh604fp2kRYzMNXL-TWvZOxmtTGAaKYfHJcnKResY,4042
|
|
105
105
|
qubx/restorers/utils.py,sha256=We2gfqwQKWziUYhuUnjb-xo-5tSlbuHWpPQn0CEMTn0,1155
|
|
106
106
|
qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
107
|
-
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
107
|
+
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=JfqqbFytabhLARoUwoDKuGXw3uPrl6Tf0eg8L944pB4,654440
|
|
108
108
|
qubx/ta/indicators.pxd,sha256=eCJ9paOxtxbDFx4U5CUhcgB1jjCQAfVqMF2FnbJ03Lo,4222
|
|
109
109
|
qubx/ta/indicators.pyi,sha256=19W0uERft49In5bf9jkJHkzJYEyE9gzudN7_DJ5Vdv8,1963
|
|
110
110
|
qubx/ta/indicators.pyx,sha256=FVkv5ld04TpZMT3a_kR1MU3IUuWfijzjJnh_lG78JxM,26029
|
|
@@ -138,7 +138,7 @@ qubx/utils/runner/configs.py,sha256=vtl04A42kT21hD68zpoZZw96rEC8HnFFX9en0Y85GLA,
|
|
|
138
138
|
qubx/utils/runner/runner.py,sha256=kwigJ9MgBcOkDpYAHj2TuwQzNerwyUWaE4UmyNYxD34,37910
|
|
139
139
|
qubx/utils/time.py,sha256=J0ZFGjzFL5T6GA8RPAel8hKG0sg2LZXeQ5YfDCfcMHA,10055
|
|
140
140
|
qubx/utils/version.py,sha256=e52fIHyxzCiIuH7svCF6pkHuDlqL64rklqz-2XjWons,5309
|
|
141
|
-
qubx-0.6.
|
|
142
|
-
qubx-0.6.
|
|
143
|
-
qubx-0.6.
|
|
144
|
-
qubx-0.6.
|
|
141
|
+
qubx-0.6.12.dist-info/METADATA,sha256=wrLTsq0yccxDnyeB2sHqCU6p6jiS8A5DjHZtivEVoWI,4142
|
|
142
|
+
qubx-0.6.12.dist-info/WHEEL,sha256=h1DdjcD2ZFnKGsDLjEycQhNNPJ5l-R8qdFdDSXHrAGY,110
|
|
143
|
+
qubx-0.6.12.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
|
|
144
|
+
qubx-0.6.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|