Qubx 0.6.50__cp312-cp312-manylinux_2_39_x86_64.whl → 0.6.52__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/mixins/processing.py +1 -1
- qubx/core/mixins/universe.py +4 -3
- 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/notifications/slack.py +14 -8
- qubx/restarts/state_resolvers.py +2 -2
- qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so +0 -0
- qubx/utils/runner/factory.py +3 -1
- qubx/utils/runner/runner.py +14 -0
- {qubx-0.6.50.dist-info → qubx-0.6.52.dist-info}/METADATA +1 -1
- {qubx-0.6.50.dist-info → qubx-0.6.52.dist-info}/RECORD +14 -14
- {qubx-0.6.50.dist-info → qubx-0.6.52.dist-info}/LICENSE +0 -0
- {qubx-0.6.50.dist-info → qubx-0.6.52.dist-info}/WHEEL +0 -0
- {qubx-0.6.50.dist-info → qubx-0.6.52.dist-info}/entry_points.txt +0 -0
qubx/core/mixins/processing.py
CHANGED
|
@@ -383,7 +383,7 @@ class ProcessingManager(IProcessingManager):
|
|
|
383
383
|
missing_symbols = [inst.symbol for inst in missing_instruments]
|
|
384
384
|
logger.info(
|
|
385
385
|
f"Phase 1: Waiting for all instruments ({ready_instruments}/{total_instruments} ready). "
|
|
386
|
-
f"Missing: {missing_symbols}. Timeout in {self.DATA_READY_TIMEOUT_SECONDS - elapsed_time_seconds
|
|
386
|
+
f"Missing: {missing_symbols}. Timeout in {self.DATA_READY_TIMEOUT_SECONDS - elapsed_time_seconds}s"
|
|
387
387
|
)
|
|
388
388
|
return False
|
|
389
389
|
else:
|
qubx/core/mixins/universe.py
CHANGED
|
@@ -114,11 +114,12 @@ class UniverseManager(IUniverseManager):
|
|
|
114
114
|
self._removal_queue.pop(instr)
|
|
115
115
|
|
|
116
116
|
def add_instruments(self, instruments: list[Instrument]):
|
|
117
|
-
self.
|
|
117
|
+
to_add = list(set([instr for instr in instruments if instr not in self._instruments]))
|
|
118
|
+
self.__do_add_instruments(to_add)
|
|
118
119
|
self.__cleanup_removal_queue(instruments)
|
|
119
|
-
self._strategy.on_universe_change(self._context,
|
|
120
|
+
self._strategy.on_universe_change(self._context, to_add, [])
|
|
120
121
|
self._subscription_manager.commit()
|
|
121
|
-
self._instruments.update(
|
|
122
|
+
self._instruments.update(to_add)
|
|
122
123
|
|
|
123
124
|
def remove_instruments(
|
|
124
125
|
self,
|
|
Binary file
|
|
Binary file
|
qubx/notifications/slack.py
CHANGED
|
@@ -5,6 +5,7 @@ This module provides a Slack implementation of IStrategyLifecycleNotifier.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import datetime
|
|
8
|
+
import threading
|
|
8
9
|
from concurrent.futures import ThreadPoolExecutor
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
@@ -52,6 +53,9 @@ class SlackLifecycleNotifier(IStrategyLifecycleNotifier):
|
|
|
52
53
|
self._emoji_error = emoji_error
|
|
53
54
|
self._throttler = throttler if throttler is not None else NoThrottling()
|
|
54
55
|
|
|
56
|
+
# Add a lock for thread-safe throttling operations
|
|
57
|
+
self._throttler_lock = threading.Lock()
|
|
58
|
+
|
|
55
59
|
self._executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="slack_notifier")
|
|
56
60
|
|
|
57
61
|
logger.info(f"[SlackLifecycleNotifier] Initialized for environment '{environment}'")
|
|
@@ -75,10 +79,16 @@ class SlackLifecycleNotifier(IStrategyLifecycleNotifier):
|
|
|
75
79
|
throttle_key: Optional key for throttling (if None, no throttling is applied)
|
|
76
80
|
"""
|
|
77
81
|
try:
|
|
78
|
-
#
|
|
79
|
-
if throttle_key is not None
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
# Thread-safe throttling check and registration
|
|
83
|
+
if throttle_key is not None:
|
|
84
|
+
with self._throttler_lock:
|
|
85
|
+
if not self._throttler.should_send(throttle_key):
|
|
86
|
+
logger.debug(f"[SlackLifecycleNotifier] Throttled message with key '{throttle_key}': {message}")
|
|
87
|
+
return
|
|
88
|
+
# Immediately register that we're about to send this message
|
|
89
|
+
# This prevents race conditions where multiple threads check should_send
|
|
90
|
+
# before any of them call register_sent
|
|
91
|
+
self._throttler.register_sent(throttle_key)
|
|
82
92
|
|
|
83
93
|
# Submit the task to the executor
|
|
84
94
|
self._executor.submit(self._post_to_slack_impl, message, emoji, color, metadata, throttle_key)
|
|
@@ -132,10 +142,6 @@ class SlackLifecycleNotifier(IStrategyLifecycleNotifier):
|
|
|
132
142
|
response = requests.post(self._webhook_url, json=data)
|
|
133
143
|
response.raise_for_status()
|
|
134
144
|
|
|
135
|
-
# Register that we sent the message (for throttling)
|
|
136
|
-
if throttle_key is not None:
|
|
137
|
-
self._throttler.register_sent(throttle_key)
|
|
138
|
-
|
|
139
145
|
logger.debug(f"[SlackLifecycleNotifier] Successfully posted message: {message}")
|
|
140
146
|
return True
|
|
141
147
|
except requests.RequestException as e:
|
qubx/restarts/state_resolvers.py
CHANGED
|
@@ -55,7 +55,7 @@ class StateResolver:
|
|
|
55
55
|
elif abs(live_qty) > abs(sim_qty) and abs(live_qty) > instrument.lot_size:
|
|
56
56
|
qty_diff = sim_qty - live_qty
|
|
57
57
|
logger.info(
|
|
58
|
-
f"Reducing position for {instrument.symbol}: {live_qty} -> {sim_qty} (diff: {qty_diff})"
|
|
58
|
+
f"Reducing position for {instrument.symbol}: {live_qty} -> {sim_qty} (diff: {qty_diff:.4f})"
|
|
59
59
|
)
|
|
60
60
|
ctx.trade(instrument, qty_diff)
|
|
61
61
|
|
|
@@ -123,7 +123,7 @@ class StateResolver:
|
|
|
123
123
|
# Only trade if there's a difference
|
|
124
124
|
if abs(qty_diff) > instrument.lot_size:
|
|
125
125
|
logger.info(
|
|
126
|
-
f"Syncing position for {instrument.symbol}: {live_qty} -> {sim_pos.quantity} (diff: {qty_diff})"
|
|
126
|
+
f"Syncing position for {instrument.symbol}: {live_qty} -> {sim_pos.quantity} (diff: {qty_diff:.4f})"
|
|
127
127
|
)
|
|
128
128
|
ctx.trade(instrument, qty_diff)
|
|
129
129
|
|
|
Binary file
|
qubx/utils/runner/factory.py
CHANGED
|
@@ -298,7 +298,9 @@ def create_lifecycle_notifiers(
|
|
|
298
298
|
params[key] = resolve_env_vars(value)
|
|
299
299
|
|
|
300
300
|
# Create throttler if configured or use default TimeWindowThrottler
|
|
301
|
-
if "SlackLifecycleNotifier" in notifier_class_name and
|
|
301
|
+
if "SlackLifecycleNotifier" in notifier_class_name and (
|
|
302
|
+
"throttle" not in params or params["throttle"] is None
|
|
303
|
+
):
|
|
302
304
|
# Import here to avoid circular imports
|
|
303
305
|
from qubx.notifications.throttler import TimeWindowThrottler
|
|
304
306
|
|
qubx/utils/runner/runner.py
CHANGED
|
@@ -28,6 +28,7 @@ from qubx.core.basics import (
|
|
|
28
28
|
CtrlChannel,
|
|
29
29
|
Instrument,
|
|
30
30
|
LiveTimeProvider,
|
|
31
|
+
Position,
|
|
31
32
|
RestoredState,
|
|
32
33
|
TransactionCostsCalculator,
|
|
33
34
|
)
|
|
@@ -695,6 +696,14 @@ def _run_warmup(
|
|
|
695
696
|
if o.instrument in _instruments:
|
|
696
697
|
instrument_to_orders[o.instrument].append(o)
|
|
697
698
|
|
|
699
|
+
# - find instruments with nonzero positions from restored state and add them to the context
|
|
700
|
+
if restored_state is not None:
|
|
701
|
+
restored_positions = {k: p for k, p in restored_state.positions.items() if p.is_open()}
|
|
702
|
+
# - if there is no warmup position for a restored position, then create a new zero position
|
|
703
|
+
for pos in restored_positions.values():
|
|
704
|
+
if pos.instrument not in _positions:
|
|
705
|
+
_positions[pos.instrument] = Position(pos.instrument)
|
|
706
|
+
|
|
698
707
|
# - set the warmup positions and orders
|
|
699
708
|
ctx.set_warmup_positions(_positions)
|
|
700
709
|
ctx.set_warmup_orders(instrument_to_orders)
|
|
@@ -766,6 +775,11 @@ def simulate_strategy(
|
|
|
766
775
|
for a, c in cond.items():
|
|
767
776
|
conditions.append(dict2lambda(a, c))
|
|
768
777
|
|
|
778
|
+
# - if a parameter is of type list, then transform it to list of lists to avoid invalid variation
|
|
779
|
+
for k, v in cfg.parameters.items():
|
|
780
|
+
if isinstance(v, list):
|
|
781
|
+
cfg.parameters[k] = [v]
|
|
782
|
+
|
|
769
783
|
experiments = variate(stg_cls, **(cfg.parameters | cfg.simulation.variate), conditions=conditions)
|
|
770
784
|
experiments = {f"{simulation_name}.{_v_id}.[{k}]": v for k, v in experiments.items()}
|
|
771
785
|
print(f"Parameters variation is configured. There are {len(experiments)} simulations to run.")
|
|
@@ -49,15 +49,15 @@ qubx/core/lookups.py,sha256=aEuyZqd_N4cQ-oHz3coEHcdX9Yb0cP5-NwDuj-DQyNk,19477
|
|
|
49
49
|
qubx/core/metrics.py,sha256=74xIecCvlxVXl0gy0JvgjJ2X5gg-RMmVZw9hQikkHE0,60269
|
|
50
50
|
qubx/core/mixins/__init__.py,sha256=AMCLvfNuIb1kkQl3bhCj9jIOEl2eKcVPJeyLgrkB-rk,329
|
|
51
51
|
qubx/core/mixins/market.py,sha256=lBappEimPhIuI0vmUvwVlIztkYjlEjJBpP-AdpfudII,3948
|
|
52
|
-
qubx/core/mixins/processing.py,sha256=
|
|
52
|
+
qubx/core/mixins/processing.py,sha256=VEaK6ZjXTa8jvavj_VpCYfGvLFTHpNoL1AKdRAeear8,27394
|
|
53
53
|
qubx/core/mixins/subscription.py,sha256=V_g9wCPQ8S5SHkU-qOZ84cV5nReAUrV7DoSNAGG0LPY,10372
|
|
54
54
|
qubx/core/mixins/trading.py,sha256=idfRPaqrvkfMxzu9mXr9i_xfqLee-ZAOrERxkxv6Ruo,7256
|
|
55
|
-
qubx/core/mixins/universe.py,sha256=
|
|
56
|
-
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
55
|
+
qubx/core/mixins/universe.py,sha256=tsMpBriLHwK9lAVYvIrO94EIx8_ETSXUlzxN_sDOsL8,9838
|
|
56
|
+
qubx/core/series.cpython-312-x86_64-linux-gnu.so,sha256=SpozS5G2UEoeCbgVsaorjvwbKo5U4d5EqxP3pSktzyM,978280
|
|
57
57
|
qubx/core/series.pxd,sha256=jBdMwgO8J4Zrue0e_xQ5RlqTXqihpzQNu6V3ckZvvpY,3978
|
|
58
58
|
qubx/core/series.pyi,sha256=RaHm_oHHiWiNUMJqVfx5FXAXniGLsHxUFOUpacn7GC0,4604
|
|
59
59
|
qubx/core/series.pyx,sha256=7cM3zZThW59waHiYcZmMxvYj-HYD7Ej_l7nKA4emPjE,46477
|
|
60
|
-
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
60
|
+
qubx/core/utils.cpython-312-x86_64-linux-gnu.so,sha256=c3ZAL_JGRFpOPUlSITmuQ_jjxv4bA1CQAV9c13wtUfI,86568
|
|
61
61
|
qubx/core/utils.pyi,sha256=a-wS13V2p_dM1CnGq40JVulmiAhixTwVwt0ah5By0Hc,348
|
|
62
62
|
qubx/core/utils.pyx,sha256=k5QHfEFvqhqWfCob89ANiJDKNG8gGbOh-O4CVoneZ8M,1696
|
|
63
63
|
qubx/data/__init__.py,sha256=ELZykvpPGWc5rX7QoNyNQwMLgdKMG8MACOByA4pM5hA,549
|
|
@@ -99,7 +99,7 @@ qubx/math/__init__.py,sha256=ltHSQj40sCBm3owcvtoZp34h6ws7pZCFcSZgUkTsUCY,114
|
|
|
99
99
|
qubx/math/stats.py,sha256=uXm4NpBRxuHFTjXERv8rjM0MAJof8zr1Cklyra4CcBA,4056
|
|
100
100
|
qubx/notifications/__init__.py,sha256=cb3DGxuiA8UwSTlTeF5pQKy4-vBef3gMeKtfcxEjdN4,547
|
|
101
101
|
qubx/notifications/composite.py,sha256=fa-rvHEn6k-Fma5N7cT-7Sk7hzVyB0KDs2ktDyoyLxM,2689
|
|
102
|
-
qubx/notifications/slack.py,sha256=
|
|
102
|
+
qubx/notifications/slack.py,sha256=RWsLyL4lm6tbmrTlXQo3nPlfiLVJ0vCfY5toJ9G8RWU,8316
|
|
103
103
|
qubx/notifications/throttler.py,sha256=8jnymPQbrgtN1rD7REQa2sA9teSWTqkk_uT9oaknOyc,5618
|
|
104
104
|
qubx/pandaz/__init__.py,sha256=6BYz6gSgxjNa7WP1XqWflYG7WIq1ppSD9h1XGR5M5YQ,682
|
|
105
105
|
qubx/pandaz/ta.py,sha256=sIX9YxxB2S2nWU4vnS4rXFuEI5WSY76Ky1TFwf9RhMw,92154
|
|
@@ -113,7 +113,7 @@ qubx/resources/instruments/symbols-bitfinex.json,sha256=CpzoVgWzGZRN6RpUNhtJVxa3
|
|
|
113
113
|
qubx/resources/instruments/symbols-kraken.f.json,sha256=lwNqml3H7lNUl1h3siySSyE1MRcGfqfhb6BcxLsiKr0,212258
|
|
114
114
|
qubx/resources/instruments/symbols-kraken.json,sha256=RjUTvkQuuu7V1HfSQREvnA4qqkdkB3-rzykDaQds2rQ,456544
|
|
115
115
|
qubx/restarts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
116
|
-
qubx/restarts/state_resolvers.py,sha256=
|
|
116
|
+
qubx/restarts/state_resolvers.py,sha256=xzQEFPGbYFYShSSb0cB3RvWl-8npRau_HrrMgTccSc0,5614
|
|
117
117
|
qubx/restarts/time_finders.py,sha256=r7yyRhJByV2uqdgamDRX2XClwpWWI9BNpc80t9nk6c0,2448
|
|
118
118
|
qubx/restorers/__init__.py,sha256=vrnZBPJHR0-6knAccj4bK0tkjUPNRl32qiLr5Mv4aR0,911
|
|
119
119
|
qubx/restorers/balance.py,sha256=yLV1vBki0XhBxrOhgaJBHuuL8VmIii82LAWgLxusbcE,6967
|
|
@@ -124,7 +124,7 @@ qubx/restorers/signal.py,sha256=0QFoy7OzDkK6AAmJEbbmSsHwmAhjMJYYggVFuLraKjk,1089
|
|
|
124
124
|
qubx/restorers/state.py,sha256=dLaVnUwRCNRkUqbYyi0RfZs3Q3AdglkI_qTtQ8GDD5Y,7289
|
|
125
125
|
qubx/restorers/utils.py,sha256=We2gfqwQKWziUYhuUnjb-xo-5tSlbuHWpPQn0CEMTn0,1155
|
|
126
126
|
qubx/ta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
127
|
-
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=
|
|
127
|
+
qubx/ta/indicators.cpython-312-x86_64-linux-gnu.so,sha256=PwEMehN97zxTw_faYmjrDUHu_8-QlfsjOxo3h7bPQKo,654440
|
|
128
128
|
qubx/ta/indicators.pxd,sha256=Goo0_N0Xnju8XGo3Xs-3pyg2qr_0Nh5C-_26DK8U_IE,4224
|
|
129
129
|
qubx/ta/indicators.pyi,sha256=19W0uERft49In5bf9jkJHkzJYEyE9gzudN7_DJ5Vdv8,1963
|
|
130
130
|
qubx/ta/indicators.pyx,sha256=Xgpew46ZxSXsdfSEWYn3A0Q35MLsopB9n7iyCsXTufs,25969
|
|
@@ -157,12 +157,12 @@ qubx/utils/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
157
157
|
qubx/utils/runner/_jupyter_runner.pyt,sha256=fDj4AUs25jsdGmY9DDeSFufH1JkVhLFwy0BOmVO7nIU,9609
|
|
158
158
|
qubx/utils/runner/accounts.py,sha256=mpiv6oxr5z97zWt7STYyARMhWQIpc_XFKungb_pX38U,3270
|
|
159
159
|
qubx/utils/runner/configs.py,sha256=snVZJun6rBC09QZVaUd7BhqNlDZqmDMG7R8gHJeuSkU,3713
|
|
160
|
-
qubx/utils/runner/factory.py,sha256=
|
|
161
|
-
qubx/utils/runner/runner.py,sha256=
|
|
160
|
+
qubx/utils/runner/factory.py,sha256=eM4-Etcq-FewD2AjH_srFGzP413pm8er95KIZixXRpM,15152
|
|
161
|
+
qubx/utils/runner/runner.py,sha256=9s7mu84U29jCE7FtdW_yKKTzQfaXmCSvANF5cb7xd_Y,31399
|
|
162
162
|
qubx/utils/time.py,sha256=J0ZFGjzFL5T6GA8RPAel8hKG0sg2LZXeQ5YfDCfcMHA,10055
|
|
163
163
|
qubx/utils/version.py,sha256=e52fIHyxzCiIuH7svCF6pkHuDlqL64rklqz-2XjWons,5309
|
|
164
|
-
qubx-0.6.
|
|
165
|
-
qubx-0.6.
|
|
166
|
-
qubx-0.6.
|
|
167
|
-
qubx-0.6.
|
|
168
|
-
qubx-0.6.
|
|
164
|
+
qubx-0.6.52.dist-info/LICENSE,sha256=qwMHOSJ2TD0nx6VUJvFhu1ynJdBfNozRMt6tnSul-Ts,35140
|
|
165
|
+
qubx-0.6.52.dist-info/METADATA,sha256=Hor3x6zOv1rKp_mKkMdFc6HqE5bWIh14oHlX8ignRLk,4612
|
|
166
|
+
qubx-0.6.52.dist-info/WHEEL,sha256=UckHTmFUCaLKpi4yFY8Dewu0c6XkY-KvEAGzGOnaWo8,110
|
|
167
|
+
qubx-0.6.52.dist-info/entry_points.txt,sha256=VqilDTe8mVuV9SbR-yVlZJBTjbkHIL2JBgXfQw076HY,47
|
|
168
|
+
qubx-0.6.52.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|