集合竞价怎么做量化因子?拆解开盘前的价格、成交量与买卖力量
开盘前几分钟,竞价金额暴增、价格快速上冲,看起来像强势,9:30 却可能低开回落。问题不在数据不够,而在信号没有被拆成可验证的因子。把竞价过程留痕,再把价格、量能、稳定性和市场位置组合起来,才有机会从“看盘经验”走向可回测研究。
竞价数据不是涨跌答案,而是一张开盘前的订单地图
集合竞价反映的是某个时间窗口内,买卖双方对开盘价格的集中报价。它能提供预期变化,却不能直接等同于真实成交,更不能把一笔大单理解成确定性资金流入。
竞价因子的价值,不是预测每只股票,而是让一批股票在同一时刻具备可比较的特征。
研究时要把三个概念分开:
| 概念 | 研究含义 | 常见误区 |
|---|---|---|
| 竞价价格 | 市场对开盘价的阶段性预期 | 把高开预期当成必然高开 |
| 竞价数量 | 报价活跃度与潜在撮合规模 | 把委托量当成已成交量 |
| 竞价变化 | 预期在 9:15 至 9:25 的重新定价 | 只看最后一条,不看过程 |
数据接口怎么分工
XTick 文档中与集合竞价研究相关的入口,可以按“实时观察、细节留存、历史回测、横截面辅助”来组织。实际路由、鉴权字段和返回字段,以当前文档为准。
| 研究任务 | 接口方向 | 用途 |
|---|---|---|
| 观察实时竞价过程 | bidtime |
记录竞价阶段的时间序列变化 |
| 查看单只股票竞价细节 | biddetail |
获取价格、数量、涨跌幅等明细字段 |
| 拉取历史竞价数据 | bidhistory |
形成跨交易日样本,避免只做盘中观察 |
| 叠加大盘环境 | dayupdate |
判断当天是普涨、普跌还是结构性行情 |
| 叠加板块环境 | bk、gainian |
做行业、概念和板块内相对排名 |
如果使用 Python SDK,建议把接口调用封装成统一的数据层,不要让策略代码直接依赖某个字段名。这样字段变更、分页规则或返回格式调整时,只需要改适配层。
一套能落地的竞价因子拆解
1. 价格预期因子
最基础的特征是竞价价格相对前收盘的偏离:
auction_gap = auction_price / prev_close - 1
它回答的是“市场预期以什么幅度开盘”。但单独使用很容易追高,实际研究中可以把它做成分位数、截面排名,或与近 20 日波动率进行标准化。
gap_zscore = auction_gap / rolling_std_20
同样的 2% 高开,放在低波动股票和高波动股票上,含义并不一样。
2. 竞价活跃度因子
竞价金额不能脱离股票自身流动性。更稳妥的做法是与历史成交额比较:
amount_ratio = auction_amount / mean(amount_20)
也可以用竞价金额除以流通市值,形成跨股票更容易比较的强度指标。这里要特别处理新股、停牌复牌股、长期低流动性股票,否则极端比值会制造大量伪信号。
3. 买卖失衡因子
如果接口提供买卖委托数量或买卖盘深度,可以构造:
imbalance = (buy_qty - sell_qty) / (buy_qty + sell_qty + 1e-8)
如果接口只有竞价成交数量,没有完整的买卖委托字段,就不要强行命名为“资金流入”。可以把它定义为“竞价成交强度”,并在文章、代码和回测报告中保持口径一致。
4. 竞价路径因子
只截取 9:25 最后一条数据,会丢掉一部分信息。更有区分度的特征,往往来自价格路径:
| 路径特征 | 计算思路 | 解释 |
|---|---|---|
| 竞价斜率 | 价格对时间做线性拟合 | 预期是持续抬升还是突然拉升 |
| 竞价波动 | 路径价格标准差 / 均值 | 报价是否稳定 |
| 重估幅度 | price_925 - price_920 |
9:20 后预期如何变化 |
| 量价同步 | 价格变化与数量变化的相关性 | 价格上行是否伴随活跃度提升 |
持续抬升和最后一分钟突然冲高,表面涨幅相同,交易含义可能完全不同。
XTick 的实时数据适合在采集阶段保存多时间点快照,再在离线研究中计算路径特征。不要只保存最终值,否则后续无法重建竞价过程。
5. 相对位置因子
集合竞价信号很容易受到市场风格影响。单只股票高开 1%,可能是强势,也可能只是当天全市场都高开。建议加入:
- 股票竞价涨幅减去市场竞价中位数;
- 股票竞价强度减去所属行业中位数;
- 个股竞价量能排名与板块竞价量能排名的差值;
- 高开股票占比、涨停预期股票占比等市场广度指标。
相对因子通常比绝对值更适合横截面选股,因为它减少了指数涨跌和市场情绪对结果的干扰。
从接口到因子的最小研究流程
XTick 实时采集
↓
按交易日、股票、时间戳保存快照
↓
统一价格、数量、复权与停牌口径
↓
构造价格、量能、路径、失衡、相对位置因子
↓
按 9:25 截面排序,生成候选组合
↓
以 9:30 后可成交价格进行回测
↓
加入滑点、手续费、涨跌停和容量约束
下面是一段适配层示例。它故意不把接口地址和鉴权参数写死,实际使用时按 XTick 文档中的当前定义替换;研究代码只接收标准化后的 DataFrame。
from __future__ import annotations
import requests
import pandas as pd
def fetch_xtick_data(api_url: str, token: str, trade_date: str) -> pd.DataFrame:
response = requests.get(
api_url,
params={"token": token, "date": trade_date},
timeout=10,
)
response.raise_for_status()
payload = response.json()
rows = payload.get("data", payload)
frame = pd.DataFrame(rows)
frame["timestamp"] = pd.to_datetime(frame["timestamp"])
frame["auction_gap"] = frame["auction_price"] / frame["prev_close"] - 1
frame["amount_ratio"] = frame["auction_amount"] / frame["amount20_mean"]
return frame
def build_cross_section(frame: pd.DataFrame) -> pd.DataFrame:
result = frame.copy()
result["gap_rank"] = result["auction_gap"].rank(pct=True)
result["amount_rank"] = result["amount_ratio"].rank(pct=True)
result["stability_rank"] = result["auction_stability"].rank(pct=True)
result["score"] = (
0.4 * result["gap_rank"]
+ 0.35 * result["amount_rank"]
+ 0.25 * result["stability_rank"]
)
return result.sort_values("score", ascending=False)
真实项目中,payload 的字段映射、异常状态和分页逻辑应放在适配层。策略层只使用统一字段,避免把“接口格式”误当成“因子逻辑”。
回测最容易踩的五个坑
时间穿越
9:25 形成的信号,不能使用 9:30 之后才知道的开盘价、开盘成交量或首分钟涨跌。开盘价可以作为执行结果,也可以作为标签,但不能同时作为 9:25 的输入特征。
把委托当成交
竞价期间的委托可能撤单、改价,也可能没有完全撮合。字段含义必须记录清楚,委托量、匹配量、成交量不能混用。
忽略交易制度
涨跌停、停牌复牌、风险警示、上市首日、除权除息和不同市场的撮合规则,都会影响竞价价格和可成交性。回测过滤条件应单独写出来,不要藏在一行复杂代码里。
只测一个市场阶段
竞价因子常常在强趋势、情绪高涨时表现突出,在震荡或快速下跌阶段失效。至少要做滚动窗口、牛熊分层和行业分层,观察收益是否依赖某一段行情。
忽略容量和成本
小市值股票的回测收益,可能经不起滑点和冲击成本。报告中应同时展示毛收益、净收益、换手率、最大回撤、收益波动、分组收益和成交容量。
一个更稳妥的组合方式
不要把单一因子阈值直接写成“高开就买”。可以把信号拆成三层:
| 层级 | 作用 | 示例 |
|---|---|---|
| 方向层 | 判断预期方向 | auction_gap、相对市场涨幅 |
| 质量层 | 判断信号是否稳定 | 路径波动、量价同步、竞价持续性 |
| 风险层 | 判断是否值得执行 | 流动性、涨跌停距离、行业拥挤度 |
只有方向、质量和风险同时通过,才进入候选池。这样做的好处是,因子失效时可以定位到底是预期错了、信号不稳定,还是交易成本吞掉了收益。
知识点图文海报:集合竞价因子挖掘四句话
数据层:保存 9:15—9:25 的竞价快照,不只保存最后一条。
因子层:价格看偏离,数量看强度,路径看持续,相对位置看环境。
研究层:9:25 截面生成信号,9:30 之后按可成交价格回测。
风控层:委托不等于成交,竞价强不等于开盘后继续强。
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ XTick 竞价流 │ → │ 清洗与留痕 │ → │ 因子计算 │
│ bidtime │ │ 时间/字段/状态 │ │ 价格/量能/路径 │
└──────────────┘ └──────────────┘ └──────┬───────┘
↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 交易执行 │ ← │ 回测验证 │ ← │ 截面排序 │
│ 滑点/容量/风控 │ │ 分层/成本/稳定 │ │ 9:25 冻结信号 │
└──────────────┘ └──────────────┘ └──────────────┘
写在最后:把“盘感”翻译成数据结构
集合竞价最值得挖的,不是某个神奇阈值,而是预期如何形成、如何变化、是否得到量能支持,以及它在市场横截面中的相对位置。
能被保存的盘口,才有机会变成能被检验的因子;能被检验的因子,才值得进入实盘候选池。
发布或接入前,请以 XTick 当前接口文档、交易所规则和实际返回样例为准,特别核对时间戳、字段含义、数据权限、复权口径与历史数据完整性。

