VicroCode
让代码创造价值
VicroCode是一个轻量级代码在线发布、交易平台,开箱即用,免部署、免服务器、免备案,支持接入智能体、通用管理系统、游戏等多种项目
稍候片刻,您可先学习AI编程手册
正在加载中...

市场信息

[Python] A 股盘前 10 分钟:集合竞价数据对策略的实际价值有多大?

这个问题我问过自己很多次。9:15 到 9:25 ,A 股在统一撮合,开盘价 9:25 就定了。但大多数行情接口在这个窗口返回空值或者直接报错。你的策略如果依赖开盘价做决策,你拿到的"开盘价"到底是 9:25 的竞价结果,还是 9:30 连续竞价的第一笔成交?这两个东西的含义完全不同。 为了搞清楚这个问题,我把个人开发者能接触到的数据源基本试了一遍。

www.v2ex.com · 2026-09-08T08:05:29+00:00

这个问题我问过自己很多次。 9:15 到 9:25 ,A 股在统一撮合,开盘价 9:25 就定了。

但大多数行情接口在这个窗口返回空值或者直接报错。你的策略如果依赖开盘价做决策,你拿到的"开盘价"到底是 9:25 的竞价结果,还是 9:30 连续竞价的第一笔成交?

这两个东西的含义完全不同。为了搞清楚这个问题,我把个人开发者能接触到的数据源基本试了一遍。

AkShare 在 9:15 直接抛 ValueError: Length mismatch ,Tushare 不报错但价格字段空到 9:30 ,Baostock 没有实时路径,聚宽和米筐的分钟线从 9:30 才开始,券商 Level-1 封装把竞价虚拟字段过滤得干干净净,机构 Level-2 有完整数据但个人拿不到权限。最后找到一家在这个窗口有数据的,REST 端点,不需要机构资质。

下面是我在 9:15 到 9:30 之间做的完整实测,标的是寒武纪( 688256.SH )。这 10 分钟的静默,代价是什么 大多数人知道"接口在 9:15 没数据",但没把代价算清楚。

信号迟到 5 分钟。 9:25 交易所主机完成统一撮合,开盘价确定。

你的接口 9:30 才给出第一个价格。高波动日,5 分钟可以差 3-5 个点。

K 线量从第一根 bar 就是混的。实测 1 分钟 K 线:09:30:00 那根的 volume 是 596 手,全是集合竞价统一撮合的量; 09:31:00 起才是连续竞价,第一根就有 2551 手。

如果你用"首根 K 线量 vs N 日均量"判断开盘强弱,你在拿两种完全不同机制产生的量做比较。你不知道那个 "open" 是哪一刻产生的。

是 9:25 统一撮合的价格,还是 9:30:01 连续竞价的第一笔?前者是全市场博弈的均衡点,后者是一笔主动单推动的瞬时成交。

算止损、算缺口、算回测基准,含义完全不同。 9:25 那一下,才是真正的开盘 券商 App 显示的开盘价是 9:25 产生的,不是你接口里拿到的 9:30 第一笔。

9:15 到 9:20 可报可撤,9:20 到 9:25 只许报不许撤,9:25 交易所主机按最大成交量原则算出一个价格——这才是开盘价。 9:30 开始的连续竞价是另一套逻辑:一笔订单冲进来,找到对手方就成交。

一个细节说透区别:上交所数据显示,9:20 到 9:25 不可撤单阶段,每天仍有约 1838 笔撤单尝试被系统作废。在撮合前的最后一刻,还有人试图撤回申报,改变供需结构。

这 10 分钟的博弈强度,远超你从 9:30 的 K 线上看到的。找到的那家数据源,窗口内全程实测 2026 年 9 月 3 日,我从 9:15 到 9:30 ,每隔约 2 分钟调一次接口,共 7 个采集点。

