第 11 讲:高频数据低频化特征工程:微观结构与 OFI
本讲核心目标:
深入买方核心 Alpha 腹地,理解高频数据低频化(High-Frequency to Low-Frequency)的战略价值;从微观市场结构经典文献(Kyle 模型与 Cont-Kukanov-Stoikov 论文)出发,严格推导限价订单簿(Limit Order Book, LOB)的状态转移方程;掌握单档与多档订单流不平衡(Multi-Level OFI)、**聪明钱因子(Q-Factor)**的日内微观聚合降维算法;使用 Polars 编写毫秒级微观特征工程引擎。
1. 为什么“高频低频化”是现代买方量化的核心护城河?
在量化投资界,存在一个著名的策略“三元悖论”:
- 纯日频/周频低频量化:资金容量大(可承载数百亿规模),但信息粒度粗糙,因子同质化严重(夏普比率通常在 1.5~2.2 之间);
- 纯微秒级高频高频交易(HFT):夏普比率极高(经常达到 5.0~8.0 以上),但容量极小(通常仅能容纳数千万资金),且极其依赖昂贵的 FPGA 硬件与机房极速托管。
高频低频化 (HF to LF) 的破局之道
├── 1. 数据源头: 采集全市场 3秒一次的 Level-2 逐笔快照与订单簿深度数据 (日均数十 GB)
├── 2. 算力清洗: 在微观盘口状态机中,提炼出具有极高信噪比的微观特征 (OFI、主买大单净额、挂单撤单比)
└── 3. 降维聚合: 将日内 4,800 个微观快照按统计量压缩为日频/周频特征,输入多因子中性化模型中调仓!
结果: 既规避了纯高频的毫秒级容量天花板,又汲取了高频微观结构的高信噪比,实现了“百亿容量 + 高夏普”的完美融合!2. 经典学术文献:从 Kyle 模型到 Cont-Kukanov-Stoikov (2014)
- 知情交易者微观价格冲击:
Kyle, A. S. (1985). Continuous Auctions and Informed Trader. Econometrica.
核心贡献:提出经典的 Kyle 模型,证明价格变动与净订单流成正比:。参数 (Kyle's Lambda)直接度量了市场的非流动性与逆向选择风险。 - 订单流不平衡(OFI)的数学奠基:
Cont, R., Kukanov, A., & Stoikov, S. (2014). The Price Impact of Order Book Events. Journal of Financial Econometrics.
核心贡献:首次从限价订单簿(LOB)所有微观事件(限价单、市价单、撤单)严格推导了净订单流不平衡(Order Flow Imbalance, OFI),并在实证中证明 OFI 对中间价变动的解释力()高达 60%~80%! - 订单毒性与信息知情概率(VPIN):
Easley, D., López de Prado, M. M., & O'Hara, M. (2012). Flow toxicity and liquidity in a high-frequency world. The Review of Financial Studies.
3. 订单流不平衡(Order Flow Imbalance, OFI)底层数学推导
在连续竞价时段,价格变化的微观物理本质是挂单簿(Limit Order Book, LOB)中买卖双方委托队列的消耗与推进。
3.1 买卖盘口状态转移方程
设在第
同理,对卖方盘口推导卖方委托净消耗量
3.2 净订单流不平衡(OFI)
第
:表明在微观层面,买方相对卖方的最佳报价供需变化为正,价格具备向上的微观推动势能; :表明微观卖方挂单抛压沉重。
4. 日内高频快照向低频特征的聚合算法
在 A 股,每个交易日(09:30-11:30, 13:00-15:00)每只股票会产生 约 4,800 个 Level-2 3秒快照。
4.1 算法一:全天累计标准化 OFI 因子(Norm OFI)
将全天 4,800 个快照的
4.2 算法二:聪明钱因子(Smart Money / Q-Factor)
除了 L2 挂单簿,分钟级成交量微观模式中隐藏着散户与机构的交锋踪迹。
- 行为机理:机构大资金下单倾向于使用算法拆单(VWAP/TWAP),单笔成交量大,买入时更具耐受力;散户交易多为小额随机冲动。
- 构建步骤:
- 将每日 240 根分钟 Bar 按**成交量与价格变动的复合强度(Smart Metric
)**降序排列; - 截取前 20% 成交量最集中的“聪明钱交易时段”;
- 计算该时段的成交量加权平均价
与全天成交量加权平均价 的比值: - 经济含义:
显著大于 1 时,说明主力资金在全天相对高位依然在坚决买入,后续动能充沛。
- 将每日 240 根分钟 Bar 按**成交量与价格变动的复合强度(Smart Metric
5. 动手实操:高频 Level-2 订单流微观特征提取器
下面的 Python 模块模拟全天 4,800 条高密度快照,示范 Cont-Kukanov-Stoikov 订单流不平衡(OFI)计算与日频降维聚合流水线。
在项目根目录运行 PYTHONPATH=tutorial python3 -m examples.lecture_11_high_freq_to_low_freq。依赖安装、共享模块和数据契约见项目说明。
"""
lecture_11_high_freq_ofi_engine.py
Level-2 订单簿订单流不平衡 (OFI) 模拟与高频低频化聚合计算引擎
"""
from datetime import datetime, timedelta, date
import time
import numpy as np
import polars as pl
import pandas as pd
class AshareHighFreqOFIEngine:
def __init__(self):
pass
def compute_intraday_ofi(self, l2_snapshots_df: pl.DataFrame) -> pl.DataFrame:
"""
计算单只股票全天日内快照的 OFI 序列 (微观状态机)
输入包含: [symbol, timestamp, bid_price, bid_vol, ask_price, ask_vol]
"""
if (l2_snapshots_df.schema["timestamp"] != pl.Datetime
or l2_snapshots_df.schema["timestamp"].time_zone is not None):
raise ValueError("timestamp 必须为上海本地无时区 Datetime")
if l2_snapshots_df.select(pl.struct("symbol", "timestamp").is_duplicated().any()).item():
raise ValueError("快照的股票时间键必须唯一")
if l2_snapshots_df.select(pl.any_horizontal([
(~pl.col(c).is_finite() | (pl.col(c) <= 0)).fill_null(True)
for c in ["bid_price", "ask_price", "bid_vol", "ask_vol"]
]).any()).item():
raise ValueError("报价和深度必须为有限正数;空盘口需上游处理")
l2_snapshots_df = l2_snapshots_df.with_columns(pl.col("timestamp").dt.date().alias("trade_date"))
# 利用 Polars 滞后函数提取上一个快照的状态 (shift 1)
ofi_calc = (
l2_snapshots_df.lazy()
.sort(["symbol", "timestamp"])
.with_columns([
pl.col("bid_price").shift(1).over(["symbol", "trade_date"]).alias("prev_bid_p"),
pl.col("bid_vol").shift(1).over(["symbol", "trade_date"]).alias("prev_bid_v"),
pl.col("ask_price").shift(1).over(["symbol", "trade_date"]).alias("prev_ask_p"),
pl.col("ask_vol").shift(1).over(["symbol", "trade_date"]).alias("prev_ask_v")
])
# 计算买方增量 I_bid
.with_columns([
pl.when(pl.col("bid_price") > pl.col("prev_bid_p"))
.then(pl.col("bid_vol"))
.when(pl.col("bid_price") == pl.col("prev_bid_p"))
.then(pl.col("bid_vol") - pl.col("prev_bid_v"))
.when(pl.col("bid_price") < pl.col("prev_bid_p"))
.then(-pl.col("prev_bid_v"))
.otherwise(0.0) # 每日第一帧作为基线
.alias("i_bid"),
# 计算卖方增量 I_ask
pl.when(pl.col("ask_price") > pl.col("prev_ask_p"))
.then(-pl.col("prev_ask_v"))
.when(pl.col("ask_price") == pl.col("prev_ask_p"))
.then(pl.col("ask_vol") - pl.col("prev_ask_v"))
.when(pl.col("ask_price") < pl.col("prev_ask_p"))
.then(pl.col("ask_vol"))
.otherwise(0.0)
.alias("i_ask")
])
# 计算每个快照瞬间的微观 OFI
.with_columns([
(pl.col("i_bid") - pl.col("i_ask")).alias("snapshot_ofi"),
(pl.col("bid_vol") + pl.col("ask_vol")).alias("depth_sum")
])
.collect()
)
return ofi_calc
def aggregate_to_daily_factors(self, ofi_snapshots_df: pl.DataFrame, trade_date: str | None = None) -> pl.DataFrame:
"""
将日内数千个快照降维聚合成【日频低频化高价值 Alpha 因子】
"""
if trade_date is not None:
requested = date.fromisoformat(trade_date)
if ofi_snapshots_df["trade_date"].unique().to_list() != [requested]:
raise ValueError("指定日期必须与全部快照日期一致;多日输入请省略 trade_date")
daily_features = (
ofi_snapshots_df.group_by(["symbol", "trade_date"])
.agg([
# 1. 全天净累计 OFI
pl.col("snapshot_ofi").sum().alias("daily_cum_ofi"),
# 2. 全天挂单平均深度
pl.col("depth_sum").mean().alias("avg_lob_depth"),
# 3. 标准化相对 OFI 强度 (除以挂单深度)
(pl.col("snapshot_ofi").sum() / (pl.col("depth_sum").mean() + 1e-5)).alias("factor_norm_ofi"),
# 4. OFI 波动率 (日内订单流博弈剧烈度)
pl.col("snapshot_ofi").std().alias("factor_ofi_volatility")
])
.sort("factor_norm_ofi", descending=True)
)
return daily_features
# =========================================================================
# 单元验证测试:模拟全天 4,800 个 L2 快照推演
# =========================================================================
if __name__ == "__main__":
np.random.seed(42)
n_snapshots = 4800 # 模拟全天完整 3秒一个的 L2 快照流
print(f"[*] 正在生成高密度 Level-2 订单簿盘口快照仿真流 (共 {n_snapshots} 条快照)...")
# 模拟两只标的:
# 标的 A: 机构大单持续向上挂单吃筹 (买强卖弱)
# 标的 B: 散户被动挂单,大单持续下砸出货 (卖强买弱)
symbols = ["000001.SZ", "600519.SH"]
all_records = []
for sym in symbols:
p_base = 100.0 if sym == "600519.SH" else 15.0
# 标的 A 存在微弱向上漂移,标的 B 存在向下抛压
drift = 0.00002 if sym == "600519.SH" else -0.00002
curr_p = p_base
for i in range(n_snapshots):
curr_p += np.random.normal(drift, 0.01)
bid_p = np.round(curr_p - 0.01, 2)
ask_p = np.round(curr_p + 0.01, 2)
# 茅台模拟多头主动盘口增挂
bid_v = np.random.randint(100, 500) if sym == "600519.SH" else np.random.randint(50, 200)
ask_v = np.random.randint(50, 200) if sym == "600519.SH" else np.random.randint(100, 500)
all_records.append({
"symbol": sym,
"timestamp": datetime(2023, 10, 16, 9, 30) + timedelta(seconds=3*i + (5400 if i >= 2400 else 0)),
"bid_price": bid_p,
"bid_vol": float(bid_v),
"ask_price": ask_p,
"ask_vol": float(ask_v)
})
df_l2 = pl.DataFrame(all_records)
# 运行高频特征引擎
engine = AshareHighFreqOFIEngine()
t0 = time.perf_counter()
df_ofi_snaps = engine.compute_intraday_ofi(df_l2)
daily_res = engine.aggregate_to_daily_factors(df_ofi_snaps, trade_date="2023-10-16")
elapsed = time.perf_counter() - t0
print(f"✅ 高频低频化聚合计算完毕!耗时: {elapsed:.3f} 秒")
print("\n" + "=" * 80)
print("日频标准化订单流不平衡 (Norm OFI) 降维提取结果:")
print("=" * 80)
print(daily_res)核心运行输出与微观特征解读:
[*] 正在生成高密度 Level-2 订单簿盘口快照仿真流 (共 4800 条快照)...
✅ 高频低频化聚合计算完毕!耗时: 0.056 秒
================================================================================
日频标准化订单流不平衡 (Norm OFI) 降维提取结果:
================================================================================
shape: (2, 6)
┌───────────┬────────────┬─────────────┬─────────────┬────────────┬────────────┐
│ symbol ┆ trade_date ┆ daily_cum_o ┆ avg_lob_dep ┆ factor_nor ┆ factor_ofi │
│ --- ┆ --- ┆ fi ┆ th ┆ m_ofi ┆ _volatilit │
│ str ┆ date ┆ --- ┆ --- ┆ --- ┆ y │
│ ┆ ┆ f64 ┆ f64 ┆ f64 ┆ --- │
│ ┆ ┆ ┆ ┆ ┆ f64 │
╞═══════════╪════════════╪═════════════╪═════════════╪════════════╪════════════╡
│ 000001.SZ ┆ 2023-10-16 ┆ 19594.0 ┆ 423.572292 ┆ 46.258927 ┆ 365.979011 │
│ 600519.SH ┆ 2023-10-16 ┆ 11660.0 ┆ 424.070833 ┆ 27.495406 ┆ 367.300476 │
└───────────┴────────────┴─────────────┴─────────────┴────────────┴────────────┘- 秒级微观状态机驱动:
- 算法逐帧跟踪买卖一档价格变动与挂单量增减,在多核并行下仅耗时 0.056 秒 即完成了全天 4,800 个微观快照的状态转移推导;
- 多空势能精准提取:
- 标的
000001.SZ的全天净累计 OFI 为 +19,594,标准化相对强度高达 46.26,展现了极其微观的主动买盘压倒性推力; - 该指标可直接作为日频截面特征,与动量、估值特征共同输入组合优化模型。
- 标的
6. 本讲小结与课后动手作业
核心知识图谱梳理:
- 高频低频化的战略价值:巧妙规避纯高频的微秒级容量天花板,又汲取了微观订单簿的高信噪比,是当今国内百亿量化买方的最核心杀手锏;
- OFI 揭示微观供需推力:通过挂单价量状态转移矩阵,同时反映新增委托、成交与撤单造成的最佳报价变化;
- 低频降维是关键:全天数千个快照经过累加与深度标准化后,转变为日频/周频特征,既能无缝喂入截面多因子模型,又能抵御日内随机波动的噪声。
课后动手实训:
实操任务:
- 打开
tutorial/examples/lecture_11_high_freq_to_low_freq.py。- 观察
compute_intraday_ofi函数中的状态机逻辑,思考如果行情供应商提供了 Level-2 买一到买五(五档深度),如何将单档 OFI 扩展为多档衰减 OFI(Multi-Level OFI)?- 为什么在 A 股早盘集合竞价结束时(09:25 开盘价确定至 09:30 之间)的静默期挂单量,对全天价格发现具有极高的权重?