mootdx通达信数据接口终极实战指南:从零搭建个人量化行情底座
mootdx通达信数据接口终极实战指南:从零搭建个人量化行情底座
【免费下载链接】mootdx通达信数据读取的一个简便使用封装项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx
写量化策略最耗时间的往往不是模型调参,而是数据:行情散落在通达信二进制文件里、实时接口各家封装的参数五花八门、历史财务数据更是难以拿全。如果你也在为"通达信数据接口"的接入成本头疼,那么本文的主角mootdx正是为你准备的——它把通达信行情、财务、离线数据读取全部封装成十几行代码即可调用的 Python 接口。这是一份重代码、重实战的从零教程,跟着敲完,你将拥有一个属于自己的量化行情底座。
核心价值:mootdx 是一个"通达信数据读取的简便封装",覆盖线上实时行情(Quotes)、离线二进制解析(Reader)、历史财务数据(Affair/Financial)三大能力,统一输出 pandas DataFrame,并自带最优服务器探测、自动重连与断线重试。
开工前先建立能力地图:mootdx 到底能做什么
动手之前,先用一张能力清单建立认知地图,后续每一节都能对上号:
| 模块 | 一句话能力 | 典型场景 |
|---|---|---|
mootdx.quotes.Quotes | 线上实时行情:K线、分时、五档、分笔、F10、除权除息 | 盘中监控、实时信号 |
mootdx.reader.Reader | 解析本地通达信vipdoc二进制数据 | 全量历史回测、离线分析 |
mootdx.affair.Affair | 财务数据文件列表、下载、解析 | 基本面选股、财报因子 |
mootdx.server.bestip | 探测并缓存最优行情服务器 | 提升连接稳定性与速度 |
mootdx.utils.to_file | DataFrame 一键导出 csv/xlsx/h5/json | 数据落地与备份 |
整个数据流非常直观:线上行情走 Quotes → 本地全量走 Reader → 基本面走 Affair → 统一落成 DataFrame → to_file 持久化。官方文档在docs/quick.md、docs/api/quote1.md、docs/api/reader.md,源码集中在mootdx/quotes.py、mootdx/reader.py、mootdx/affair.py,遇到疑问可以直接翻源码。
30 秒跑通第一个行情程序
环境初始化只需要两步,我们直接上手。
步骤一:安装依赖(建议在虚拟环境中执行)
# 安装包含全部扩展依赖 pip install -U 'mootdx[all]' # 想从源码学习或二次开发,可以克隆仓库 git clone https://gitcode.com/GitHub_Trending/mo/mootdx cd mootdx && pip install -e '.[all]'步骤二:复制即运行的最小 Demo
from mootdx.quotes import Quotes # market='std' 表示标准市场(沪深股票),bestip 自动探测最优服务器 client = Quotes.factory(market='std', bestip=True, heartbeat=True, timeout=15) # 拉取招商银行最近 10 根日 K df = client.bars(symbol='600036', frequency=9, offset=10) print(df[['open', 'high', 'low', 'close', 'vol']].head())预期输出(字段以实际为准):
open high low close vol datetime 2026-08-01 09:30:00 32.1 32.55 31.98 32.40 251234.0 2026-08-04 09:30:00 32.4 32.80 32.20 32.66 268901.0 ...到这里你已经完成了 90% 的接入工作,剩下的就是围绕业务把各个能力拼装起来。下面我们逐个拆解三大核心能力。
用 Quotes 吃透线上实时行情:K线、分时、五档一网打尽
Quotes.factory()是一个工厂方法:传入market='std'返回沪深标准行情客户端,传入market='ext'返回扩展市场客户端(期货、黄金等)。生产环境强烈建议开启bestip=True自动选优,配合heartbeat=True保持长连接心跳,避免服务器静默断开。
多周期 K 线:用字符串代替难记的数字
bars()的frequency参数既支持数字也支持字符串,内部通过get_frequency()做映射。对应的映射表定义在mootdx/utils/__init__.py中:
| 字符串 | 周期 | 数字 |
|---|---|---|
'5m' | 5 分钟 | 0 |
'15m' | 15 分钟 | 1 |
'30m' | 30 分钟 | 2 |
'1h' | 60 分钟 | 3 |
'day' | 日 K | 9 |
'week' | 周 K | 5 |
'mon' | 月 K | 6 |
这里最容易踩坑:单次offset上限是 800 条,超过会被自动截断;想要更长的历史,用start分页拉取,或者直接用下文会讲到的k()按日期区间取数。另外bars()支持复权参数adjust:
from mootdx.quotes import Quotes client = Quotes.factory(market='std') # 前复权日 K:复权因子来自除权除息数据,对回测至关重要 df_qfq = client.bars(symbol='600036', frequency='day', offset=800, adjust='qfq') # 按日期区间取日 K,自动分页拼接,还顺带过滤节假日 df_range = client.k(symbol='600036', begin='2025-01-01', end='2025-12-31') print(df_range[['open', 'close']].tail())批量快照、分时与分笔:监控系统的地基
class RealtimeMonitor: """盘中快照监控:批量报价 + 分时 + 分笔成交""" def __init__(self, market='std'): self.client = Quotes.factory(market=market, heartbeat=True) def snapshot(self, symbols): """批量获取多只股票实时快照(五档等)""" df = self.client.quotes(symbol=symbols) return df[['code', 'price', 'last_close', 'open', 'high', 'low', 'vol']] def intraday(self, symbol): """当日分时 + 当日分笔成交""" minute = self.client.minute(symbol=symbol) ticks = self.client.transaction(symbol=symbol, start=0, offset=100) return minute, ticks # 使用示例 monitor = RealtimeMonitor() snap = monitor.snapshot(['000001', '600000', '000858']) print(snap.head())除权除息与财务快照:回测不复权的元凶
回测收益失真,十有八九是忽略了复权。xdxr()返回除权除息事件,finance()返回最新财务摘要,两者配合adjust='qfq'能还原真实可比的股价序列:
# 查看贵州茅台的除权除息记录 xdxr_df = client.xdxr(symbol='600519') print(xdxr_df[['category', 'name', 'year', 'fenhong', 'peigu', 'songzhuangu']].head()) # 查看最新财务摘要(每股收益、净资产等) fin = client.finance(symbol='600519') print(fin.head())用 Reader 榨干本地通达信二进制数据:离线全量历史不求人
线上接口只提供近期的 K 线,做全量回测必须解析本机通达信客户端落盘的二进制文件。Reader帮你自动匹配vipdoc/{sh,sz,ds}/lday/*.day这类路径,无需关心字节格式。
三种频率一次讲透:日线、分钟线、五分钟线
from mootdx.reader import Reader # tdxdir 必须是通达信安装目录(内含 vipdoc 子目录) reader = Reader.factory(market='std', tdxdir='/path/to/tdx') # 日线:读取 sh600036.day daily = reader.daily(symbol='600036') print(daily.head()) # 1 分钟线:minline/sh600036.lc1 min1 = reader.minute(symbol='600036') # 5 分钟线:fzline/sh600036.lc5 min5 = reader.fzline(symbol='600036') print(min5.head())这里最容易踩坑:tdxdir传错层级会直接抛Exception: tdxdir 目录不存在。它必须指向通达信安装根目录(包含vipdoc/文件夹),而不是vipdoc本身。源码见mootdx/reader.py的ReaderBase.find_path(),它会按"88 开头的板块指数放 sh 目录、带#的扩展市场放 ds 目录"自动路由。
板块数据与自定义板块:从"个股视角"升级到"板块视角"
# 解析本地板块文件,group=True 时按分组返回 blocks = reader.block(symbol='block_zs.dat', group=True) print(blocks.head()) # 自定义板块:把一批股票写入通达信自定义板块 ok = reader.block_new(name='我的自选', symbol=['600036', '000001', '000858']) print('板块创建成功' if ok else '创建失败')批量读取封装:一个函数搞定几十只股票
from pathlib import Path from mootdx.reader import Reader class OfflineReader: """离线批量读取器:自动跳过缺失文件""" def __init__(self, tdxdir): self.reader = Reader.factory(market='std', tdxdir=tdxdir) def batch_daily(self, symbols, start_date=None): result = {} for code in symbols: try: df = self.reader.daily(symbol=code) if df is None or df.empty: continue if start_date: df = df[df.index >= start_date] result[code] = df except Exception as e: # 单只失败不影响整体 print(f'{code} 读取失败: {e}') return result # 使用示例 loader = OfflineReader('/path/to/tdx') data = loader.batch_daily(['600036', '000001', '600000'], start_date='2024-01-01') print({k: len(v) for k, v in data.items()})用 Affair 一键搞定历史财务数据:下载、校验、解析三合一
基本面分析最缺的是"干净的历年财报"。Affair负责从通达信服务器拉取gpcw*.zip财报压缩包并解析成带中文表头的 DataFrame。
三步走:查列表、下载、解析
from mootdx.affair import Affair # 1. 获取远程财务文件列表(含 filename / hash / filesize) files = Affair.files() print(files[:3]) # 2. 下载单个财报压缩包(带 tqdm 进度条) Affair.fetch(downdir='financial_data', filename='gpcw20251231.zip') # 3. 解析成中文表头的 DataFrame(code 为索引) df = Affair.parse(downdir='financial_data', filename='gpcw20251231.zip') print(df.head())这里最容易踩坑:parse()传入的downdir必须与fetch()的下载目录一致;如果本地没有该文件,parse()会自动先下载再解析(源码见mootdx/affair.py)。另外下载时会校验文件 MD5,重复文件会跳过,重试成本很低。
增量同步器:只下载缺失的财报
import os from pathlib import Path from mootdx.affair import Affair class FinancialSyncer: """财务数据增量同步:跳过已下载且校验通过的压缩包""" def __init__(self, download_dir='financial_data'): self.download_dir = Path(download_dir) self.download_dir.mkdir(exist_ok=True) def sync(self): remote = Affair.files() local = {p.name for p in self.download_dir.glob('*.zip')} missing = [f for f in remote if f['filename'] not in local] for f in missing: print(f"下载 {f['filename']} ...") Affair.fetch(downdir=str(self.download_dir), filename=f['filename']) print(f"完成,本次新增 {len(missing)} 个文件") # 使用示例 FinancialSyncer().sync()组合实战:30 行代码构建全市场日线增量备份工具
把前面三大能力串起来,我们构建一个真正能用的工具:自动获取全市场股票列表 → 逐日拉取日 K → 按"股票代码.csv"落地磁盘 → 已存在的文件跳过。这就是一个迷你量化数据仓库。
import time from pathlib import Path from functools import lru_cache from mootdx.quotes import Quotes from mootdx.utils import to_file class DailyBackupEngine: """全市场日线增量备份:Quotes 拉数 + to_file 落地""" def __init__(self, out_dir='daily_backup', retries=3): self.out_dir = Path(out_dir) self.out_dir.mkdir(exist_ok=True) self.retries = retries self.client = Quotes.factory(market='std', bestip=True, heartbeat=True) def _fetch_with_retry(self, symbol): """带重试的单只日 K 拉取,规避瞬时断连""" for attempt in range(self.retries): try: df = self.client.bars(symbol=symbol, frequency='day', offset=800, adjust='qfq') if df is not None and not df.empty: return df except Exception as e: print(f'{symbol} 第{attempt + 1}次失败: {e}') time.sleep(2 * (attempt + 1)) # 退避等待 return None def run(self, market=0, limit=50): """market=0 上海 / 1 深圳;limit 控制本次数量,避免全市场耗时过长""" stocks = self.client.stocks(market=market) # 返回股票列表 DataFrame codes = stocks['code'].astype(str).str.zfill(6).head(limit).tolist() done = 0 for code in codes: target = self.out_dir / f'{code}.csv' if target.exists(): # 增量:已存在则跳过 continue df = self._fetch_with_retry(code) if df is None: continue to_file(df.reset_index(), filename=str(target)) # 自动识别 .csv 后缀 done += 1 print(f'已备份 {code},累计 {done} 只') print(f'本次任务完成,共落地 {done} 个文件到 {self.out_dir}') # 使用示例:备份上海市场前 50 只股票 DailyBackupEngine().run(market=0, limit=50)这个引擎演示了工程化的三个关键动作:连接复用(只创建一次客户端)、失败重试(退避指数)、增量落地(文件存在即跳过)。把它挂到定时任务里,你就有了一份可持续更新的本地日线库;再叠加Reader读历史、Affair补财务,一个完整的量化数据底座就成型了。
避坑指南:高频报错与性能瓶颈速查
实战中高频问题整理成速查表,遇到直接对照:
| 现象 | 根本原因 | 解决方案 |
|---|---|---|
tdxdir 目录不存在 | tdxdir传成了vipdoc或子目录 | 传入通达信安装根目录,如C:/new_tdx、/path/to/tdx |
| 行情一直返回空 DataFrame | 行情服务器失联/被断 | 开启bestip=True重测服务器;heartbeat=True保活;或手动执行python -m mootdx bestip -vv刷新配置 |
frequency数字记混 | 数字与周期对应关系难记 | 直接用字符串'day'、'5m'、'week',映射表见mootdx/utils/__init__.py |
bars拿到的 K 线不够长 | 单次offset上限 800 | 用start分页循环,或改用k(begin=, end=)按日期区间取 |
| 回测收益与真实严重偏离 | 未做复权 | bars(..., adjust='qfq')前复权,或adjust='hfq'后复权 |
| 扩展市场接口不可用 | 官方已标注失效 | 关注ExtQuotes的 warning 日志,期货/黄金数据建议自行评估替代方案 |
| 财务文件解析出空表 | downdir与下载目录不一致 | 确保parse()与fetch()使用同一目录;文件缺失时parse()会自动先下载 |
| M1 Mac 无法安装 PyMiniRacer | 该依赖与 Apple Silicon 兼容性问题 | 见docs/faq/py_mini_racer.md,按文档处理或避开相关功能 |
性能最佳实践三条:
- 永远不要循环里反复
Quotes.factory()——每次创建都是一次 TCP 握手与服务器探测,全局复用一个客户端,能省下数倍耗时。项目自带的重连逻辑(mootdx/quotes.py中reconnect())会帮你自动恢复。 - 批量优于单只——
quotes(symbol=[...])支持一次传入多只股票,比逐只请求减少大量网络往返。 - 缓存落地——频繁查询的数据用
to_file落盘成 csv/h5,下次直接读文件;需要内存缓存的场景可以参考tests/test_reconnect.py、tests/test_frequency.py里的用法,结合项目测试用例理解行为边界。
总结与下一步:从复制代码到真正跑起来
回顾一下,你在这篇教程里拿到了三把钥匙:
- Quotes:线上实时行情,K线/分时/分笔/除权除息一条龙,
adjust复权参数保证回测数据真实可比; - Reader:离线二进制解析,日线/分钟线/板块数据自动路由,全量历史不求人;
- Affair:财务数据下载与解析,带 MD5 校验的增量同步,基本面因子随手可得;
- 最后用 30 行组合出一个全市场日线增量备份引擎,直接落地成可运行的量化数据仓库。
接下来怎么继续?我建议你按这个顺序动手:先跑通文中的最小 Demo 建立信心,再对照docs/api/quote1.md和docs/api/reader.md逐一实验每个方法,然后浏览sample/目录下的官方示例(basic_quotes.py、basic_reader.py、basic_affairs.py),最后把备份引擎挂到你自己的定时任务里,开始积累第一份本地行情数据。
数据和策略一样,都需要长期沉淀。现在就去跑第一行代码吧——你的量化行情底座,从这次动手开始。
【免费下载链接】mootdx通达信数据读取的一个简便使用封装项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
