我做日内策略回测时,吃过最大的亏不是因子失效,而是实盘与回测之间那一点点数据精度的差异。很多策略在 1 分钟频率上信号非常依赖开盘后价格的变化节奏,一旦分时线出现空缺或填充错误,整个入场逻辑就会偏移。因此,对于量化爱好者而言,自建一套可控的分钟级数据采集与聚合流程,是让策略从拟合走向稳健的必修课。
研究痛点:回测分钟线与实盘分时图的两张皮
在多数量化平台上,分钟线数据是经过服务端预先切片然后吐出来的,表面上看省事,实际上暗藏两个陷阱:一是切片时区与本地不一致,可能出现分钟边界错位;二是某些低活跃度时段服务端直接忽略,造成分钟序列缺失,而我们做因子计算时又极度依赖序列的连续性。结果就是回测很美,实盘信号却频频错乱。
数据需求:量化策略对分钟切片的结构要求
做日内因子,我要求每一条分钟切片必须包含:
- 分钟时间标记:务必为本地交易时间,且严格对齐。
- 成交价格:用该分钟最后一笔成交价作为“分钟收盘价”。
- 成交量:若数据源提供累加 tick,可以算出分钟内的攻击量;若提供快照量,则做差值。
有了这个结构,再加上价格,就可以构建最简单的量价因子,如分钟涨速、量比等。
AllTick API 的支持:将控制权收回本地
为了避免被服务端切片“二次加工”干扰,我直接接入 AllTick 的实时 tick 推送,在本地完成所有聚合逻辑。这样无论是夏令时切换还是分钟边界的定义,都由我的策略代码完全掌握。
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
# 接收实时 tick 数据,准备本地聚合
print(f"时间: {data['time']}, 价格: {data['price']}, 成交量: {data['volume']}")
def on_open(ws):
subscribe_data = {
"action": "subscribe",
"symbol": "AAPL"
}
ws.send(json.dumps(subscribe_data))
ws = websocket.WebSocketApp(
"wss://api.alltick.co/stock",
on_message=on_message,
on_open=on_open
)
ws.run_forever()
分钟聚合:从 tick 海洋中提炼标准分钟线
数据到手后,我用 pandas 的 resample 进行 1 分钟重采样,并对无成交时段做前向填充,保证序列不中断:
import pandas as pd
df['time'] = pd.to_datetime(df['time'])
df.set_index('time', inplace=True)
# 按1分钟窗口聚合,取价格最后值,成交量可另行累加
df_1min = df['price'].resample('1min').last().ffill()
可视化与策略信号叠加
分钟序列标准化之后,我通常会用 plotly 绘制分时走势,同时将策略的开平仓信号标记在图上,便于复盘:
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=df_1min.index,
y=df_1min.values,
mode='lines',
name='价格'
)
)
fig.show()
学术价值:高频分钟数据是量化研究的基石
在量化金融学术领域,分钟级价格序列常被用来测试 日内动量效应、流动性成本以及市场反应速度 等假说。一个未被污染的连续分钟数据集,能显著提升统计检验的效力。对于社区里希望深入研究的同仁来说,先把这条从实时数据到标准分钟线的管道建好,后续的因子挖掘与模型训练才会站在坚实的地基上。


