quotekit — A股/北交所/场内ETF 统一行情工具箱
一个出口拉取 A 股个股(含北交所)、场内 ETF 与指数的实时行情和 K 线,统一返回 pandas DataFrame。
- 标的覆盖:沪深 A 股 + 北交所(43/83/87/92 开头)+ 场内 ETF(沪 50/51/52/56/58、深 15/16 开头)+ 股指指数
- 默认源 mootdx(通达信协议,32 线程并发,快、带五档盘口)
- 自动回退:mootdx 失败/缺失的代码(含北交所、休市场景)自动用 easyquotation 新浪源补,仍缺失再用腾讯源
- 休市可用:休市时返回最后交易日收盘快照(自动落到 eq 源,属设计行为)
安装
pip install -e . # 开发安装
pip install build && python -m build # 打包: dist/quotekit-0.6.0-py3-none-any.whl
pip install dist/quotekit-0.6.0-py3-none-any.whl
依赖:pandas、mootdx、easyquotation、pypinyin(见 pyproject.toml)。
快速上手
from quotekit import get_quotes, get_index_quotes, configure
# 个股: 三种代码写法混用均可
df = get_quotes(['600519', '000001.SZ', 'sh600000', '920099'])
print(df[['symbol', 'price', 'open', 'high', 'low', 'volume', 'amount', 'time']])
# 指数: 000001上证 399001深成 399006创业板指 000300沪深300
idx = get_index_quotes(['000001', '399001', '000300'])
# 场内ETF: 与个股同一接口, 支持实时快照(含五档)和K线
etf = get_quotes(['510300', '510050', '588000', '159915', '511990'])
etf_bars = get_bars('510300', freq='day', sd='2026-01-01') # ETF日K
# 交易所 A 股列表(symbol 格式 000001.SZ): 'all' | 'SH' | 'SZ' | 'BJ'
lst = get_stock_list() # 全市场 5400+ 只, 含名称
lst = get_stock_list('BJ') # 仅北交所
lst = get_stock_list(refresh=True) # 强制绕过缓存重拉
# K线: 单只或多只, 频度 1m/5m/15m/30m/60m/day/week/month, 支持复权与日期区间
bars = get_bars('600519', freq='day', limit=120) # 最近120根
bars = get_bars(['600519', '000001.SZ'], freq='30m', limit=100) # 多只30分钟K
bars = get_bars('600519', freq='day', limit=800, adjust='qfq') # 前复权
bars = get_bars('600519', freq='day', sd='2024-01-01') # 日期区间(优先于limit)
bars = get_bars('600519', freq='day', sd='2026-01-01', ed='2026-03-31')
bars = get_bars('000001.SZ', freq='day', ed='2025-12-31') # ed之前全部历史
bars = get_bars('920099', freq='week', limit=52) # 北交所周K
# 搜索: 股票/ETF/指数, 支持代码/中文名/拼音首字母/全拼
search('茅台') # 中文名 -> 600519
search('mt') # 拼音首字母
search('maotai') # 全拼
search('000001') # 同时命中 上证指数 + 平安银行
search('hs300', kind='etf') # kind: 'all'|'stock'|'etf'|'index'
# 强制指定源 / 临时改线程数
df = get_quotes(['600519'], source='tencent')
df = get_quotes(all_codes, workers=16)
# 全局配置(线程数/超时/批量, 批量上限60)
configure(workers=32, timeout=10, batch=60)
返回 schema
个股/ETF 29 列 / 指数 9 列,symbol 格式 600519.SH / 000001.SZ / 920099.BJ / 510300.SH。
| 列 | 类型 | 说明 |
|---|---|---|
| code | str | 6 位纯代码 |
| symbol | str | 带市场后缀 |
| price | float | 现价 |
| open / high / low | float | 今开 / 最高 / 最低 |
| volume | int64 | 成交量(股票=股、ETF=份;mootdx 源手×100) |
| amount | float | 成交额(元) |
| time | str | YYYY-MM-DD HH:MM:SS |
| bid1..5 / ask1..5 | float | 五档价(个股与 ETF) |
| bid_vol1..5 / ask_vol1..5 | int64 | 五档量(个股与 ETF) |
场内 ETF 实测说明(2026-09-30 快照验证):实时与 K 线与个股完全同接口;成交量口径为份, 经"金额÷量≈现价"自检通过(510300/510050/588000/159915/511990 五只全部吻合);日K收盘与量 和实时快照精确一致;mootdx 主路径交易日生效(TDX 协议 ETF 与股票同接口)。
get_stock_list(market) 返回 4 列:code(6 位)、symbol(000001.SZ 格式)、name、market(SH/SZ/BJ)。
SH/SZ 来自 mootdx 实时列表(含名称,休市可用),A 股口径前缀:SH 60/68、SZ 00/30;BJ 来自 easyquotation
内置代码表(静态文件,名称经 eq 补齐,新上市股票可能滞后)。进程内缓存,refresh=True 重拉。
注意:列表仅含 A 股,不含 ETF/指数(get_quotes/get_bars 支持场内 ETF,代码需自行传入)。
search(keyword, kind, limit) 返回 5 列:code / symbol / name / market / type(type 为
stock/etf/index,etf 含 LOF 等场内基金)。证券池覆盖全部 A 股 + 北交所 + 场内基金 + 沪深指数,
来自 mootdx 全列表(与 get_stock_list 共享缓存)+ 北交所清单。
匹配排序两级:先按匹配层级(代码精确 > 代码前缀 > 名称前缀 > 名称包含 > 拼音首字母前缀 >
首字母包含 > 全拼包含 > 模糊兜底),同层内按相似度降序(difflib SequenceMatcher 的字母重合度,
如 mt 会把"煤炭"排在"煤炭指数"前);拼写有误差时(如 maotia)由模糊层兜底召回(阈值 0.55,
结合最长公共子串比率)。
全量列表获取:8 线程分页并行拉取(每页 1000 条,绕过 mootdx 自带 stocks() 的串行翻页,
直接调底层 tdxpy 协议接口),三级缓存——进程内 → 磁盘(TTL 8 小时,~/.quotekit/market_list.csv,
环境变量 QUOTEKIT_CACHE_DIR 可改路径,跨进程复用)→ 网络。refresh=True 强制重拉并刷新磁盘缓存。
get_bars(codes, freq, limit, adjust, sd, ed) 返回 9 列:code / symbol / datetime / open / high / low / close /
volume(股) / amount(元)。datetime:分钟线 YYYY-MM-DD HH:MM:SS,日线及以上 YYYY-MM-DD。
取数方式两种(给了 sd/ed 时优先,忽略 limit):
- limit 模式:最近 N 根。mootdx 逐只自动翻页凑足;tencent/sina 按源上限截断(日K 800、分钟 320/1970)。
- 日期区间模式:
sd/ed('YYYY-MM-DD',分钟线可带时分秒;均可单独给,ed 缺省=至今)。 tencent 日线原生支持日期段并按年分段回拉(可取全部历史,实测 1991 年起);mootdx 回翻过滤; 分钟线的日期区间受源保留窗口限制(mootdx 近期、tencent 最近 320 根、sina 最近 1970 根)。 日期模式下区间无数据返回空 DataFrame(不报错)。
频度与源能力:
| 频度 | mootdx(主源) | tencent(回退) | sina(回退,仅分钟) |
|---|---|---|---|
| 1m/5m/15m/30m/60m | 近期滚动窗口,复权支持 | 320 根,无复权 | 1970 根,无复权 |
| day/week/month | 回溯到上市,复权支持 | 800 根/段(自动分段翻全部历史),复权支持 | ✗ |
分钟频率的复权仅 mootdx 支持;腾讯源无成交额字段(amount 为 NaN);休市时 mootdx 返回空自动回退。
数据源与实现
| 数据 | 主路径 | 回退路径 | 说明 |
|---|---|---|---|
| 个股/ETF 实时快照 | mootdx → tdxpy(通达信 TCP 7709,32 线程 × 60 只/批) | 新浪 → 腾讯(easyquotation) | 休市时 mootdx 空,自动回退拿最后快照 |
| 指数实时快照 | mootdx 底层 tdxpy(显式 market+code,绕过 mootdx 的市场误判) | 新浪 → 腾讯 | sina 沪市指数量单位为手已 ×100 归一 |
| K线 分钟 | mootdx(近期窗口,支持复权) | 腾讯 mkline(320 根)→ 新浪(1970 根) | 回退源分钟无复权 |
| K线 日/周/月 | mootdx(回溯到上市,支持复权) | 腾讯 fqkline(800 根/段,自动按年分段回拉全部历史,支持复权) | — |
| 股票列表 | mootdx → tdxpy get_security_list(8 线程分页) |
— | 北交所来自 easyquotation 静态代码表,名称经腾讯补齐 |
| 搜索池 | 同上(与股票列表共享缓存)+ pypinyin 拼音 | — | 沪深指数取自 mootdx 全列表 |
注:腾讯 K 线接口为 ifzq.gtimg.cn 的公开端点(fqkline/mkline),直接 HTTP 调用,不经 easyquotation。
性能实测(2026-10,休市环境)
| 操作 | 耗时 |
|---|---|
| 全市场列表冷拉取(51861 条,8 线程) | 1.8~5.7s(受 mootdx 服务器波动,慢轮曾 20s) |
| 线程数对比(2/4/8/16 各 3 轮均值) | 4.8s / 2.4s / 1.9s / 5.9s(负优化)——8 为甜点 |
| 新进程命中磁盘缓存建池 | ~0.8s |
| 同进程搜索(缓存后) | ~50ms |
| 全市场实时快照(mootdx 32 线程,交易日) | ~0.3s(休市计时为协议往返上界) |
口径与已知行为(实测)
- 单位统一:量=股(ETF 为份)、额=元;已修正各源字段错位(sina
volume实为成交额、tencent成交额(万)实为元、sina 沪市指数量单位为手需 ×100)。 - mootdx 单连接独占、批量上限 60 只/次;并发靠"每线程一条连接"。
- 北交所(43/83/87/92 开头)mootdx 不支持,auto 模式自动由 eq 补齐;老北交码(83/43)sina 数据残缺(有价无开高低),需要完整数据请强制
source='tencent'。 - mootdx 的
servertime不含日期,按调用当日拼时间;交易日调用即正确。 - 全部源失败抛
QuoteSourceError(含各源失败原因)。 - 休市期间:mootdx 快照为空 → 自动回退 eq 拿最后快照。
运行测试
python -m unittest discover -s tests -v # 离线单元测试
python tests/test_live_smoke.py # 在线冒烟(需网络, 交易日效果最佳)
目录结构
quotekit/
├── pyproject.toml
├── src/quotekit/
│ ├── __init__.py # 出口: get_quotes / get_index_quotes / get_bars / get_stock_list / configure
│ ├── api.py # 实时行情编排与回退链
│ ├── bars.py # K线接口(8频度, 复权, 多源回退)
│ ├── lists.py # 交易所 A 股列表(8线程分页+三级缓存)
│ ├── search.py # 证券搜索(拼音/相似度/模糊兜底)
│ ├── sources.py # mootdx / easyquotation 实时行情适配器
│ ├── codes.py # 代码归一(sh600519 / 600519.SH / 600519)
│ ├── schema.py # 统一列定义
│ └── config.py # 全局配置
├── tests/ # 离线单测 + 在线冒烟
└── examples/basic_usage.py
Metadata
Release files for quotekit 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quotekit-0.6.0.tar.gz | 28.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quotekit-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.1 kB
Release files / quotekit-0.6.0.tar.gz
| Download URL | quotekit-0.6.0.tar.gz |
|---|---|
| Size | 28.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c7ef97d176ff43441e2d4ff74804fff58c2ea91b468c935e9e0d2c3821a592d
|
|
BLAKE2b-256 checksum How to use checksums |
f2b09acdf68c943ffdc73b3764959bc5475cc34709d05ae455b062ff816c54bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|
Release files / quotekit-0.6.0-py3-none-any.whl
| Download URL | quotekit-0.6.0-py3-none-any.whl |
|---|---|
| Size | 23.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57968861e442052b45e706537731156fc4060c4cb14d4fbbb6226a0920e43127
|
|
BLAKE2b-256 checksum How to use checksums |
605ccde6922de4cf28b7c4b82f1c95d094ffda8da7c482701f04ec3922d3499b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.12
|