Files
sanguo_vnpy_v2/scripts/qmt_relogin/patch_shim_xtdata_20260911.py
T

62 lines
2.3 KiB
Python

# -*- coding: utf-8 -*-
"""B-pack client-side fix 2026-09-11: shim get_trading_dates output normalization.
The server-side fix (market_bigqmt.py patch) normalizes the RPC answer, but
fresh client processes (xt_eod wrapper, future engines) load THIS shim first.
Defense in depth: normalize here too, so the contract holds even if the server
side regresses (e.g. server file restored from a backup).
Idempotent: re-running on a patched file exits 0.
Run ON THE VPS: C:\\Python310\\python.exe -X utf8 patch_shim_xtdata_20260911.py
"""
import io
import shutil
import sys
P = r"C:\sanguo_bigqmt\xtquant_bridge\xtquant\xtdata.py"
BAK = P + ".bak_20260911"
OLD = '''def get_trading_dates(market, start_time="", end_time="", count=-1):
return _compat.xtdata.get_trading_dates(market, start_time, end_time, count)'''
NEW = '''def _norm_calendar_ms(result):
"""Contract fix 2026-09-11: 'YYYYMMDD' strings -> Beijing-midnight epoch ms.
The bridge server's native xtdata path returns string dates whenever a
local quote source has been reachable (2026-09-11 incident: all 12 engine
schedulers starved on ts/1000 TypeErrors). Consumers divide by 1000 with
local-timezone fromtimestamp, and this host runs Asia/Shanghai, so
datetime().timestamp() is the exact inverse. All-numeric lists pass
through untouched."""
if not isinstance(result, list) or not result:
return result
if all(isinstance(x, (int, float)) and not isinstance(x, bool) for x in result):
return result
out = []
for x in result:
if isinstance(x, str) and len(x) == 8 and x.isdigit():
import datetime as _dt
out.append(int(_dt.datetime(int(x[:4]), int(x[4:6]), int(x[6:8])).timestamp() * 1000))
else:
out.append(x)
return out
def get_trading_dates(market, start_time="", end_time="", count=-1):
return _norm_calendar_ms(_compat.xtdata.get_trading_dates(market, start_time, end_time, count))'''
src = io.open(P, encoding="utf-8").read()
if "_norm_calendar_ms(_compat.xtdata.get_trading_dates" in src:
print("ALREADY_PATCHED")
sys.exit(0)
if src.count(OLD) != 1:
print("ANCHOR_NOT_UNIQUE: %d" % src.count(OLD))
sys.exit(1)
shutil.copyfile(P, BAK)
src = src.replace(OLD, NEW)
io.open(P, "w", encoding="utf-8", newline="\n").write(src)
print("PATCHED ok, backup=%s" % BAK)