跳转至

通道与数据源

通达信的不同数据散落在不同的协议和服务器上。选路是 router.py 的职责, 调用方不需要关心——但知道「为什么慢」「为什么某个字段没有」时,这张表是排错起点。

路由表

请求 通道 为什么
K 线 — 复权(QFQ / HFQ) MAC 复权数据只有 MAC 通道提供
K 线 — MIN_1 不复权 MAC 标准通道 1 分钟深度不足;且必须串行分页
K 线 — 其他周期不复权 标准 价格小数位规则已验证
指数 K 线 标准 含涨跌家数等指数专有字段
五档报价 标准 标准通道字段更全(含 decimal_point)
逐笔成交 MAC 含 trade_count(成交笔数),且支持历史回溯
分时 MAC 标准通道不完整;MAC 0x122D 稳定返回 240 条
证券列表 / 数量 标准 仅标准通道提供
除权除息 / 财务 标准 仅标准通道提供
板块 / 竞价 / 异动 / 快照 / 资金流 / 服务器时段 / 分类报价 MAC 这些是 MAC 专有命令
港股 / 美股 / 期货 / 期权 EX(7727) 完全不同的协议栈

只请求,不改语义

路由是内部实现细节。同一个 get_bars() 调用,传不传 adjust 会走不同通道, 但返回类型和字段完全一致——你不需要写 if adjust: 分支。

三组服务器

src/pytdxdata/servers.json 里维护三份清单,分别对应三个连接池:

池 数量级 用途
标准池 9 台 报价 / K线 / 列表 / 财务
MAC 池 22 台 逐笔 / 分时 / 复权 / 板块 / 资金流
EX 池 4 台 港股 / 美股 / 期货 / 期权

上表为 2026-09-21 离线探针(python -m pytdxdata.server_probe --discover)实测可达台数。 服务器会下线、换 IP 或变更协议,实际台数以当日测速缓存为准(见下方「运行时:当日测速缓存」)。

EX 池内部还要再分两类,因为握手方式不同:

类型 数量 握手
MAC EX 服务器 2 0x2454 login
pytdx EX 服务器 2(通达信扩展市场 / 国泰君安) 0x2454 setup

这就是 config.get_ex_handshakes() 存在的原因——EX 的 4 台机器不是同一种握手。

注意 MAC 池实测并不比标准池小(22 台 vs 9 台)。早期版本曾按「MAC 可用节点很少」来解释逐笔 / 分时并发弱于日线,实测已推翻该前提——两者的单台连接上限(mac_pool_cap / std_pool_cap)默认相同,都是 4。

为什么这些服务器会被「探测」

服务器列表不是静态配置——通达信节点会下线、换 IP、或者握手正常但返回空数据。

server_probe 的探测逻辑不是只看 TCP 连通性,而是真实请求一段 K 线并校验内容:

python -m pytdxdata.server_probe              # 按申报协议全量探测
python -m pytdxdata.server_probe --discover   # 三种协议全测,并据实修正 protocols
python -m pytdxdata.server_probe --group ex   # 只测 EX
python -m pytdxdata.server_probe --refresh    # 只重测当前 status=ok 的

普通「只 ping 握手」的探测会把这类坏节点放进来,症状是偶发的空返回—— 比直接连不上更难查。所以探测必须校验数据。

写回字段:status / latency / checked_at / checked_date / fast_pool, 以及顶层 version / checked_date / note。其中 fast_pool 与运行时缓存里的 fast 用同一条规则(整体延迟前 10 名,或延迟 < 200ms),用于还没有当日缓存时的冷启动排序。

为什么需要 --discover

「申报协议」会过期。实测(2026-09-21)有一批服务器的 0x010C 标准 K 线变成空响应 (返回 2 字节空壳),但同端口同主机的 0x122E MAC 帧正常——它们从 standard 退化成了 mac-only。只测申报协议的话,这类退化永远发现不了,标准池会一直含着一批死节点。

--discover 对每台主机把三种协议都测一遍,并据实测结果重写 protocols; 配套两个必须处理的细节:

  • 失败必须重试一次再判定不支持。单次抖动会误删协议,而 protocols 被收窄后不会自动恢复。
  • EX 握手模式申报可能错,探测失败时换另一种(login ⇄ setup)再试。
  • 无任何协议可达时不动 protocols,只把 status 置 fail——保留"它申报过什么"的信息。
  • 顺带剔除 ip 非法的脏记录(历史遗留如 "s1")。

运行时:当日测速缓存

python -m pytdxdata.server_probe 是离线重生成随包清单的工具;运行时还有一条在线的 轻量路径——TdxData.start() 会异步触发一次全量测速,把结果缓存到用户级目录 (…/pytdxdata/hosts-today.json),当天后续启动直接复用,不再重测。

设计与几个必须踩对的点:

关注点 正确做法 反例(会静默出错)
候选集 取全部候选(清单 ∪ 常量 ∪ env) 只把「当前池成员」丢给探针 → 上次慢的节点永远捞不回来
可达判定 发真实 K 线命令并要求非空 只握手 / 只读报文头 → 测不出「空响应」坏节点
写盘位置 用户级缓存目录 写回包内 servers.json → 容器只读、多用户互相覆盖
对调用方 后台 task + debug 日志 + 绝不抛异常 在 start() 里 await 或打印 → 启动变慢、污染用户输出
并发 进程内单例 + asyncio.Lock 三个池各测一遍 → 三倍流量
写入 临时文件 + os.replace 原子替换 直接覆写 → 并发进程读到半截 JSON

全部不可达时不写缓存——否则「今天全挂了」会被缓存一整天,明天也不重试。

缓存存在时,config.get_standard_hosts() 等按实测延迟升序返回该协议的可达主机; 缓存缺失 / 跨日 / 版本不符 / 已损坏时,才回落到包内清单。开关见 安装与配置 → 环境变量。

EX 通道细节

  • 端口固定 7727,与标准 / MAC 的 7709 不同
  • 走 pytdx EX 协议(0x23FF K线 / 0x23FA 报价 / 0x23F4 市场列表)
  • 合约代码规则与 A 股不同:港股 5 位(00700)、美股字母(AAPL)、 期货带月份(IFL0 / rb2610)、期权 8 位(10010971)
  • 美股期权 / 港股期权协议内无数据
await td.get_bars("hk00700", KlinePeriod.DAY, count=700)
await td.get_bars("usAAPL", KlinePeriod.DAY, count=700)

扩展市场用字符串前缀(hk / us / cffex …)指定;ExMarket 的完整成员见 枚举速查。

下一步