xtquant-big-convert 0.2.0__py3-none-any.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.
- BIGQMT_REDIS_DRYRUN.py +254 -0
- BIGQMT_ZMQ_BACKTEST.py +152 -0
- bigqmt_backtest/__init__.py +23 -0
- bigqmt_backtest/__main__.py +5 -0
- bigqmt_backtest/broker.py +358 -0
- bigqmt_backtest/client.py +134 -0
- bigqmt_backtest/data_feed.py +278 -0
- bigqmt_backtest/engine.py +372 -0
- bigqmt_backtest/models.py +179 -0
- bigqmt_backtest/protocol.py +137 -0
- bigqmt_backtest/qmt_runtime.py +718 -0
- bigqmt_backtest/server.py +80 -0
- bigqmt_backtest/strategy.py +75 -0
- bigqmt_backtest/zmq_server.py +65 -0
- bigqmt_signal_trader/README.md +50 -0
- bigqmt_signal_trader/__init__.py +32 -0
- bigqmt_signal_trader/adapter_factory.py +159 -0
- bigqmt_signal_trader/adapters/__init__.py +1 -0
- bigqmt_signal_trader/adapters/market_bigqmt.py +1115 -0
- bigqmt_signal_trader/adapters/order_bigqmt.py +192 -0
- bigqmt_signal_trader/adapters/order_dryrun.py +30 -0
- bigqmt_signal_trader/adapters/position_bigqmt.py +146 -0
- bigqmt_signal_trader/adapters/position_sync_redis.py +65 -0
- bigqmt_signal_trader/adapters/redis_common.py +56 -0
- bigqmt_signal_trader/adapters/signal_redis.py +115 -0
- bigqmt_signal_trader/adapters/state_redis.py +90 -0
- bigqmt_signal_trader/app.py +98 -0
- bigqmt_signal_trader/code_utils.py +48 -0
- bigqmt_signal_trader/contracts.py +81 -0
- bigqmt_signal_trader/download_jobs.py +252 -0
- bigqmt_signal_trader/exec_events.py +449 -0
- bigqmt_signal_trader/formula_server.py +718 -0
- bigqmt_signal_trader/full_tick_cache.py +219 -0
- bigqmt_signal_trader/local_cache.py +202 -0
- bigqmt_signal_trader/logging_setup.py +171 -0
- bigqmt_signal_trader/models.py +304 -0
- bigqmt_signal_trader/price_engine.py +53 -0
- bigqmt_signal_trader/quote_push_channel.py +270 -0
- bigqmt_signal_trader/quote_subscription_manager.py +258 -0
- bigqmt_signal_trader/redis_rpc.py +1540 -0
- bigqmt_signal_trader/risk_guard.py +45 -0
- bigqmt_signal_trader/runner.py +71 -0
- bigqmt_signal_trader/runtime_bigqmt.py +19 -0
- bigqmt_signal_trader/transports/__init__.py +16 -0
- bigqmt_signal_trader/transports/base.py +121 -0
- bigqmt_signal_trader/transports/factory.py +126 -0
- bigqmt_signal_trader/transports/mysql_transport.py +462 -0
- bigqmt_signal_trader/transports/redis_transport.py +424 -0
- bigqmt_signal_trader/transports/shm_transport.py +34 -0
- bigqmt_signal_trader/transports/zmq_transport.py +459 -0
- bigqmt_signal_trader/whole_quote_session.py +204 -0
- bigqmt_signal_trader/xtquant_compat.py +2461 -0
- bigqmt_signal_trader_diagnostic.py +131 -0
- bigqmt_signal_trader_dryrun.py +28 -0
- bigqmt_signal_trader_redis_dryrun.py +63 -0
- bigqmt_signal_trader_redis_rpc_runtime.py +301 -0
- bigqmt_signal_trader_strategy.py +936 -0
- xtquant/__init__.py +9 -0
- xtquant/xtconstant.py +128 -0
- xtquant/xtdata.py +165 -0
- xtquant/xttrader.py +7 -0
- xtquant/xttype.py +3 -0
- xtquant_big_convert-0.2.0.dist-info/METADATA +994 -0
- xtquant_big_convert-0.2.0.dist-info/RECORD +67 -0
- xtquant_big_convert-0.2.0.dist-info/WHEEL +5 -0
- xtquant_big_convert-0.2.0.dist-info/licenses/LICENSE +21 -0
- xtquant_big_convert-0.2.0.dist-info/top_level.txt +10 -0
BIGQMT_REDIS_DRYRUN.py
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#coding:gbk
|
|
2
|
+
"""QMT bridge entry using the same file-loader pattern as qmt_realtime strategies.
|
|
3
|
+
|
|
4
|
+
Broker QMT strategy sandboxes may reject local package names through their
|
|
5
|
+
normal ``import`` allowlist. The realtime QMT strategies in gupiao_ztfx load
|
|
6
|
+
their colocated helpers through ``importlib.util.spec_from_file_location``.
|
|
7
|
+
This entry applies path-based loading to the bridge package, including its
|
|
8
|
+
internal relative imports, while leaving all standard-library and QMT imports
|
|
9
|
+
untouched. This terminal's spec loader ignores custom builtins for nested
|
|
10
|
+
package imports, so local bridge files are compiled explicitly after resolving
|
|
11
|
+
their path.
|
|
12
|
+
"""
|
|
13
|
+
import builtins as _builtins
|
|
14
|
+
import importlib as _importlib
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import types
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_LOCAL_ROOTS = (
|
|
21
|
+
"bigqmt_signal_trader",
|
|
22
|
+
"bigqmt_signal_trader_strategy",
|
|
23
|
+
"bigqmt_signal_trader_redis_rpc_runtime",
|
|
24
|
+
"bigqmt_signal_trader_local_config",
|
|
25
|
+
)
|
|
26
|
+
_ORIGINAL_IMPORT = _builtins.__import__
|
|
27
|
+
_ORIGINAL_IMPORT_MODULE = _importlib.import_module
|
|
28
|
+
_ORIGINAL_RELOAD = _importlib.reload
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _known_qmt_python_dir():
|
|
32
|
+
# Find the QMT python dir from sys.path instead of a hardcoded path, so
|
|
33
|
+
# the bridge loads regardless of broker install location or launch mode
|
|
34
|
+
# (editor / paste-run / exec). Falls back to empty when not found.
|
|
35
|
+
for p in sys.path:
|
|
36
|
+
if p and r"\python" in p and os.path.isdir(p):
|
|
37
|
+
return p
|
|
38
|
+
return ""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
_SOURCE_ROOT = os.path.dirname(os.path.abspath(__file__))
|
|
43
|
+
except Exception:
|
|
44
|
+
_SOURCE_ROOT = _known_qmt_python_dir()
|
|
45
|
+
if not _SOURCE_ROOT:
|
|
46
|
+
_SOURCE_ROOT = _known_qmt_python_dir()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _is_local_module(name):
|
|
50
|
+
return any(name == root or name.startswith(root + ".") for root in _LOCAL_ROOTS)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _resolve_name(name, module_globals, level):
|
|
54
|
+
if not level:
|
|
55
|
+
return name
|
|
56
|
+
package = (module_globals or {}).get("__package__") or (module_globals or {}).get("__name__", "")
|
|
57
|
+
if not package:
|
|
58
|
+
raise ImportError("relative import without package")
|
|
59
|
+
for unused in range(level - 1):
|
|
60
|
+
if "." not in package:
|
|
61
|
+
raise ImportError("relative import beyond top-level package")
|
|
62
|
+
package = package.rsplit(".", 1)[0]
|
|
63
|
+
return package + ("." + name if name else "")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _find_local_source(name):
|
|
67
|
+
relative = name.replace(".", os.sep)
|
|
68
|
+
dirs = []
|
|
69
|
+
if _SOURCE_ROOT:
|
|
70
|
+
dirs.append(_SOURCE_ROOT)
|
|
71
|
+
for p in sys.path:
|
|
72
|
+
if p and os.path.isdir(p) and p not in dirs:
|
|
73
|
+
dirs.append(p)
|
|
74
|
+
for d in dirs:
|
|
75
|
+
package_init = os.path.join(d, relative, "__init__.py")
|
|
76
|
+
if os.path.isfile(package_init):
|
|
77
|
+
return package_init, True
|
|
78
|
+
module_file = os.path.join(d, relative + ".py")
|
|
79
|
+
if os.path.isfile(module_file):
|
|
80
|
+
return module_file, False
|
|
81
|
+
raise ModuleNotFoundError("local source not found: %s" % name, name=name)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _set_parent_attribute(name, module):
|
|
85
|
+
if "." not in name:
|
|
86
|
+
return
|
|
87
|
+
parent_name, child_name = name.rsplit(".", 1)
|
|
88
|
+
parent = _load_local_module(parent_name)
|
|
89
|
+
setattr(parent, child_name, module)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _load_local_module(name):
|
|
93
|
+
existing = sys.modules.get(name)
|
|
94
|
+
if existing is not None:
|
|
95
|
+
return existing
|
|
96
|
+
source_path, is_package = _find_local_source(name)
|
|
97
|
+
if "." in name:
|
|
98
|
+
_load_local_module(name.rsplit(".", 1)[0])
|
|
99
|
+
module = types.ModuleType(name)
|
|
100
|
+
module.__file__ = source_path
|
|
101
|
+
module.__package__ = name if is_package else name.rpartition(".")[0]
|
|
102
|
+
if is_package:
|
|
103
|
+
module.__path__ = [os.path.dirname(source_path)]
|
|
104
|
+
module_builtins = dict(_builtins.__dict__)
|
|
105
|
+
module_builtins["__import__"] = _local_import
|
|
106
|
+
module.__dict__["__builtins__"] = module_builtins
|
|
107
|
+
module.__dict__["__bigqmt_load_local_module"] = _load_local_module
|
|
108
|
+
sys.modules[name] = module
|
|
109
|
+
# QMT native allowlist rejects the root package eager exports.
|
|
110
|
+
if name == "bigqmt_signal_trader":
|
|
111
|
+
return module
|
|
112
|
+
try:
|
|
113
|
+
with open(source_path, "rb") as source_file:
|
|
114
|
+
source = source_file.read()
|
|
115
|
+
exec(compile(source, source_path, "exec"), module.__dict__)
|
|
116
|
+
except Exception:
|
|
117
|
+
sys.modules.pop(name, None)
|
|
118
|
+
raise
|
|
119
|
+
_set_parent_attribute(name, module)
|
|
120
|
+
return module
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _local_import(name, module_globals=None, module_locals=None, fromlist=(), level=0):
|
|
124
|
+
absolute_name = _resolve_name(name, module_globals, level)
|
|
125
|
+
if not _is_local_module(absolute_name):
|
|
126
|
+
return _ORIGINAL_IMPORT(name, module_globals, module_locals, fromlist, level)
|
|
127
|
+
module = _load_local_module(absolute_name)
|
|
128
|
+
for child in fromlist or ():
|
|
129
|
+
if child != "*":
|
|
130
|
+
try:
|
|
131
|
+
_load_local_module(absolute_name + "." + child)
|
|
132
|
+
except ModuleNotFoundError:
|
|
133
|
+
pass
|
|
134
|
+
if fromlist:
|
|
135
|
+
return module
|
|
136
|
+
return _load_local_module(absolute_name.split(".", 1)[0])
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _local_import_module(name, package=None):
|
|
140
|
+
if _is_local_module(name):
|
|
141
|
+
return _load_local_module(name)
|
|
142
|
+
return _ORIGINAL_IMPORT_MODULE(name, package)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _local_reload(module):
|
|
146
|
+
if _is_local_module(getattr(module, "__name__", "")):
|
|
147
|
+
return _load_local_module(module.__name__)
|
|
148
|
+
return _ORIGINAL_RELOAD(module)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _clear_local_modules():
|
|
152
|
+
for name in list(sys.modules):
|
|
153
|
+
if _is_local_module(name):
|
|
154
|
+
sys.modules.pop(name, None)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _stop_previous_rpc_service():
|
|
158
|
+
"""Release the previous QMT strategy's socket before clearing its module.
|
|
159
|
+
|
|
160
|
+
QMT can re-execute this entry in the same Python process. The old strategy
|
|
161
|
+
module owns the RPC service and its ZMQ ROUTER socket, so dropping that
|
|
162
|
+
module from ``sys.modules`` first would make the service unreachable and
|
|
163
|
+
leave its port bound for the next strategy start.
|
|
164
|
+
"""
|
|
165
|
+
previous = sys.modules.get("bigqmt_signal_trader_strategy")
|
|
166
|
+
reset = getattr(previous, "reset_app", None)
|
|
167
|
+
if not callable(reset):
|
|
168
|
+
return
|
|
169
|
+
try:
|
|
170
|
+
reset()
|
|
171
|
+
print("[bigqmt_shell] previous rpc service stopped")
|
|
172
|
+
except Exception as exc:
|
|
173
|
+
# Continue the reload so a broken old instance does not prevent QMT
|
|
174
|
+
# from reporting its normal startup error.
|
|
175
|
+
print("[bigqmt_shell] previous rpc service stop failed: %s" % exc)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
_stop_previous_rpc_service()
|
|
179
|
+
_clear_local_modules()
|
|
180
|
+
_importlib.import_module = _local_import_module
|
|
181
|
+
_importlib.reload = _local_reload
|
|
182
|
+
print("[bigqmt_shell] importlib entry source_root=%s" % _SOURCE_ROOT)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _fallback_account_id():
|
|
186
|
+
for name in ("BIGQMT_ACCOUNT_ID", "account", "account_id", "accountID"):
|
|
187
|
+
value = globals().get(name)
|
|
188
|
+
if value:
|
|
189
|
+
return str(value)
|
|
190
|
+
return ""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
_local_import("bigqmt_signal_trader.adapters.redis_common", globals(), fromlist=("*",))
|
|
195
|
+
_local_import("bigqmt_signal_trader.redis_rpc", globals(), fromlist=("*",))
|
|
196
|
+
_strategy = _local_import("bigqmt_signal_trader_strategy", globals(), fromlist=("*",))
|
|
197
|
+
_strategy.reset_app()
|
|
198
|
+
except Exception as bridge_preload_error:
|
|
199
|
+
print("[bigqmt_shell] bridge preload failed: %s" % bridge_preload_error)
|
|
200
|
+
|
|
201
|
+
_runtime = _local_import("bigqmt_signal_trader_redis_rpc_runtime", globals(), fromlist=("*",))
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _load_local_config():
|
|
205
|
+
return _local_import("bigqmt_signal_trader_local_config", globals(), fromlist=("*",))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
_config = _load_local_config()
|
|
210
|
+
BIGQMT_REDIS_CONFIG = getattr(_config, "BIGQMT_REDIS_CONFIG", {})
|
|
211
|
+
print("[bigqmt_shell] local redis config loaded keys=%s" % sorted((BIGQMT_REDIS_CONFIG or {}).keys()))
|
|
212
|
+
_runtime.configure_runtime_redis(BIGQMT_REDIS_CONFIG)
|
|
213
|
+
except Exception as redis_config_error:
|
|
214
|
+
print("[bigqmt_shell] local redis config load failed: %s" % redis_config_error)
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
_config = _load_local_config()
|
|
218
|
+
BIGQMT_ACCOUNT_ID = getattr(_config, "BIGQMT_ACCOUNT_ID", "")
|
|
219
|
+
print("[bigqmt_shell] local account config loaded=%s" % bool(BIGQMT_ACCOUNT_ID))
|
|
220
|
+
_runtime.configure_runtime_account(BIGQMT_ACCOUNT_ID)
|
|
221
|
+
except Exception as account_config_error:
|
|
222
|
+
print("[bigqmt_shell] local account config load failed: %s" % account_config_error)
|
|
223
|
+
account_id = _fallback_account_id()
|
|
224
|
+
if account_id:
|
|
225
|
+
_runtime.configure_runtime_account(account_id)
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
qmt_extra = {}
|
|
229
|
+
for function_name in (
|
|
230
|
+
"get_history_trade_detail_data", "get_value_by_order_id", "get_last_order_id",
|
|
231
|
+
"get_ipo_data", "get_new_purchase_limit", "get_assure_contract",
|
|
232
|
+
"get_enable_short_contract", "get_unclosed_compacts", "get_closed_compacts",
|
|
233
|
+
"get_debt_contract", "get_option_subject_position", "get_comb_option",
|
|
234
|
+
"get_hkt_exchange_rate",
|
|
235
|
+
"download_history_data", "download_history_data2",
|
|
236
|
+
):
|
|
237
|
+
if function_name in globals():
|
|
238
|
+
qmt_extra[function_name] = globals()[function_name]
|
|
239
|
+
print("[bigqmt_shell] down_history_data bound=%s" % ("down_history_data" in qmt_extra))
|
|
240
|
+
_runtime.bind_runtime_api(
|
|
241
|
+
passorder_func=globals().get("passorder"),
|
|
242
|
+
cancel_func=globals().get("cancel"),
|
|
243
|
+
get_trade_detail_data_func=globals().get("get_trade_detail_data"),
|
|
244
|
+
extra_funcs=qmt_extra or None,
|
|
245
|
+
)
|
|
246
|
+
except NameError:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
init = _runtime.init
|
|
251
|
+
handlebar = _runtime.handlebar
|
|
252
|
+
adjust = _runtime.adjust
|
|
253
|
+
order_callback = _runtime.order_callback
|
|
254
|
+
deal_callback = _runtime.deal_callback
|
BIGQMT_ZMQ_BACKTEST.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#coding:gbk
|
|
2
|
+
"""Isolated QMT backtest entry for external ZMQ strategies.
|
|
3
|
+
|
|
4
|
+
This file is ASCII-only. It loads only the bigqmt_backtest package and never
|
|
5
|
+
loads or mutates the live bridge package.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import builtins as _builtins
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
import types
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
BACKTEST_ZMQ_CONFIG = {
|
|
15
|
+
"bind_endpoint": "tcp://127.0.0.1:16662",
|
|
16
|
+
"run_id": "",
|
|
17
|
+
"account_id": "",
|
|
18
|
+
"account_type": "STOCK",
|
|
19
|
+
"strategy_name": "ZMQ_BACKTEST",
|
|
20
|
+
"combo_type": 1101,
|
|
21
|
+
"quick_trade": 2,
|
|
22
|
+
"market_price_type": 5,
|
|
23
|
+
"limit_price_type": 11,
|
|
24
|
+
"bar_wait_timeout_seconds": 60,
|
|
25
|
+
"require_qmt_backtest": True,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
_LOCAL_ROOT = "bigqmt_backtest"
|
|
30
|
+
_ORIGINAL_IMPORT = _builtins.__import__
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _known_qmt_python_dir():
|
|
34
|
+
for p in sys.path:
|
|
35
|
+
if p and r"\python" in p and os.path.isdir(p):
|
|
36
|
+
return p
|
|
37
|
+
return ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
_SOURCE_ROOT = os.path.dirname(os.path.abspath(__file__))
|
|
42
|
+
except Exception:
|
|
43
|
+
_SOURCE_ROOT = _known_qmt_python_dir()
|
|
44
|
+
if not _SOURCE_ROOT:
|
|
45
|
+
_SOURCE_ROOT = _known_qmt_python_dir()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _is_local(name):
|
|
49
|
+
return name == _LOCAL_ROOT or name.startswith(_LOCAL_ROOT + ".")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _resolve_name(name, module_globals, level):
|
|
53
|
+
if not level:
|
|
54
|
+
return name
|
|
55
|
+
package = (module_globals or {}).get("__package__") or ""
|
|
56
|
+
if not package:
|
|
57
|
+
raise ImportError("relative import without package")
|
|
58
|
+
for unused in range(level - 1):
|
|
59
|
+
package = package.rsplit(".", 1)[0]
|
|
60
|
+
return package + (("." + name) if name else "")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _find_source(name):
|
|
64
|
+
relative = name.replace(".", os.sep)
|
|
65
|
+
dirs = []
|
|
66
|
+
if _SOURCE_ROOT:
|
|
67
|
+
dirs.append(_SOURCE_ROOT)
|
|
68
|
+
for p in sys.path:
|
|
69
|
+
if p and os.path.isdir(p) and p not in dirs:
|
|
70
|
+
dirs.append(p)
|
|
71
|
+
for d in dirs:
|
|
72
|
+
package_init = os.path.join(d, relative, "__init__.py")
|
|
73
|
+
if os.path.isfile(package_init):
|
|
74
|
+
return package_init, True
|
|
75
|
+
module_file = os.path.join(d, relative + ".py")
|
|
76
|
+
if os.path.isfile(module_file):
|
|
77
|
+
return module_file, False
|
|
78
|
+
raise ModuleNotFoundError("local source not found: %s" % name, name=name)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _load_local_module(name):
|
|
82
|
+
existing = sys.modules.get(name)
|
|
83
|
+
if existing is not None:
|
|
84
|
+
return existing
|
|
85
|
+
source_path, is_package = _find_source(name)
|
|
86
|
+
if "." in name:
|
|
87
|
+
_load_local_module(name.rsplit(".", 1)[0])
|
|
88
|
+
module = types.ModuleType(name)
|
|
89
|
+
module.__file__ = source_path
|
|
90
|
+
module.__package__ = name if is_package else name.rpartition(".")[0]
|
|
91
|
+
if is_package:
|
|
92
|
+
module.__path__ = [os.path.dirname(source_path)]
|
|
93
|
+
module_builtins = dict(_builtins.__dict__)
|
|
94
|
+
module_builtins["__import__"] = _local_import
|
|
95
|
+
module.__dict__["__builtins__"] = module_builtins
|
|
96
|
+
sys.modules[name] = module
|
|
97
|
+
if name == _LOCAL_ROOT:
|
|
98
|
+
return module
|
|
99
|
+
try:
|
|
100
|
+
with open(source_path, "rb") as source_file:
|
|
101
|
+
source = source_file.read()
|
|
102
|
+
exec(compile(source, source_path, "exec"), module.__dict__)
|
|
103
|
+
except Exception:
|
|
104
|
+
sys.modules.pop(name, None)
|
|
105
|
+
raise
|
|
106
|
+
if "." in name:
|
|
107
|
+
parent_name, child_name = name.rsplit(".", 1)
|
|
108
|
+
setattr(_load_local_module(parent_name), child_name, module)
|
|
109
|
+
return module
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _local_import(name, module_globals=None, module_locals=None, fromlist=(), level=0):
|
|
113
|
+
absolute_name = _resolve_name(name, module_globals, level)
|
|
114
|
+
if not _is_local(absolute_name):
|
|
115
|
+
return _ORIGINAL_IMPORT(name, module_globals, module_locals, fromlist, level)
|
|
116
|
+
module = _load_local_module(absolute_name)
|
|
117
|
+
for child in fromlist or ():
|
|
118
|
+
if child != "*":
|
|
119
|
+
try:
|
|
120
|
+
_load_local_module(absolute_name + "." + child)
|
|
121
|
+
except ModuleNotFoundError:
|
|
122
|
+
pass
|
|
123
|
+
if fromlist:
|
|
124
|
+
return module
|
|
125
|
+
return _load_local_module(absolute_name.split(".", 1)[0])
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
for _name in sorted(
|
|
129
|
+
[name for name in list(sys.modules) if _is_local(name)],
|
|
130
|
+
key=lambda item: item.count("."),
|
|
131
|
+
reverse=True,
|
|
132
|
+
):
|
|
133
|
+
sys.modules.pop(_name, None)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
_runtime = _load_local_module("bigqmt_backtest.qmt_runtime")
|
|
137
|
+
_runtime.configure(**BACKTEST_ZMQ_CONFIG)
|
|
138
|
+
_runtime.bind_qmt_api(
|
|
139
|
+
passorder_func=globals().get("passorder") or getattr(_builtins, "passorder", None),
|
|
140
|
+
cancel_func=globals().get("cancel") or getattr(_builtins, "cancel", None),
|
|
141
|
+
get_trade_detail_data_func=(
|
|
142
|
+
globals().get("get_trade_detail_data")
|
|
143
|
+
or getattr(_builtins, "get_trade_detail_data", None)
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
init = _runtime.init
|
|
148
|
+
handlebar = _runtime.handlebar
|
|
149
|
+
order_callback = _runtime.order_callback
|
|
150
|
+
deal_callback = _runtime.deal_callback
|
|
151
|
+
stop = _runtime.stop
|
|
152
|
+
after_backtest = _runtime.after_backtest
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Isolated ZMQ bridge for QMT-native and standalone backtests.
|
|
2
|
+
|
|
3
|
+
This package deliberately does not import ``bigqmt_signal_trader``. The live
|
|
4
|
+
bridge and both backtest backends therefore have separate module state,
|
|
5
|
+
identities, and order gateways. QMT-native mode never uses the local broker.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .client import BacktestZmqClient
|
|
9
|
+
from .data_feed import CsvBarFeed, InMemoryBarFeed
|
|
10
|
+
from .engine import BacktestConfig, BacktestEngine
|
|
11
|
+
from .protocol import BacktestBridgeProtocol
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BacktestBridgeProtocol",
|
|
16
|
+
"BacktestConfig",
|
|
17
|
+
"BacktestEngine",
|
|
18
|
+
"BacktestZmqClient",
|
|
19
|
+
"CsvBarFeed",
|
|
20
|
+
"InMemoryBarFeed",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
__version__ = "1.0.0"
|