mirror of
https://ghfast.top/https://github.com/aeroxw/easy_tdx_max.git
synced 2026-09-12 13:24:18 +08:00
通达信服务端 K 线记录第一个 4 字节字段的语义随周期/品种变化,此前原样 透传错误数据(逐字节拆包 + 新浪实时行情/东方财富三方交叉验证锁定): - 指数分钟线(MIN_1/3/5/15/30/60,含 880xxx 板块指数):f1 实为 成交额(百元),与 amount 恒差 100 倍,真实分钟成交量不在报文中 (15:00 上证 5min 真值 13,954,814 手 vs 返回 208,748,512≈amount/100) → vol 置 NaN,不拿成交额冒充成交量; - 指数与个股周/月/季/年线(cat 5/6/10/11):f1 = 真实成交量/100 (上证本周三日日线 vol 合计 1,666,668,288 手 vs 周线 16,666,683) → ×100 还原,与日线单位对齐(指数=手、个股=股); - 日线(cat 4)与 cat 9(日线变体,枚举名误标 YEAR,真年线是 cat 11) 不受影响,cat 9 明确不套 ×100 并由测试锁定。 配套:DataFrameResponse NaN→null(Starlette allow_nan=False 透传会 500); client/路由 docstring 写明各单位;回归测试 7 例(实抓原始字节构造报文); 验收脚本 scripts/verify_issue64.py 连真实服务器复测。附带发现仅记录: 指数分时 vol=成交额(万元)、/bars?category=YEAR 实际返回日线(cat 9)。
70 lines
3.4 KiB
Python
70 lines
3.4 KiB
Python
"""issue #64 验证脚本:指数 K 线 vol 字段语义核查(连真实服务器)。
|
||
|
||
结论(2026-09-02 实测,对照新浪实时行情与东方财富分钟K):
|
||
- 指数分钟线(MIN_1/3/5/15/30/60):协议每条记录的两个 4 字节字段
|
||
f1 ≈ f2/100、f2 = 成交额(元)。f1 是"成交额(百元)"而非成交量,
|
||
真实分钟成交量不在报文中(东财 15:00 5min bar 实测 13,954,814 手,
|
||
而协议 f1 返回 208,748,512 ≈ amount/100)。
|
||
- 指数日线:f1 = 成交量(手),与新浪实时行情一致(差值仅为自定义
|
||
浮点解码噪声 ~1e-7)。日线路径正确。
|
||
- 指数周/月/季/年:f1 = 真实成交量/100(本周三交易日日线 vol 合计
|
||
1,666,668,288 手,周线 f1 = 16,666,683,恰好 ÷100)。
|
||
- 附带发现:股票周/月线 f1 同样 = 真实vol/100(浦发 8/31-9/2 三日
|
||
日线 vol 合计 269,388,528 股,周线 f1×100 = 269,388,500);
|
||
指数分时接口 vol 列 = 成交额(万元)(全日合计 ≈ 日成交额/10000)。
|
||
|
||
用法:python scripts/verify_issue64.py
|
||
"""
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||
|
||
from easy_tdx.client import TdxClient # noqa: E402
|
||
from easy_tdx.models.enums import KlineCategory, Market # noqa: E402
|
||
|
||
|
||
def main() -> None:
|
||
cl = TdxClient()
|
||
cl.connect()
|
||
try:
|
||
print(f"{'调用':<44s} {'vol(返回)':>16s} {'amount(返回)':>18s} amt/vol")
|
||
cases = [
|
||
("SH000001 MIN_5 (指数分钟, issue场景)", Market.SH, "000001", KlineCategory.MIN_5),
|
||
("SH000001 MIN_1 (指数分钟)", Market.SH, "000001", KlineCategory.MIN_1),
|
||
("SH000001 DAY (指数日线, 正确)", Market.SH, "000001", KlineCategory.DAY),
|
||
("SH000001 WEEK (指数周线, /100)", Market.SH, "000001", KlineCategory.WEEK),
|
||
("SH000001 MONTH (指数月线, /100)", Market.SH, "000001", KlineCategory.MONTH),
|
||
("SZ399001 MIN_5 (深成指分钟)", Market.SZ, "399001", KlineCategory.MIN_5),
|
||
("SZ399006 MIN_5 (创业板指分钟)", Market.SZ, "399006", KlineCategory.MIN_5),
|
||
]
|
||
for label, mkt, code, cat in cases:
|
||
df = cl.get_index_bars(mkt, code, cat, 0, 1)
|
||
r = df.iloc[-1]
|
||
ratio = r["amount"] / r["vol"] if r["vol"] else float("nan")
|
||
print(f"{label:<44s} {r['vol']:>16,.0f} {r['amount']:>18,.0f} {ratio:>10.2f}")
|
||
|
||
# 分钟线 f1 与 amount/100 的偏差(仅剩解码噪声)
|
||
df = cl.get_index_bars(Market.SH, "000001", KlineCategory.MIN_5, 0, 5)
|
||
print("\n分钟线 f1 vs amount/100(应≈1.0,偏差为解码噪声):")
|
||
for _, r in df.iterrows():
|
||
print(
|
||
f" {r['datetime']} vol={r['vol']:>13,.0f} amount/100={r['amount'] / 100:>13,.0f}"
|
||
f" 比值={r['vol'] / (r['amount'] / 100):.8f}"
|
||
)
|
||
|
||
# 分时接口 vol 全日合计 ≈ 日成交额/10000(万元)
|
||
mt = cl.get_minute_time_data(Market.SH, "000001")
|
||
day = cl.get_index_bars(Market.SH, "000001", KlineCategory.DAY, 0, 1).iloc[-1]
|
||
print(
|
||
f"\n指数分时 vol 全日合计 = {mt['vol'].sum():,.0f}"
|
||
f" 日成交额/10000 = {day['amount'] / 10000:,.0f}(≈成交额万元,非成交量)"
|
||
)
|
||
finally:
|
||
cl.close()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|