通达信 TCP 协议 A 股行情数据客户端
Project description
xmtdx
通达信 TCP 协议 A 股行情数据客户端,零运行时依赖。
pytdx 年久失修:多处已知解析 bug、Python 2 包袱、无类型注解、大量未知字段被静默丢弃。xmtdx 重新实现协议,修复已知 bug,保留全部原始字节与未知字段供后续逆向分析。
特性
- 零依赖:纯标准库,Python ≥ 3.10
- 同步 + asyncio 双接口:
TdxClient/AsyncTdxClient,commands 层不含任何 IO - 完整类型注解:strict
mypy+ruff通过 - 高可用传输:同步/异步均支持
ping_all()、from_best_host()、断线自动重连 - 修复 pytdx 已知 bug(见下文)
- 保留原始字节:每条数据记录含
_raw: bytes,未知字段以unknown_N命名而非丢弃 - 保活心跳机制:
AsyncTdxClient自动发送心跳包,确保长连接生产环境稳定性 - 沪深 A 股完整列表:
get_security_list_all()自动过滤非 A 股品种并挂载行业信息 - 北交所列表限制:
get_security_list(Market.BJ, start)当前不能稳定获取,BJ 暂未纳入get_security_list_all() - 全市场涨跌统计:一键获取全 A 股涨/跌/平家数及总成交额
- 离线 + 本地传输回归测试:覆盖解析、异步并发串行化、超时、自动重连与坏包处理
安装
python3 -m venv .venv
source .venv/bin/activate
pip install -e . # 开发模式
pip install -e ".[dev]" # 含测试/类型检查工具
pip install -e ".[pandas]" # 含 pandas(可选)
快速开始
同步
from xmtdx import TdxClient, Market, KlineCategory
# 指定服务器
with TdxClient("180.153.18.170") as c:
count = c.get_security_count(Market.SH)
bars = c.get_security_bars(Market.SH, "600000", KlineCategory.DAY, 0, 5)
for b in bars:
print(b.year, b.month, b.day, b.open, b.close, b.high, b.low, b.vol)
# 自动测速选最低延迟服务器
with TdxClient.from_best_host() as c:
quotes = c.get_security_quotes([(Market.SH, "600000"), (Market.SZ, "000001")])
print(quotes[0].price, quotes[0].bid1, quotes[0].ask1)
asyncio
import asyncio
from xmtdx import AsyncTdxClient, Market, KlineCategory
async def main():
async with AsyncTdxClient("180.153.18.170") as c:
bars = await c.get_security_bars(Market.SH, "600000", KlineCategory.DAY, 0, 5)
print(bars[0])
asyncio.run(main())
高可用工具
from xmtdx import ping_all, KNOWN_HOSTS
# 并发测速,返回按延迟排序的 [(host, seconds), ...]
results = ping_all(KNOWN_HOSTS, timeout=5.0)
for host, ms in results:
print(f"{host} {ms*1000:.0f} ms")
# 自动选最优服务器
with TdxClient.from_best_host(ping_timeout=5.0) as c:
...
# asyncio 版本同样支持
client = AsyncTdxClient.from_best_host(ping_timeout=5.0)
内置服务器列表(KNOWN_HOSTS):
180.153.18.170 180.153.18.171 180.153.18.172
115.238.56.198 115.238.90.165 218.75.126.9
47.107.75.159 59.175.238.38
API
TdxClient
| 方法 | 说明 |
|---|---|
get_security_count(market) |
市场证券总数 |
get_security_list(market, start) |
证券列表(每页 ~1000 条;BJ 当前不能稳定获取) |
get_security_list_all() |
沪深 A 股列表(自动挂载行业信息;BJ 暂未纳入) |
get_market_stat() |
全市场 A 股涨跌统计(家数、成交额) |
get_security_quotes([(market, code), ...]) |
批量实时五档行情(最多 80 只/次) |
get_price_limits(market, code, name, pre_close) |
计算当前涨跌停价(自动处理上市初期无涨跌幅限制) |
get_security_bars(market, code, category, start, count=800) |
K 线(股票) |
get_index_bars(market, code, category, start, count=800) |
K 线(指数) |
get_minute_time_data(market, code) |
今日分时(240 条) |
get_history_minute_time_data(market, code, date) |
历史某日分时,date=YYYYMMDD |
get_transaction_data(market, code, start, count=800) |
当日逐笔成交(分页) |
get_history_transaction_data(market, code, date, start, count=800) |
历史逐笔成交 |
get_fund_flow(market, code) |
当日资金流向统计(超大/大/中/小单) |
get_history_fund_flow(market, code, start, count) |
历史日线资金流向序列(优先 Category 22,空回包时自动回退到历史逐笔重算) |
get_xdxr_info(market, code) |
除权除息历史 |
get_finance_info(market, code) |
最新财务数据 |
get_company_info_category(market, code) |
公司信息文件目录 |
get_company_info_content(market, code, filename, offset, length) |
公司信息文本 |
get_block_info(filename) |
板块信息(行业、概念、风格等) |
get_report_file(filename) |
批量拉取大文件(如 'base_info.zip', 'gpcw.txt') |
AsyncTdxClient 提供与同步版对应的查询方法与高可用入口,均为 async def。
单个 AsyncTdxClient 仅维护一条 TCP 连接;并发调用会在连接内串行执行。
已知限制
xmtdx当前不能稳定获取 BJ 证券列表;get_security_count(Market.BJ)可用,但get_security_list(Market.BJ, start)经常超时,因此get_security_list_all()暂不纳入 BJ。
KlineCategory
MIN_1 MIN_3 MIN_5 MIN_15 MIN_30 MIN_60
DAY WEEK MONTH SEASON YEAR YEAR_ALT
数据模型
所有 dataclass 字段均有类型注解。每条记录附带 _raw: bytes(原始协议字节)。
SecurityBar(K 线)
open close high low vol amount
year month day hour minute
_raw
SecurityQuote(实时行情)
market code price pre_close open high low
vol cur_vol amount s_vol b_vol
bid1..bid5 bid_vol1..bid_vol5
ask1..ask5 ask_vol1..ask_vol5
rise_speed limit_up limit_down server_time
unknown_2..unknown_3 unknown_5..unknown_8
_raw
limit_up / limit_down 当前不再直接由协议字段映射,默认保留为 None;
建议通过 client.get_price_limits(...) 计算当前涨跌停价,或用
xmtdx.codec.price_rules.compute_price_limits(..., listed_days=...) 做纯规则计算。
MinuteBar(分时)
price vol
unknown_1 # 原 pytdx 丢弃字段,保留供分析(≠ 均价)
_raw
TransactionRecord(逐笔成交)
hour minute price vol
buyorsell # 0=买, 1=卖, 2=中性, 8=集合竞价
unknown_last
_raw
SecurityInfo(证券列表)
market code name volunit decimal_point pre_close
industry_tdx industry_sw
XdxrRecord(除权除息)
market code year month day category name
fenhong peigujia songzhuangu peigu suogu
xingquanjia fenshu
panqian_liutong panhou_liutong # 单位:万股
qian_zongguben hou_zongguben # 单位:万股
_raw
category == 1 时,fenhong / songzhuangu / peigu 已归一化为“每股”口径。
复权公式
若在仓库外自行计算前复权 / 后复权,建议仅使用 category == 1 的 xdxr
记录(现金分红 / 送转 / 配股)参与因子计算:
cash = fenhongbonus = songzhuangurights = peigurights_price = peigujia
单次除权除息事件的价格因子可写为:
factor = (pre_close - cash + rights * rights_price) / (1 + bonus + rights)
其中 pre_close 为事件前一交易日的未复权收盘价。
- 前复权:将事件日前的历史价格连续乘以各次
factor - 后复权:将事件日后的价格连续除以各次
factor
当前建议只把 category == 1 用作复权;2..14 类事件仍更适合作为原始事件暴露,
不建议直接纳入通用复权引擎。
FinanceInfo(财务)
流通股本、总股本、各省份/行业代码、资产负债表及利润表主要科目(30 个 float 字段)。
CompanyInfoCategory(公司信息目录)
name filename start length
TdxBlock(板块信息)
name category count codes
FundFlow(资金流)
super_in/out large_in/out medium_in/out small_in/out
main_net_inflow total_net_inflow
HistoricalFundFlow(历史资金流序列)
year month day
super_in/out large_in/out medium_in/out small_in/out
main_net_inflow
修复的 pytdx Bug
| # | 位置 | 问题 | 修复 |
|---|---|---|---|
| 1 | xdxr_info |
循环内始终读 body[:7],所有记录字段相同 |
改为从当前 pos 读取,pos 正确推进 |
| 2 | security_list |
GBK 解码截断时 crash | decode('gbk', errors='replace') |
| 3 | security_list |
pre_close 误当作整数价格 /100 |
恢复为通达信自定义浮点解码 |
| 4 | transaction |
最后一个字段被 _ 丢弃 |
保留为 unknown_last |
| 5 | minute_time |
reversed1 字段被丢弃 |
保留为 unknown_1 |
| 6 | xdxr_info |
股本字段用 float(uint32) 直解,差约 374 倍 |
改用 _decode_volume(通达信自定义浮点),单位万股,与 FinanceInfo 完全吻合 |
| 7 | security_quotes |
涨停/跌停价映射错误或缺失 | 停止使用不可信协议位,改由业务规则计算 |
架构
src/xmtdx/
├── client.py # TdxClient / AsyncTdxClient(高层 API)
├── transport/
│ ├── sync.py # TdxConnection(socket)+ ping_host / ping_all
│ └── async_.py # AsyncTdxConnection(asyncio)
├── commands/ # 每条命令:build_request() + parse_response(),无 IO
├── codec/ # price / volume / datetime / frame 编解码
└── models/ # 纯 dataclass,无业务逻辑
commands 层不依赖 transport,可独立单测。transport 层负责 TCP、握手、帧解压、分发。
开发
# 单元测试(无需网络)
python -m pytest tests/unit/
# 集成测试(需要网络,默认跳过)
XMTDX_LIVE=1 python -m pytest tests/integration/
# 未知字段探测脚本
python scripts/probe_unknowns.py
# 类型检查
mypy src/
# lint
ruff check src/ tests/
协议说明
通达信使用私有二进制 TCP 协议:
- 帧格式:16 字节响应头(含 zipsize / unzipsize),body 按需 zlib 解压
- 价格编码:变长有符号整数(类 LEB128,bit8=继续,bit7=符号,首字节低 6 位 + 后续低 7 位)
- 成交量编码:4 字节自定义浮点(字节 3 = 指数,字节 0-2 = 精度),不可用于价格字段
- 握手:连接后必须顺序发送 3 条 setup 命令,响应丢弃
- 价格存储:整数 × 100,差分编码(相邻 tick 存 delta)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file xmtdx-0.1.1.tar.gz.
File metadata
- Download URL: xmtdx-0.1.1.tar.gz
- Upload date:
- Size: 74.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfdfc28902b24bee755bdf1f0f3b893d0bbe8fdfef848b67e5f1e1286c7ad70a
|
|
| MD5 |
f81d403eb557b638e1dae609542ea3d6
|
|
| BLAKE2b-256 |
5783c27247d530ba20390af680ea407b71b20d764b05ac6ce6f1d971061403da
|
File details
Details for the file xmtdx-0.1.1-py3-none-any.whl.
File metadata
- Download URL: xmtdx-0.1.1-py3-none-any.whl
- Upload date:
- Size: 50.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b064dd0308da6a3bab92336ff6cace02adad7268c2126e413a9122e32d7e7b7a
|
|
| MD5 |
fbb93189b23ddcb6bf9268a70208f059
|
|
| BLAKE2b-256 |
9119758ea85f9175129025c124b3b33845856c62ecea0368ea07e496caa4b6d4
|