cfquant 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.
Files changed (90) hide show
  1. LTtx/__init__.py +2 -0
  2. LTtx/tx/Config.txt +8 -0
  3. LTtx/tx/LTtx_server.py +1177 -0
  4. LTtx/tx/__init__.py +5 -0
  5. LTtx/tx/tx.py +1935 -0
  6. cfquant/__init__.py +26 -0
  7. cfquant/account_routing.py +119 -0
  8. cfquant/channels.py +76 -0
  9. cfquant/cli.py +266 -0
  10. cfquant/client.py +365 -0
  11. cfquant/config.py +86 -0
  12. cfquant/hub.py +304 -0
  13. cfquant/logging_i18n.py +348 -0
  14. cfquant/normal_bridge.py +676 -0
  15. cfquant/pipe_bridge.py +249 -0
  16. cfquant/pipe_client.py +223 -0
  17. cfquant/pipe_hub.py +602 -0
  18. cfquant/pipe_transport.py +493 -0
  19. cfquant/protocol.py +238 -0
  20. cfquant/qmt_bridge.py +1081 -0
  21. cfquant/runtime_report.py +334 -0
  22. cfquant/tx.py +1898 -0
  23. cfquant/tx_trade_bridge.py +1905 -0
  24. cfquant/version.py +5 -0
  25. cfquant/xtconstant.py +262 -0
  26. cfquant/xtdata.py +462 -0
  27. cfquant/xttrader.py +955 -0
  28. cfquant/xttype.py +586 -0
  29. cfquant-0.2.0.dist-info/LICENSE +21 -0
  30. cfquant-0.2.0.dist-info/METADATA +144 -0
  31. cfquant-0.2.0.dist-info/RECORD +90 -0
  32. cfquant-0.2.0.dist-info/WHEEL +5 -0
  33. cfquant-0.2.0.dist-info/entry_points.txt +4 -0
  34. cfquant-0.2.0.dist-info/top_level.txt +6 -0
  35. cfquant_pipe_hub.py +45 -0
  36. cfquant_web_server.py +12137 -0
  37. qmt_scripts/CFQUANT.py +507 -0
  38. qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +830 -0
  39. qmt_scripts/CFQUANT_LITE.py +4928 -0
  40. qmt_scripts/CFQUANT_TRADE_LOWLAT.py +382 -0
  41. qmt_scripts/__init__.py +1 -0
  42. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_CTYPE_ALL_LOWLAT_SH.py +866 -0
  43. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_CTYPE_ALL_LOWLAT_SZ.py +866 -0
  44. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_LITE_SH.py +5020 -0
  45. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_LITE_SZ.py +5020 -0
  46. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_TRADE_LOWLAT_SH.py +436 -0
  47. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/CFQUANT_TRADE_LOWLAT_SZ.py +436 -0
  48. qmt_scripts//321/205/320/240/320/234/321/210/342/224/244/320/266/321/205/320/237/342/225/226/321/207/320/233/320/274/321/207/320/273/320/233/321/205/342/225/225/320/222/321/205/320/254/342/225/221/readme.md +95 -0
  49. web_dashboard/__init__.py +1 -0
  50. web_dashboard/app.js +9847 -0
  51. web_dashboard/avatars/amber-pulse.svg +15 -0
  52. web_dashboard/avatars/copper-grid.svg +15 -0
  53. web_dashboard/avatars/market-blue.svg +15 -0
  54. web_dashboard/avatars/rose-circuit.svg +15 -0
  55. web_dashboard/avatars/signal-green.svg +15 -0
  56. web_dashboard/avatars/slate-wave.svg +15 -0
  57. web_dashboard/avatars/teal-orbit.svg +16 -0
  58. web_dashboard/avatars/violet-node.svg +15 -0
  59. web_dashboard/favicon.svg +5 -0
  60. web_dashboard/image/qmt_deploy/image-10.png +0 -0
  61. web_dashboard/image/qmt_deploy/image-11.png +0 -0
  62. web_dashboard/image/qmt_deploy/image-12.png +0 -0
  63. web_dashboard/image/qmt_deploy/image-13.png +0 -0
  64. web_dashboard/image/qmt_deploy/image-14.png +0 -0
  65. web_dashboard/image/qmt_deploy/image-15.png +0 -0
  66. web_dashboard/image/qmt_deploy/image-16.png +0 -0
  67. web_dashboard/image/qmt_deploy/image-17.png +0 -0
  68. web_dashboard/image/qmt_deploy/image-18.png +0 -0
  69. web_dashboard/image/qmt_deploy/image-19.png +0 -0
  70. web_dashboard/image/qmt_deploy/image-20.png +0 -0
  71. web_dashboard/image/qmt_deploy/image-21.png +0 -0
  72. web_dashboard/image/qmt_deploy/image-4.png +0 -0
  73. web_dashboard/image/qmt_deploy/image-5.png +0 -0
  74. web_dashboard/image/qmt_deploy/image-6.png +0 -0
  75. web_dashboard/image/qmt_deploy/image-7.png +0 -0
  76. web_dashboard/image/qmt_deploy/image-8.png +0 -0
  77. web_dashboard/image/qmt_deploy/image-9.png +0 -0
  78. web_dashboard/image//321/211/320/220/320/252/321/207/320/244/320/270/321/206/320/270/320/261/321/205/342/225/235/320/237/321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/image-1.png +0 -0
  79. web_dashboard/image//321/211/320/220/320/252/321/207/320/244/320/270/321/206/320/270/320/261/321/205/342/225/235/320/237/321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/image-2.png +0 -0
  80. web_dashboard/image//321/211/320/220/320/252/321/207/320/244/320/270/321/206/320/270/320/261/321/205/342/225/235/320/237/321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/image-3.png +0 -0
  81. web_dashboard/image//321/211/320/220/320/252/321/207/320/244/320/270/321/206/320/270/320/261/321/205/342/225/235/320/237/321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/image.png +0 -0
  82. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783479325179.png +0 -0
  83. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783479745262.png +0 -0
  84. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783480178700.png +0 -0
  85. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783480428759.png +0 -0
  86. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783489807217.png +0 -0
  87. web_dashboard/image//321/211/320/223/320/270/321/207/342/225/234/342/226/223/321/206/320/234/320/227/321/205/320/235/320/247/1783490503491.png +0 -0
  88. web_dashboard/index.html +2317 -0
  89. web_dashboard/styles.css +7817 -0
  90. web_dashboard/vendor/mermaid.min.js +2029 -0
