1. 合集第二篇:这次补上的三类数据,是短线策略真正缺的东西
做财经指标API接口合集这个系列,第一篇文章发布之后,很多朋友私信我说接口清单确实有帮助,但真到自己动手写策略的时候,还是有几个坎过不去:分钟数据到底怎么拉才算全、买卖五档数据用哪种方式拿才实时、竞价数据要抓哪些字段才有用。这些问题不解决,接口文档写得再清楚也只是纸上谈兵。
这篇就专门把分钟数据、买卖五档和竞价数据这三类拆开讲。这三类数据放在一起看很有意思:分钟数据是回测和盘中策略的地基,买卖五档是实时盘口观察的核心,竞价数据则是开盘前判断情绪的重要参考。把它们串起来,基本就是一套“盘前看竞价、盘中看五档、盘后和回测看分钟K线”的完整数据闭环。
内容上我会直接给可运行的代码样例,也会把我实际踩过的坑一并写出来。不管你是刚接触接口对接的初学者,还是已经在写策略的老手,这篇都值得花几分钟翻一遍。
1.1 上一篇里大家问得最多的问题
第一篇把常用接口按功能分了类:行情快照、历史K线、财务指标、资金流向。当时评论区里高频出现的问题有三个:一是K线接口只能拿到日线,做日内策略完全没有分钟数据可用;二是五档行情不知道哪家稳定,怕拿到的是延时数据;三是竞价数据完全不知道从哪个接口取,只能在行情软件里肉眼盯盘。
这些问题说到底是同一个核心:大家需要的不是更多的接口地址,而是怎么把数据正确、稳定地拿回来并落地使用。所以这期我改变了写作方式,不再铺开列表,而是把三类数据逐个做深度拆解,从接口设计到本地落库都有。
1.2 三类数据在整个量化流程里的定位
先明确一个概念,这三类数据不是同一类用途。分钟数据是历史数据,主要用来回测和策略因子计算;买卖五档是实时数据,主要用来做盘口监控、主力异动识别、下单执行辅助;竞价数据是极短窗口的快照数据,主要用来做开盘情绪判断和日内方向预判。
我自己做A股日内策略的流程是这样的:昨晚复盘选股池,今天9:15开始拉竞价数据,9:25确认开盘价和匹配量,9:30开盘后切到五档数据观察盘口变化,盘后用分钟数据做当天的策略回测和参数修正。这个过程里三类数据缺一不可,少了任何一环,策略都像缺了一条腿走路。
2. 数据源选型:免费接口和付费接口怎么取舍
这一节我直接说结论:我目前用的是“免费源做备份 + 廉价付费源做主数据”的组合。很多人一上来就想找全免费的数据源,我能理解,但做过一段时间之后你会发现,免费数据源节省的是钱,消耗的是时间,而且消耗的时间往往比省下来的钱更贵。
数据源选型不能只看“能不能拿到数据”,还要看“数据全不全”、“稳不稳定”、“字段是否是原始值”、“有没有技术支持”。这几点在真正做策略的时候比接口是否免费重要得多。
2.1 免费源的风险清单
免费源最大的问题不是速度,而是“文档和实际返回不一致”。我遇到过两次印象特别深的情况。第一次,文档里写的返回字段是last_price,实际返回的是price,字段名不同改一下映射表就能解决,但如果你的代码里写死了字段名,就得动一堆逻辑。第二次更坑,免费接口的请求频率限制会悄悄变化,今天允许每3秒一次,下周变成每10秒一次,你的日志里开始大量出现429状态码,不仔细排查根本发现不了。
还有一个容易忽视的问题:免费接口偶尔会停服维护,而且没有任何提前公告。维护期间正好是开盘时间,你的策略就只能干看着。所以免费源不是不能用,而是不能把它当生产环境的唯一依赖。
2.2 付费源的隐藏成本
付费源也不是一劳永逸。按量计费适合前期测试,但分钟数据拉多了,每次请求都在烧钱。包月订阅看起来更可控,但要注意套餐里包含的究竟是“真正的五档”还是“五档快照”,以及“tick级数据”到底是逐笔成交还是500毫秒切一次片的快照数据。这两个概念差的不是一点半点,拿到手之后处理逻辑完全不同。
另一个容易被忽略的成本是权限拆分。很多平台把K线、五档、竞价数据分开售卖,单独看每个都不贵,加在一起就肉疼了。我自己选型时有一个原则:先把真正需要的数据列出来,再留一点冗余预算,最后算总价,而不是看到哪个套餐便宜就买哪个。
2.3 高性价比的组合方案
我目前的组合是这样:历史分钟K线用某个基础套餐,免费额度相对充足,日常增量拉取够用;五档数据用另一个平台的WebSocket推送,只订阅持仓股和自选股,不订阅全市场;竞价数据用HTTP快照在9:15到9:25这段时间高频轮询,开盘后立刻停止。
这样拆的原因是不同数据源在各自擅长的场景下延迟和成功率确实有差异。把五档拆到WebSocket推送源,能减少HTTP轮询一半以上的请求量,也避免了快照接口因为频繁请求被封禁的风险。数据源不是越贵越好,也不是全都要用一个平台,按场景拆分使用往往性价比最高。
3. 分钟数据接口:复权、频率、批量拉的底层逻辑
分钟数据是三类数据里最“看着简单、做起来复杂”的一类。接口返回一串JSON数组,看起来就是时间、开高低收、成交量,但真正对接过就知道,复权、时区、交易时段、增量更新这些问题一个比一个麻烦。
3.1 复权因子会让你的K线对不上账
很多人在拉分钟数据时,默认参数是“不复权”或者“前复权”。做回测的时候,一旦股票除权除息,除权那天的一根K线会突然跳空,如果策略里用了均线、布林带这种依赖价格连续性的指标,跳空会被误判成突破或者异常,回测结果直接失真。
这里有一个容易忽视的细节:分钟线本身没有独立的复权因子,它是按日线复权因子换算出来的。如果数据平台没有提供日线除权因子,分钟线的前复权就可能不准。所以我的经验是:做回测时统一用“后复权”数据,因为后复权从上市首日开始连续复权,数据序列最稳定;盘中监控看实时价格时再用“不复权”原始价,因为交易下单需要的是真实价格。两种场景分开处理,能避免很多策略层面的干扰。
3.2 接口设计的频率参数与映射
常见分钟频率有1分钟、5分钟、15分钟、30分钟、60分钟,部分平台还支持3分钟、45分钟等非常规频率,但不是所有都支持。我调接口前一定会先看文档里的频率枚举值,不同平台字段名差异很大,有的用1m,有的用1min,有的直接传数字1。
以Python的requests为例,拉最近几根1分钟K线的代码可以这样写:
import requests import time BASE_URL = "https://your-data-source/api/v1/line" def get_min_kline(symbol: str, freq: str = "1m", count: int = 10): params = { "symbol": symbol, "freq": freq, "count": count, "ak": "your_api_key", "ts": int(time.time() * 1000) } resp = requests.get(BASE_URL, params=params, timeout=5) data = resp.json() if data.get("code") != 0: raise RuntimeError(data.get("msg", "unknown error")) return data["data"]["list"]返回的list通常包含time、open、high、low、close、volume、amount这几个字段。有一个细节必须提醒:很多平台返回的open、close是字符串类型,比如"7.32",不转换成float型,后续算指标时会报错或者得出错误结果。我在代码里会统一加一层类型转换。
3.3 分钟数据怎么接进本地库
数据量上来之后,每次全量拉取不仅慢,还容易触发限频。我的做法是“首次全量 + 定时增量”。建一张kline表,主键是(symbol, freq, time),首次同步时拉最近N根K线写入;增量更新时每隔3到5分钟拉最近2根,按时间戳比对后写入。
增量拉取有一个关键技巧:把起始时间往前多拉1根。因为接口落数据经常有延迟,当前这根1分钟K线要等这分钟彻底结束后才完整可用,如果恰好在这个窗口期拉数据,拉到的最后一根K线数据可能是不完整的。多拉1根再靠主键去重,能有效避免漏数据,这个习惯帮我少踩了很多坑。
4. 买卖五档数据:HTTP快照和WebSocket推送的取舍
买卖五档是短线玩家最关心的数据之一。想做实时盘口监控、主力资金异动识别,没有五档数据基本无从下手。但五档数据的获取方式和分钟数据完全不同,它的实时性要求更高,接口对接方式也更复杂。
4.1 五档和十档不是数字差两个那么简单
A股常见的level1行情是五档,level2是十档,但两者的差距不只是档位数。五档只能看到买卖双方各挂五档的价格和量,十档能看到更深的挂单分布,更重要的是,Level2还有逐笔成交明细,可以还原每一笔单子的成交路径,这对识别大单拆分、主力进出有质的区别。
但Level2数据源通常按年费和License授权收费,个人开发者要拿到正经的Level2授权,门槛和成本都不低。所以我的建议很现实:如果只是个人研究,五档快照够用;如果做高频或实盘辅助,再去考虑Level2。不要一开始就all in贵的。
4.2 HTTP快照轮询:低成本的准实时方案
HTTP快照的方式是,每次请求都返回当前时刻完整的五档数据。它的优点是实现简单、部署成本低、不容易因为连接断开丢数据;缺点是只能做到准实时,每次请求之间有一个轮询间隔,如果轮询太频繁又会触发限频。
一个简单的五档快照拉取代码如下:
def get_orderbook(symbol: str): params = {"symbol": symbol, "ak": "your_api_key"} resp = requests.get("https://your-data-source/api/v1/depth", params=params, timeout=5) data = resp.json() if data.get("code") != 0: raise RuntimeError(data.get("msg", "unknown error")) return data["data"]返回体大概长这样:
{ "symbol": "600000", "ts": 1693000000000, "bids": [ {"price": 7.32, "volume": 1200}, {"price": 7.31, "volume": 800} ], "asks": [ {"price": 7.33, "volume": 900}, {"price": 7.34, "volume": 1500} ] }轮询频率我建议3秒一次比较安全,具体取决于数据源限频规则。如果只是监控盘口变化,不需要每次都全量处理,算两帧之间的差量就够了,能大幅减少计算开销。
4.3 增量推送:真正的实时盘口要这么写
如果做的是实时监控或者高频交易辅助,HTTP轮询的延迟不能满足需求,这时候需要走WebSocket。订阅一个symbol后,服务端会持续推送增量消息,格式一般类似:
{"symbol":"600000","type":"snapshot","data":{...}} {"symbol":"600000","type":"update","data":{"side":"bid","pos":2,"price":7.32,"volume":800}}增量推送不能直接覆盖本地盘口,要做合并。规则是:收到snapshot就把整块数据覆盖到本地盘口,收到update则只更新对应档位。这个“本地维护盘口”的过程看着简单,但很容易踩坑。比如有些推送源的档位序号从1开始而不是从0开始,如果没对齐,你更新的就是错误的档位。
另一个更隐蔽的问题是:WebSocket连接一旦断开,重连后如果只等增量推送,中间丢失的增量消息会导致本地盘口失真。我的方案是维护一个本地时间戳,重连成功后先拉一次snapshot校准,再开始接收增量。这样既保证了实时性,又避免了数据不一致。
5. 竞价数据:开盘前最容易忽略的“黄金窗口”
竞价数据是A股特有的一个数据场景,很多刚接触接口开发的朋友一开始根本不会想到去取它。但做过短线的人都知道,9:15到9:25这10分钟里蕴含的信息量,可能比开盘后半小时的数据更值得关注。
5.1 集合竞价的时间规则与数据特点
A股集合竞价分两个阶段:9:15到9:25是开盘集合竞价,14:57到15:00是收盘集合竞价。其中9:20之前可以撤单,9:20之后不能撤单。对数据接口来说,9:15到9:20之间的虚拟匹配价会一直跳动,因为可以撤单,盘口会出现很多“虚假挂单”;9:20到9:25之间挂单锁定,价格开始收敛,最终在9:25撮合出开盘价。
所以抓竞价数据,通常要在9:15到9:25之间以较高频率轮询,比如每1秒拉一次快照,把当前的虚拟匹配价、匹配量、买卖双方未匹配量都记录下来。9:25之后竞价结束,这些数据基本定格,再拉也拉不到更多信息了。
5.2 竞价数据里能挖出什么指标
我自己常用的竞价指标有三个:
- 竞价匹配量:反映参与集合竞价的资金规模。量特别大,说明当天该股票的关注度极高,可能是利好刺激,也可能是多空分歧剧烈。
- 竞价涨幅:9:25竞价价格相对昨日收盘价的涨跌幅。偏离过大说明情绪极端,追高风险上升。
- 未匹配买单和卖单量:如果卖单未匹配量特别大,意味着开盘后可能有一波抛压,反之买单未匹配量大则可能开盘拉升。
这些指标单独看没有绝对意义,需要结合个股的历史数据和当日板块环境综合判断。比如昨晚选好的一批股票,今天竞价涨幅超过5%且匹配量异常放大,我一般会直接放弃追高。
5.3 竞价数据抓取与落库实践
竞价数据我是以“每个交易日一个表”的方式存储的,字段包括symbol、time、price、volume、bid_vol、ask_vol。这里的price是当前虚拟匹配价,volume是当前匹配量,bid_vol是未匹配买单量,ask_vol是未匹配卖单量。
代码片段类似:
def fetch_auction(symbol: str): params = {"symbol": symbol, "ak": "your_api_key", "type": "auction"} resp = requests.get("https://your-data-source/api/v1/snapshot", params=params, timeout=5) data = resp.json() return data["data"]轮询频率我建议1秒1次,9:15到9:25一共600秒,理想情况下一个股票会有600个时间点记录。但要注意,竞价的这段时间恰好是数据源整体的峰值高并发窗口,限频风险远高于其他时段。我的经验是提前做一次压测,确认数据源在这个频率下能稳定返回,如果不行就降低到2秒一次,优先保证数据可用性。
6. 高频调用下绕不过去的坑:限频、字段、时间戳
前面讲了三类数据各自的对接方式,这一节专门讲坑。因为即使接口文档写得再详细,实际对接中总会遇到一些文档里没写、但一旦遇到就能卡你半天的问题。
6.1 限频被卡之后怎么办
被限频最典型的特征就是HTTP 429或者返回code=403。看到这个状态码别慌,先做两件事:第一,看服务端返回的Retry-After头,它告诉你要等多久才能继续请求;第二,翻自己日志里的请求频率,看是哪个任务集中爆发导致了限频。
我踩过最大的坑是,本地5个脚本同时运行,每个脚本单独看请求频率都在合法范围内,但合起来的总请求量翻了几倍,直接被限频。解决方法是把所有的请求集中到一个统一调度模块,由它统一管理请求频率和鉴权,而不是每个脚本各发各的。这样既能精准控制频率,也方便排查问题。
6.2 字段类型和精度坑
不同平台返回的数字字段可能是number、string,甚至是带单位的字符串。我遇到过把成交量返回成"123.4万"的情况,看起来是人读友好,程序处理起来却很要命。所以对接任何接口,第一步一定是先抽样打印原始返回,确认字段类型后,再写解析逻辑。
价格精度也要注意。A股价格最小变动单位是0.01元,但有些平台返回的是保留4位小数的字符串,比如7.3200,用float解析没问题,但如果直接拿去做SQL的where条件,可能因为浮点表示误差匹配不上。我一般用decimal或者按“分”为单位存整数,彻底规避浮点精度问题。
6.3 时间戳与时区问题
分钟数据和五档数据返回的时间戳,大部分是Unix毫秒,但也有些平台返回秒级时间戳,甚至直接返回字符串"2026-01-01 09:30:00"。统一处理方法是我定义了一个时间解析入口,所有时间戳都经过它转换成本地时区后,再以%Y-%m-%d %H:%M:%S格式存库。
还有一个容易踩的坑是日切问题。股票数据的时间范围是交易时段内,但很多平台在夜间会返回昨天的最后一帧快照。如果不判断“当前时间是否在交易时段内”,你拉到的就是昨天的旧数据。我一般会在拉快照后加一个简单的时间窗口判断,非交易时段直接跳过,既能省配额也能避免脏数据。
7. 关于这个接口合集,我的下一步打算
到这里,分钟数据、五档数据、竞价数据的对接已经基本串起来了。下一步我计划把这几类数据统一封装成一个Python包,对外提供get_kline、get_depth、get_auction三个方法,内部做配额统一控制和自动重连。这样不管底层数据源怎么换,上层的策略代码都不用改。
另外,这套东西后续还可以往两个方向扩展:一是把盘中实时数据接入可视化看板,做一个自用的盘口监控页面;二是把竞价数据和分钟数据联合起来,生成一份每日开盘前的“市场情绪快照”,辅助决定当天的整体仓位。
根据我这几个月来回对接数据源的经验,最深的感受是:做数据接口对接,最怕的不是接口本身复杂,而是文档和实际返回不一致。文档写得天花乱坠,实际返回里字段名错一个、类型变一下,就能让你排查一整天。所以每次对接新接口,我都在动手写代码之前先花10分钟把原始返回完整打印出来,对着文档逐字段核对。这10分钟看着是浪费,实际上能省下后面一整天的排错时间。