Import TDX (通达信) local A-share market data into PostgreSQL / MySQL / SQLite.
读取本地通达信股票数据(日线 + 5/15/30/60 分钟线),增量同步到数据库。适合想用 SQL / pandas 做 A 股量化分析、又不想依赖收费行情 API 的人。
tdx2db 做一件事:把通达信本地数据变成你自己的 SQL 数据库资产。差异化在管道可靠性:
- 增量幂等、断点自愈:起点按股票、按表分别计算,中断重跑不丢数据不重复;衍生分钟表缺口增量重跑自动补齐
- 状态可观测:
tdx2db status一眼确认每表行数/覆盖/日期范围,"退出码 0 ≠ 数据进去了"有官方验证手段 - 无幸存者偏差:数据来自本地 vipdoc 文件,已退市股票的历史仍在
- AI agent 就绪:
AGENTS.md+ Claude Code skill 提供显式的 agent 使用契约
与同类开源项目的分工(事实性对比,各有侧重):
| 项目 | 数据来源 | 产出形态 | 状态* |
|---|---|---|---|
| tdx2db | 本地 vipdoc 文件 | PostgreSQL / MySQL / SQLite(增量同步) | 活跃 |
| easy_tdx | 通达信协议在线直连 | DataFrame / JSON / REST(含指标、回测) | 活跃 |
| tdx-api | 通达信协议在线直连 | Docker 部署的 REST 实时接口 | 活跃 |
| rustdx | 本地 .day + 东方财富 | CSV / ClickHouse / MongoDB(含复权因子) | 低频维护 |
| mootdx / pytdx | 本地文件 + 在线协议 | DataFrame 读取库 | 已停更 |
* 状态为 2026-07 快照。需要实时行情选在线直连类项目;需要可 SQL 查询、可增量维护的历史数据资产,选 tdx2db。
# Python >= 3.9。默认安装即支持 SQLite(零配置开箱即用)
pip install tdx2db
# 使用 PostgreSQL / MySQL 时安装对应驱动
pip install 'tdx2db[postgres]' # PostgreSQL
pip install 'tdx2db[mysql]' # MySQL
pip install 'tdx2db[all]' # 两者都装
# 国内网络可选用镜像加速:pip install tdx2db -i https://mirrors.aliyun.com/pypi/simple/PostgreSQL / MySQL 需要先建数据库(表结构会在首次运行时自动创建,数据库本身需要先建好):
createdb tdx_data # PostgreSQL
# mysql -u root -p -e 'CREATE DATABASE tdx_data' # MySQL
# SQLite 无需此步骤在运行命令的目录下创建 .env 文件(.env 从当前工作目录读取;也可以直接用环境变量或命令行参数):
# 通达信安装目录。判断标准:该目录下应存在 vipdoc/sz/lday/*.day 文件
# Windows 下装在常见默认路径(C:/D:/E: 盘的 new_tdx / zd_zsone / tdx / new_jyplug)时
# 可以不配置——程序会自动探测;显式配置永远优先
TDX_PATH=C:\new_tdx # Windows
# TDX_PATH=/Volumes/share/new_tdx # macOS(SMB 挂载 Windows 共享)
# TDX_PATH=/mnt/share/new_tdx # Linux(CIFS 挂载)
DB_TYPE=postgresql # postgresql / mysql / sqlite
DB_HOST=localhost
DB_PORT=5432
DB_NAME=tdx_data # sqlite 时为文件名(生成 tdx_data.db)
DB_USER=postgres
DB_PASSWORD=your_password # 密码只从 .env 读取,不提供命令行参数可选项:DB_BATCH_SIZE(批量写入大小)、CSV_OUTPUT_PATH(CSV 导出目录)、USE_TQDM(进度条开关)。
最小化尝鲜(不写 .env,SQLite 落盘为当前目录 tdx_data.db):
tdx2db --tdx-path /path/to/new_tdx --db-type sqlite --db-name tdx_data sync-
打开通达信 → 选项 → 盘后数据下载 → 下载日线和分钟线数据(TDX 默认只缓存看过的股票,必须先做这一步)
-
同步股票列表:
tdx2db stock-list --db-only- 一键同步所有行情数据:
tdx2db synctdx2db sync程序按股票逐只检测数据库最新日期,只同步新数据。
tdx2db status # 每表行数 / 覆盖股票数 / 日期范围
tdx2db status --json # 机器可读输出,适合脚本 / LLM agent 消费只读命令,不需要配置 TDX_PATH。sync 之后跑一下即可确认数据真的入库了(退出码 0 不代表数据写入成功);若衍生分钟表(15/30/60)覆盖股票数少于 5 分钟表,会输出警告及修复命令。
增量同步(自动跳过重复数据)依赖 (code, date/datetime) 唯一约束。
新用户:无需任何操作——表结构由程序自动创建,已内建唯一约束。
老用户(v0.2.0 之前建的表没有约束)需执行一次迁移脚本,否则 PostgreSQL 下增量写入会全部失败、MySQL/SQLite 下会静默累积重复数据。不确定的话可先自检:
-- PostgreSQL:有输出说明约束已存在,无需迁移
SELECT conname FROM pg_constraint WHERE conname LIKE 'uq_%';
-- MySQL
SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = DATABASE() AND CONSTRAINT_NAME LIKE 'uq_%';迁移脚本:
# PostgreSQL
psql -U your_user -d your_database -f scripts/add_constraints.sql
# MySQL
mysql -u your_user -p your_database < scripts/add_constraints_mysql.sql脚本会先清理已有重复数据再加约束,执行前请备份。
单独同步日线/分钟线
# 日线增量同步(逐股票精确增量)
tdx2db daily --db-only --auto-start --incremental
# 分钟线增量同步
tdx2db minutes --db-only --auto-start --incremental指定日期范围
tdx2db daily --db-only --start_date 2025-01-01 --end_date 2025-01-31
tdx2db minutes --db-only --start_date 2025-01-01导出到 CSV
tdx2db daily --csv-only
tdx2db minutes --csv-only| 表名 | 唯一约束 | 内容 |
|---|---|---|
daily_data |
(code, date) | 日线 OHLCV + 均线 |
minute5_data / minute15_data / minute30_data / minute60_data |
(code, datetime) | 分钟线 OHLCV + 均线(15/30/60 由 5 分钟重采样) |
stock_info |
code | 股票列表:真实名称 + 总股本/流通A股(万股)+ 股本更新日/上市日期 |
block_stock_relation |
(block_type, block_name, code) | 板块-个股关系(行业/概念/指数/地区/风格/特殊),全量快照 |
板块数据:来自通达信本地板块文件(T0002/hq_cache/),随 sync 自动更新,也可单独 tdx2db blocks --db-only。行业为 881 研究行业(一/二/三级各一行);中证500/1000 等跨市场指数成分完整;每次同步为全量替换快照(无历史版本)。老用户需执行一次 scripts/migrate_block_relation.sql(表结构变更,原表从未有写入路径)。
均线列:ma5 / ma10 / ma60 / ma250 为常规窗口,ma13 / ma21 / ma34 / ma55 / ma89 / ma144 / ma233 为斐波那契窗口(服务缠论类分析,不需要可忽略)。上市不足对应窗口天数的行为 NULL。
stock_info.code 带市场前缀(sz000001 / sh600000),而 daily_data / minute*_data 的 code 是 6 位纯数字(000001)。跨表 JOIN 需要 RIGHT(stock_info.code, 6) 或等价处理——这是最容易踩的坑。
已知限制:
stock_info.name为真实股票名称(来自通达信本地 infoharbor_ex.code,缺失时回退占位符)- 收录范围:深市
000 / 001 / 002 / 300 / 301,沪市60xxxx / 688xxx;北交所、ETF、指数暂未纳入
Q: 报"无法找到股票列表文件"或读到 0 只股票
A: TDX_PATH 指向错误,或通达信还没下载数据。确认该目录下存在 vipdoc/sz/lday/*.day,并先在通达信里执行"盘后数据下载"。
Q: 报 database "tdx_data" does not exist
A: 表结构会自动建,但数据库本身要先创建,见"安装"一节的 createdb。
Q: PostgreSQL 报 no unique or exclusion constraint,或 MySQL 数据越导越多
A: 老库缺唯一约束,见"增量同步与唯一约束"一节的自检和迁移脚本。
Q: 为什么没有北交所 / ETF / 指数数据?
A: 当前 A 股筛选规则只收深市 000/001/002/300/301 和沪市 60/688。北交所(vipdoc/bj/)等扩展欢迎提 PR(见 CONTRIBUTING.md)。
Q: 如何计算换手率?
A: stock_info 存有流通A股 ltag(万股,来自通达信本地 base.dbf,随盘后更新),单位换算后公式恰为:
SELECT d.date, d.volume / s.ltag AS turnover_pct
FROM daily_data d JOIN stock_info s ON RIGHT(s.code, 6) = d.code
WHERE d.code = '000001' ORDER BY d.date DESC LIMIT 20;注意:股本是当前快照,股本变动点(配股/增发等)之前的历史换手率会失真;精确历史换手率需自行结合 gbbq 股本变迁数据。list_date 上市日期也在 stock_info 中,可用于次新股过滤。老库需执行一次 scripts/migrate_stock_info_capital.sql 后重跑 tdx2db stock-list --db-only。
Q: 数据是否复权? A: 不复权,且默认口径不会改变(设计决策,见 issue #2)。复权请在消费端处理。
四层管道,单向数据流:
CLI (cli.py) → Reader (reader.py) → Processor (processor.py) → Storage (storage.py)
argparse pytdx 读取本地 校验 + 重采样 + 均线 SQLAlchemy 批量写库
命令分发 + .day/.lc5 文件 (OHLCV 校验, resample, 增量 ON CONFLICT +
同步编排 MA 计算) 表名白名单
git clone https://github.com/xbfighting/tdx2db.git && cd tdx2db
pip install -e '.[all]'
pytest tests/ # 单元测试(不需要真实 TDX 数据和数据库)从源码运行时 python main.py <子命令> 与 tdx2db <子命令> 等价(老用户习惯保留)。
贡献前请读 CONTRIBUTING.md——特别是"不接受的改动"一节(数据契约)。
使用 AI 辅助开发的贡献者:仓库带 CLAUDE.md,包含架构细节与历史坑(code 格式差异、增量逻辑),能让 AI 产出符合数据契约的 PR。
用 AI agent 查询数据:仓库带 AGENTS.md(schema、典型查询、陷阱清单,跨工具通用)和 Claude Code skill(.claude/skills/tdx2db-query/)。在本仓库目录下工作的 agent 可直接正确使用数据库,无需人工解释。