@@ -0,0 +1,334 @@
1
+ # -*- coding: utf-8 -*-
2
+ """QMT runtime version marker helpers.
3
+
4
+ The marker file is intentionally independent from LTtx and pipe RPC so the web
5
+ process can identify the running QMT script version even while request channels
6
+ are blocked or still warming up.
7
+ """
8
+
9
+ import glob
10
+ import json
11
+ import os
12
+ import sys
13
+ import tempfile
14
+ import time
15
+
16
+
17
+ RUNTIME_SCHEMA = "cfquant.qmt.runtime"
18
+ MARKER_FILENAME_PREFIX = "cfquant_qmt_runtime"
19
+
20
+
21
+ def _now_text(ts=None):
22
+ ts = float(ts if ts is not None else time.time())
23
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))
24
+
25
+
26
+ def _text(value):
27
+ if value is None:
28
+ return ""
29
+ try:
30
+ return str(value).strip()
31
+ except Exception:
32
+ return ""
33
+
34
+
35
+ def _path(value):
36
+ value = _text(value)
37
+ if not value:
38
+ return ""
39
+ try:
40
+ return os.path.abspath(os.path.expandvars(os.path.expanduser(value)))
41
+ except Exception:
42
+ return value
43
+
44
+
45
+ def _safe_name(value, default="runtime"):
46
+ value = _text(value) or default
47
+ out = []
48
+ for ch in value:
49
+ if ch.isalnum() or ch in ("-", "_", "."):
50
+ out.append(ch)
51
+ else:
52
+ out.append("_")
53
+ name = "".join(out).strip("._")
54
+ return name or default
55
+
56
+
57
+ def _append_unique(paths, path):
58
+ path = _path(path)
59
+ if not path:
60
+ return
61
+ try:
62
+ key = os.path.normcase(os.path.abspath(path))
63
+ except Exception:
64
+ key = path.lower()
65
+ for item in paths:
66
+ try:
67
+ item_key = os.path.normcase(os.path.abspath(item))
68
+ except Exception:
69
+ item_key = item.lower()
70
+ if item_key == key:
71
+ return
72
+ paths.append(path)
73
+
74
+
75
+ def configured_marker_dirs(config=None, entry_base_dir=None):
76
+ config = config if isinstance(config, dict) else {}
77
+ paths = []
78
+
79
+ for key in ("qmt_runtime_marker_dir", "runtime_marker_dir"):
80
+ _append_unique(paths, config.get(key))
81
+ for key in ("runtime_status_dir", "web_runtime_status_dir"):
82
+ base = _path(config.get(key))
83
+ if base:
84
+ _append_unique(paths, os.path.join(base, "qmt_runtime"))
85
+ for key in ("runtime_dir", "web_runtime_dir"):
86
+ base = _path(config.get(key))
87
+ if base:
88
+ _append_unique(paths, os.path.join(base, "status", "qmt_runtime"))
89
+
90
+ for name in ("CFQUANT_QMT_RUNTIME_MARKER_DIR", "CFQUANT_RUNTIME_MARKER_DIR"):
91
+ _append_unique(paths, os.environ.get(name))
92
+ for name in ("CFQUANT_RUNTIME_STATUS_DIR", "CFQUANT_WEB_RUNTIME_STATUS_DIR"):
93
+ base = _path(os.environ.get(name))
94
+ if base:
95
+ _append_unique(paths, os.path.join(base, "qmt_runtime"))
96
+ for name in ("CFQUANT_RUNTIME_DIR", "CFQUANT_WEB_RUNTIME_DIR"):
97
+ base = _path(os.environ.get(name))
98
+ if base:
99
+ _append_unique(paths, os.path.join(base, "status", "qmt_runtime"))
100
+
101
+ base_dir = _path(entry_base_dir)
102
+ if not base_dir:
103
+ entry_file = _path(config.get("entry_file"))
104
+ if entry_file:
105
+ base_dir = os.path.dirname(entry_file)
106
+ if base_dir:
107
+ parent_dir = os.path.dirname(base_dir)
108
+ _append_unique(paths, os.path.join(base_dir, "runtime", "status", "qmt_runtime"))
109
+ if parent_dir and parent_dir != base_dir:
110
+ _append_unique(paths, os.path.join(parent_dir, "runtime", "status", "qmt_runtime"))
111
+ if os.path.basename(base_dir).lower() == "python":
112
+ _append_unique(paths, os.path.join(parent_dir, "bin.x64", "runtime", "status", "qmt_runtime"))
113
+
114
+ if not paths:
115
+ _append_unique(paths, os.path.join(tempfile.gettempdir(), "cfquant", "runtime", "status", "qmt_runtime"))
116
+ return paths
117
+
118
+
119
+ def build_qmt_runtime_report(
120
+ reason="startup",
121
+ version="",
122
+ core_version="",
123
+ entry_version="",
124
+ entry_script="",
125
+ entry_file="",
126
+ bridge="",
127
+ bridge_id="default",
128
+ account_id="",
129
+ account_type="",
130
+ account_key="",
131
+ mode="",
132
+ transport="",
133
+ runtime_mode="",
134
+ channel_key="runtime",
135
+ request_channel="",
136
+ callback_event_channel="",
137
+ channels=None,
138
+ pipe_name="",
139
+ market="",
140
+ market_role="",
141
+ market_route_parent_bridge_id="",
142
+ config=None,
143
+ globals_dict=None,
144
+ module_file="",
145
+ started_at=None,
146
+ extra=None,
147
+ ):
148
+ config = config if isinstance(config, dict) else {}
149
+ globals_dict = globals_dict if isinstance(globals_dict, dict) else {}
150
+ channels = channels if isinstance(channels, dict) else (config.get("channels") if isinstance(config.get("channels"), dict) else {})
151
+ channel_key = _text(channel_key) or "runtime"
152
+ request_channel = _text(request_channel) or _text(channels.get(channel_key))
153
+ entry_file = _path(entry_file or globals_dict.get("__file__") or config.get("entry_file"))
154
+ entry_script = _text(entry_script or config.get("entry_script"))
155
+ if not entry_script and entry_file:
156
+ entry_script = os.path.basename(entry_file)
157
+ entry_version = _text(
158
+ entry_version
159
+ or globals_dict.get("_ENTRY_VERSION")
160
+ or globals_dict.get("LITE_ENTRY_VERSION")
161
+ or globals_dict.get("ENTRY_VERSION")
162
+ or config.get("entry_version")
163
+ or config.get("qmt_runtime_entry_version")
164
+ )
165
+ core_version = _text(
166
+ core_version
167
+ or globals_dict.get("CORE_VERSION")
168
+ or globals_dict.get("_CORE_VERSION")
169
+ or version
170
+ or config.get("core_version")
171
+ or config.get("qmt_runtime_core_version")
172
+ )
173
+ version = _text(version or core_version)
174
+ started = started_at
175
+ if started in (None, "", 0):
176
+ started = globals_dict.get("_runtime_started_at") or config.get("started_at") or time.time()
177
+ try:
178
+ started = float(started)
179
+ except Exception:
180
+ started = time.time()
181
+ now = time.time()
182
+ report = {
183
+ "schema": RUNTIME_SCHEMA,
184
+ "report_schema": "cfquant.qmt.runtime_marker.v1",
185
+ "version": version,
186
+ "core_version": core_version or version,
187
+ "entry_version": entry_version,
188
+ "entry_script": entry_script,
189
+ "entry_file": entry_file,
190
+ "bridge": _text(bridge),
191
+ "bridge_id": _text(bridge_id or config.get("bridge_id") or globals_dict.get("BRIDGE_ID") or "default") or "default",
192
+ "account_id": _text(account_id or config.get("account_id") or globals_dict.get("DEFAULT_ACCOUNT_ID")),
193
+ "account_type": _text(account_type or config.get("account_type") or globals_dict.get("DEFAULT_ACCOUNT_TYPE")),
194
+ "account_key": _text(account_key or config.get("account_key")),
195
+ "mode": _text(mode or config.get("mode")),
196
+ "transport": _text(transport),
197
+ "runtime_mode": _text(runtime_mode),
198
+ "channel_key": channel_key,
199
+ "request_channel": request_channel,
200
+ "callback_event_channel": _text(callback_event_channel),
201
+ "channels": dict(channels or {}),
202
+ "pipe_name": _text(pipe_name or config.get("pipe_name")),
203
+ "market": _text(market or config.get("market") or globals_dict.get("QMT_MARKET")),
204
+ "market_role": _text(market_role or config.get("market_role")),
205
+ "market_route_parent_bridge_id": _text(market_route_parent_bridge_id or config.get("market_route_parent_bridge_id")),
206
+ "core_dir": os.path.dirname(os.path.abspath(__file__)),
207
+ "version_file": os.path.join(os.path.dirname(os.path.abspath(__file__)), "version.py"),
208
+ "module_file": _path(module_file or __file__),
209
+ "config_path": _path(globals_dict.get("RUNTIME_CONFIG_PATH") or config.get("config_path") or config.get("path")),
210
+ "python": sys.executable,
211
+ "pid": os.getpid(),
212
+ "cwd": _path(os.getcwd()),
213
+ "started_at": started,
214
+ "started_at_text": _now_text(started),
215
+ "reported_at": now,
216
+ "reported_at_text": _now_text(now),
217
+ "reason": _text(reason or "startup"),
218
+ "source": "qmt_startup_marker",
219
+ }
220
+ if isinstance(extra, dict):
221
+ report.update(extra)
222
+ return report
223
+
224
+
225
+ def marker_filename(report):
226
+ report = report if isinstance(report, dict) else {}
227
+ bridge_id = _safe_name(report.get("bridge_id") or "default", "default")
228
+ channel_key = _safe_name(report.get("channel_key") or "runtime", "runtime")
229
+ entry_script = _safe_name(os.path.splitext(os.path.basename(_text(report.get("entry_script"))))[0], "entry")
230
+ pid = _safe_name(report.get("pid") or os.getpid(), "pid")
231
+ return "%s_%s_%s_%s_%s.json" % (MARKER_FILENAME_PREFIX, bridge_id, channel_key, entry_script, pid)
232
+
233
+
234
+ def write_qmt_runtime_marker(report, marker_dirs=None, config=None, entry_base_dir=None):
235
+ report = dict(report or {})
236
+ dirs = []
237
+ for path in marker_dirs or []:
238
+ _append_unique(dirs, path)
239
+ for path in configured_marker_dirs(config=config, entry_base_dir=entry_base_dir):
240
+ _append_unique(dirs, path)
241
+
242
+ files = []
243
+ errors = []
244
+ name = marker_filename(report)
245
+ for directory in dirs:
246
+ try:
247
+ os.makedirs(directory, exist_ok=True)
248
+ path = os.path.join(directory, name)
249
+ temp_path = "%s.%s.tmp" % (path, os.getpid())
250
+ data = dict(report)
251
+ data["marker_file"] = path
252
+ data["marker_dir"] = directory
253
+ data["marker_written_at"] = time.time()
254
+ data["marker_written_at_text"] = _now_text(data["marker_written_at"])
255
+ with open(temp_path, "w", encoding="utf-8") as f:
256
+ json.dump(data, f, ensure_ascii=False, indent=2, sort_keys=True)
257
+ os.replace(temp_path, path)
258
+ files.append(path)
259
+ except Exception as e:
260
+ errors.append("%s: %s" % (directory, e))
261
+ return {
262
+ "ok": bool(files),
263
+ "files": files,
264
+ "primary_file": files[0] if files else "",
265
+ "errors": errors,
266
+ "report": report,
267
+ }
268
+
269
+
270
+ def publish_qmt_runtime_marker(marker_dirs=None, config=None, entry_base_dir=None, **kwargs):
271
+ report = build_qmt_runtime_report(config=config, **kwargs)
272
+ return write_qmt_runtime_marker(
273
+ report,
274
+ marker_dirs=marker_dirs,
275
+ config=config,
276
+ entry_base_dir=entry_base_dir,
277
+ )
278
+
279
+
280
+ def _read_marker_file(path):
281
+ try:
282
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
283
+ data = json.load(f)
284
+ if not isinstance(data, dict):
285
+ return None
286
+ if data.get("schema") != RUNTIME_SCHEMA and not data.get("core_version"):
287
+ return None
288
+ stat_result = os.stat(path)
289
+ data.setdefault("marker_file", path)
290
+ data.setdefault("marker_dir", os.path.dirname(path))
291
+ data.setdefault("marker_mtime", stat_result.st_mtime)
292
+ data.setdefault("marker_mtime_text", _now_text(stat_result.st_mtime))
293
+ return data
294
+ except Exception:
295
+ return None
296
+
297
+
298
+ def read_qmt_runtime_markers(marker_dirs, max_age_seconds=None, max_files=256):
299
+ if isinstance(marker_dirs, str):
300
+ marker_dirs = [marker_dirs]
301
+ paths = []
302
+ for directory in marker_dirs or []:
303
+ directory = _path(directory)
304
+ if not directory or not os.path.isdir(directory):
305
+ continue
306
+ paths.extend(glob.glob(os.path.join(directory, "%s_*.json" % MARKER_FILENAME_PREFIX)))
307
+ unique = []
308
+ seen = set()
309
+ for path in paths:
310
+ key = os.path.normcase(os.path.abspath(path))
311
+ if key in seen:
312
+ continue
313
+ seen.add(key)
314
+ unique.append(path)
315
+ unique.sort(key=lambda item: os.path.getmtime(item) if os.path.exists(item) else 0, reverse=True)
316
+ if max_files:
317
+ unique = unique[: int(max_files)]
318
+
319
+ now = time.time()
320
+ reports = []
321
+ for path in unique:
322
+ data = _read_marker_file(path)
323
+ if not data or not data.get("core_version"):
324
+ continue
325
+ if max_age_seconds is not None:
326
+ stamp = data.get("reported_at") or data.get("marker_written_at") or data.get("marker_mtime") or 0
327
+ try:
328
+ stamp = float(stamp)
329
+ except Exception:
330
+ stamp = 0.0
331
+ if stamp and now - stamp > float(max_age_seconds):
332
+ continue
333
+ reports.append(data)
334
+ return reports