Appearance
TdxQuant 实战(三):封装内部行情服务
上一篇文章已经分别通过本地 HTTP 接口和 Python API,验证了 TdxQuant 可以正常获取历史行情。
这一篇不再展开某个 Web 框架的完整项目代码,而是讨论如何在 TdxQuant 外面增加一层内部行情服务,使它能够被 Spring Boot 或其他业务系统长期、稳定地调用。
这层服务可以使用 Flask、FastAPI 或 Python 原生 HTTP 能力实现。本文以 Flask 和 Waitress 为例说明部分结构,但重点是不同实现都需要面对的数据转换、访问控制和运行稳定性问题。
最终调用链路如下:
text
Spring Boot 等业务服务
→ HTTP
→ Python 行情服务(Flask / FastAPI / 原生实现)
→ tqcenter
→ 通达信金融终端为什么需要封装 TdxQuant
为什么还要增加一层行情服务
TdxQuant 已经在本机提供 127.0.0.1:17709 HTTP 接口,但它更适合本机调试,不适合直接作为对外服务。
一方面,127.0.0.1 只能在当前电脑访问;另一方面,原始接口缺少业务系统常用的统一响应结构、访问鉴权、日志、字段转换和异常处理。因此,可以在外面增加一层自己的 Python 行情接口。
为什么不直接暴露 17709
不建议通过端口映射或防火墙规则,把 TdxQuant 的 17709 端口直接开放到公网。
原始接口能够调用行情、公式以及其他 TdxQuant 能力,一旦暴露,访问范围很难控制。更安全的做法是只开放自己的行情接口,并通过云服务器安全组、IP 白名单和接口鉴权限制调用方。
text
业务服务器
→ 受保护的内部行情 API
→ Python API(tqcenter)
→ TdxQuant一个稳定行情服务需要解决什么问题
把 TdxQuant 封装成 HTTP 接口并不复杂,真正需要考虑的是:这个接口能否长期、稳定并且安全地运行。
只要行情服务监听在 0.0.0.0,并且服务器开放了对应端口,其他设备就可能访问该服务。如果没有任何限制,非法调用者不仅可以读取行情,还可能频繁调用刷新接口,占用通达信客户端、网络和服务器资源。
因此,一个可长期运行的行情服务通常需要解决以下问题:
- 如何识别合法调用方,拒绝未经授权的访问;
- 如何防止请求参数在传输过程中被修改;
- 如何降低合法请求被截获后重复使用的风险;
- 如何限制调用来源、调用频率和可访问的接口;
- 如何记录请求日志,方便定位失败和异常调用;
- 如何处理 TdxQuant 调用失败、超时和客户端离线;
- 如何避免多个请求同时调用底层接口造成不稳定。
最简单的方案是在请求头中携带一个固定 Token:
text
X-API-Token: xxxxxxxxx这种方式适合只有一个调用方的内部服务,但随着调用方增加,固定 Token 很难区分请求来自哪个系统,也不方便单独停用某个调用方。
更完整的方案是给每个调用方分配一组身份信息:
text
clientId
clientSecretclientId 用于标识调用方,可以随请求发送;clientSecret 只保存在调用方和服务端,不能直接通过网络传输,而是用于计算接口签名 sign。
请求中通常还会携带:
text
X-Client-Id
X-Timestamp
X-Nonce
X-Sign服务端根据 clientId 找到对应的 clientSecret,使用相同规则重新计算签名,并依次检查:
text
调用方是否存在
→ 时间戳是否在允许范围内
→ nonce 是否已经使用
→ 请求签名是否一致
→ 当前调用方是否有权访问该接口其中,时间戳用于限制请求有效期,nonce 用于标识一次请求,两者配合可以降低请求被截获后重复提交的风险。
签名用于确认请求由持有 clientSecret 的调用方生成,并验证请求路径、参数和请求体没有被修改。
需要注意,接口签名只能验证调用方和请求内容,不能加密传输数据。如果请求会经过公网或其他不可信网络,还应使用 HTTPS、VPN 或其他加密通道。固定 Token 同样不应通过未加密连接传输。
除了接口签名,还应通过网络层进一步限制访问范围:
text
云安全组 IP 白名单
→ 行情服务应用层 IP 白名单
→ clientId + sign 身份校验IP 白名单和接口签名并不重复。IP 白名单限制哪些服务器可以连接,接口签名则验证请求是否由合法调用方生成。
此外,即使请求来自合法调用方,也应考虑接口限流。调用方程序出现循环错误时,可能在短时间内反复刷新行情,影响通达信客户端和其他正常任务。
本文只介绍这些机制在 TdxQuant 行情服务中的作用和基本设计思路,不提供一套可以直接复制上线的完整鉴权代码。实际项目还需要根据部署网络、调用方数量和安全要求进行调整。
核心接口设计
选择 Web 实现并准备运行环境
工程至少需要包含服务入口、配置文件和启动脚本。Web 层可以选择 Flask、FastAPI,也可以直接使用 Python 原生 HTTP 能力。
如果使用 Flask 和 Waitress,主要依赖可以先安装:
shell
python -m pip install flask waitress pandas -i https://pypi.tuna.tsinghua.edu.cn/simple这里的 Flask 用于定义接口,Waitress 用于在 Windows 中长期运行服务,pandas 用于处理 TdxQuant 返回的数据。选择 FastAPI 或原生实现时,后续的数据转换、鉴权和 TQ 调用约束仍然相同。
启动时只初始化一次
tq.initialize() 不应该在每次请求中重复执行,而应在行情服务启动时初始化一次。
python
tq.initialize(__file__)这样既可以避免重复初始化,也能让初始化失败在服务启动阶段及时暴露。
为什么 TQ 调用需要加锁
Web 框架或 HTTP 服务器可以同时处理多个请求,但 tqcenter 底层会调用通达信提供的本地 DLL,其并发安全性不应被默认假设。
因此,所有 TQ 调用最好统一经过同一个锁:
python
with tq_lock:
data = tq.get_market_data(...)这会让 TdxQuant 请求串行执行。对于日 K 同步、指标计算等任务,稳定性通常比并发吞吐量更重要。
统一响应结构
TdxQuant 的原始返回格式并不一定适合直接提供给 Java 或其他业务系统。
可以在行情服务层统一包装为:
json
{
"success": true,
"data": {},
"message": null,
"timestamp": "2026-07-19T15:31:00"
}这样,业务系统只需要判断统一的状态字段,不必直接依赖 TdxQuant 的原始错误结构。
DataFrame 为什么需要转换
通过 Python API 获取行情时,TdxQuant 会按字段返回多个 pandas DataFrame:
text
{
"Open": DataFrame,
"Close": DataFrame
}这种结构适合 Python 内部计算,但不适合直接作为普通 JSON 返回。
对外可以转换为按证券和日期排列的结构:
json
[
{
"stockCode": "000001.SZ",
"tradeDate": "2026-07-17",
"open": 10.81,
"close": 10.79
}
]同时可以在行情服务边界完成字段名转换:
text
Open → open
High → high
Low → low
Close → closeTdxQuant 内部保留原始字段,对外接口使用统一字段,可以减少业务系统对具体数据源的依赖。
安全设计
从固定 Token 到接口签名
只有一个调用方时,可以先从固定 Token 开始:
text
X-API-Token调用方增加后,再升级为:
text
clientId
clientSecret
timestamp
nonce
sign不同框架都可以在请求进入业务方法前统一完成校验。以 Flask 为例:
python
@app.before_request
def authenticate():
verify_ip()
verify_timestamp()
verify_nonce()
verify_signature()这里的代码只是结构示意。签名原文如何拼接、请求体如何计算摘要、时间戳允许多大偏差,都需要在调用方和服务端之间明确约定。
IP 白名单应该放在哪一层
IP 白名单最好同时放在网络层和应用层。
网络层可以使用云服务器安全组,只允许业务服务器的固定公网 IP 访问行情服务端口;应用层则可以再次检查请求来源。
text
云安全组
→ 行情服务 IP 校验
→ Token 或接口签名
→ 业务接口如果行情服务前面还有 Nginx 或其他反向代理,需要正确处理真实客户端 IP,不能直接相信任意请求头中的地址。
运行与维护
以 Flask 和 Waitress 单进程运行为例
Flask 自带的开发服务器不适合长期运行。Windows 环境下可以使用 Waitress:
python
serve(
app,
host="0.0.0.0",
port=18080,
threads=2,
)这里建议保持单进程,只使用少量线程。虽然 Waitress 可以同时接收请求,但所有 TQ 调用仍通过同一个锁串行执行。
无论选择哪种 Web 实现,都不建议同时启动多个行情服务进程,也不要使用会创建多个 worker 进程的部署方式,避免多个进程分别初始化并争用底层 TdxQuant 能力。
批量刷新、失败重试与日志
证券数量较多时,不建议一次性刷新全部代码,可以按固定数量分批处理。
text
证券列表
→ 每批 20 个
→ 调用 refresh_kline
→ 记录结果
→ 继续下一批批量大小没有固定答案,可以根据实际执行时间、内存占用和接口稳定性调整。
对于网络波动、客户端短暂离线等问题,可以加入有限次数重试,但不要无限循环:
text
第一次失败
→ 等待 2 秒
→ 第二次失败
→ 等待 4 秒
→ 第三次仍失败
→ 记录日志并告警日志至少应记录调用时间、调用方、接口名称、证券数量、执行耗时和错误信息,但不要输出 clientSecret、Token 等敏感数据。
Windows 启动顺序
长期运行时,需要保证启动顺序:
text
Windows 启动
→ 登录用户
→ 启动通达信金融终端并完成登录
→ 启动内部行情服务可以通过 Windows 任务计划程序,在用户登录后延迟一段时间启动行情服务,给通达信客户端预留登录和初始化时间。
由于通达信属于桌面客户端,不建议把这套服务直接当成完全无用户会话的 Windows Service 运行。远程桌面断开后,也需要确认通达信和 TdxQuant 仍能保持正常状态。
实际应用
完成工程化封装后,可以把 TdxQuant 作为一个独立的内部行情节点:
text
业务系统触发行情同步
→ 调用内部行情 API 刷新历史 K 线
→ 获取标准 JSON 行情
→ 数据入库
→ 计算 CCI / KDJ
→ 筛选超卖标的
→ 推送到手机内部行情服务只负责提供稳定的数据能力,定时任务、数据入库、指标计算和消息推送仍由业务系统负责。
安全与运行检查
正式部署前,至少确认以下事项:
text
不直接暴露 17709
内部行情接口具备身份校验
云安全组只允许指定业务服务器访问
接口具备限流或调用频率控制
TQ 调用统一加锁
服务保持单进程
通达信客户端保持登录
刷新失败有重试、日志和告警
错误响应不会泄露敏感路径、Token 或 clientSecret本篇小结
这个系列完成了三个阶段:
text
能安装 → 能调用 → 理解如何工程化运行TdxQuant 负责提供通达信行情能力,Python 行情服务负责建立稳定、统一、可控制的内部 API 边界,Spring Boot 等业务系统则负责调度、数据入库、指标计算和消息推送。
这样既保留了 TdxQuant 的数据能力,也避免业务系统直接依赖它的本地目录、Python 数据结构和原始接口。