9:15 — 竞价开窗 GET /ai-market-guide/ symbols=688256.SH { "last_price": "1120", # 虚拟撮合价,非昨收 "prev_close": "1108", "volume_24h": "0", "high_24h": "0", "low_24h": "0" # open 字段:不存在 } GET /ai-market-guide/

symbol=688256.SH { "bids": [["1126","35"], ...], "asks": [["1126","35"], ...] # bid = ask ,虚拟撮合特征 } GET /ai-market-guide/ symbol=688256.SH { "trades": [] # 无成交记录 } 三个信号同时出现: open 字段缺失, volume_24h 归零,depth 里买一等于卖一,trades 为空。

这是集合竞价进行中的 API 状态,和 9:30 连续竞价是两套完全不同的字段结构。 9:20 — 撤单截止 GET /ai-market-guide/

symbol=688256.SH { "bids": [["1126","133"], ...] # 量从 44 跳到 133 } 撤单通道关闭,只有新单能进,没有旧单能出。深度量开始单调递增。

9:24 — 最后 1 分钟 GET /ai-market-guide/ symbol=688256.SH { "bids": [["1126","324"], ...] # 量从 179 急涌到 324 } 量的积累轨迹: 时间 bid[0]量 增量 9:15 35 — 9:20 133 +89 9:24 324 +145 这条曲线在 9:30 之前 5 分钟就成型了。

9:20 后无法撤单,这个阶段的行为比开盘价本身更真实。 9:25 — 统一撮合完成 GET /ai-market-guide/

symbols=688256.SH { "open": "1126", # 字段首次出现 "volume_24h": "596", # 竞价总成交量 "high_24h": "1126", "low_24h": "1126" # 三价合一 } GET /ai-market-guide/ symbol=688256.SH { "trades": [{ "price": "1126", "quantity": "596", "side": "neutral", # 竞价统一撮合专属标记 "timestamp": 1788398703000 }] } 时间戳精确到秒:09:25:03 。

open 字段出现、 side=neutral 出现、depth 恢复双边不对称——三个事件同时发生。 9:30 — 连续竞价开始,K 线真相 bar① 09:30:00 open=1126 high=1126 low=1126 close=1126 volume=596 bar② 09:31:00 open=1124.68 high=1129.86 low=1111 close=1112 volume=2551 09:30:00 这根 bar 四价合一,volume 全是集合竞价量。

连续竞价从 09:31:00 才开始。把这根 bar 和 09:31:00 之后的 bar 放在一起做量价分析,信号从第一根 K 线就是失真的。

三个字段信号,判断数据来自哪个阶段 open 字段是否存在。竞价进行中, open 不在响应体里——不是 null ,是字段本身缺失。

9:25 后字段首次出现。用字段存在性判断阶段,比同步本地时钟可靠。

side 是否为 neutral 。 9:25 后 trades 里最新一条的 side 是 neutral 。

连续竞价开始后只有 buy / sell 。这个语义来自 FIX 协议——集合竞价没有主动方。

大多数数据源的成交记录不区分这两种成交,你拿到一条记录不知道它来自 9:25 还是 9:30:01 。 high_24h == low_24h 。

竞价刚结束时,high 和 low 都等于 open 。三价合一是竞价 bar 的专属特征。

连续竞价开始后立刻分叉。代码 import os import requests BASE_URL = "/ai-market-guide/ HEADERS = {"X-API-Key": os.getenv("TICKDB_API_KEY")} def check_auction_phase(symbol: str) -> str: try: ticker_resp = requests.get( f"{BASE_URL}/v1/market/ticker", headers=HEADERS, params={"symbols": symbol}, timeout=10, ) ticker_data = ticker_resp.json()["data"][0] trades_resp = requests.get( f"{BASE_URL}/v1/market/trades", headers=HEADERS, params={"symbol": symbol}, timeout=10, ) trades = trades_resp.json()["data"]["trades"] if "open" not in ticker_data: return "auction" if trades and trades[0].get("side") == "neutral": return "closed_auction" return "continuous" except requests.RequestException as e: print(f"请求失败: {e}") raise 核心逻辑就是 "open" not in ticker_data 这一行。

字段存在性就是状态机。集合竞价数据到底值多少 回到开头的问题。

实测之后,我的判断是: 把信号提前 5 分钟。 9:25 竞价完成,你可以立刻知道高开还是低开、竞价量是大是小,不用等到 9:30 。

读懂量的积累过程。 9:20 撤单截止前后的量跳变幅度,反映不可撤单阶段有多少坚定买入;最后 1 分钟的急涌幅度,反映临近清算时市场情绪是否在加速集中。

这个曲线 9:30 之前就能读。识别重大事件后的市场态度。

财报、监管公告、隔夜美股大跌之后,集合竞价是市场第一次集中表态的窗口。价格飘移速度、撮合价稳定性、不可撤单阶段量的急增幅度——这些过程数据能区分"信息完全消化"和"分歧极大时的脆弱均衡",开盘价本身区分不了。

让风控有可靠的价格基准。止损单挂在"开盘价基础上",这个开盘价必须是 9:25 确定的那个。

如果你的风控系统在 9:25 需要计算持仓市值,用 9:30 的连续竞价价格会有几分钟延迟。回测数据质量的基础保障。

如果你用含集合竞价量的 09:30:00 bar 做"开盘强度"指标,回测曲线存在系统性偏差。用 trades 原始记录区分竞价和连续竞价成交,是修正这个偏差的唯一办法。

说几个我自己的判断,不一定对: 免费行情接口在集合竞价窗口的沉默,本质上是一种数据平权失败。机构用 Level-2 能看到竞价过程,个人开发者看到的是空值。

这 10 分钟的信息差,对开盘策略的影响被严重低估了。大多数个人开发者的开盘策略,从来没有见过真正的开盘价。

他们分析的是 9:30:01 的第一笔连续竞价成交,然后把它标记为 "open"。用含集合竞价量的 09:30:00 bar 做"开盘强度"因子,回测曲线存在系统性偏差。

这个偏差的方向和幅度,很多人可能从来没验证过。如果你也在做 A 股盘前策略,建议下一个交易日 9:15 到 9:30 自己跑一遍。

数据验证这一步,永远值得比策略开发花更多时间。参考资料 :上交所 LDDS Level-1 接口规范、深交所 STEP 接口规范、FIX 协议 Aggressor-Side 字段处理规范

返回 AI 市场导读

来源:v2ex.com