第一章:数据准备与预处理——打好地基才能盖高楼
各位同学,咱们直接进入正题。做量化交易,尤其是研究羊群效应这种偏行为金融的策略,数据就是你的眼睛。眼睛要是花的,后面再牛的模型也白搭。这一章,我带你手把手把数据这关过了。
1. 数据源选择:Level2行情 vs 逐笔成交
先说说数据从哪来。我个人习惯把数据源分成两类:Level2行情和逐笔成交数据。很多人一开始搞混,我当年也踩过坑。
| 数据源 | 特点 | 适用场景 |
|---|---|---|
| Level2行情 | 每3秒快照一次,包含十档买卖盘口、逐笔成交汇总 | 监测资金流向、大单异动、盘口挂单变化 |
| 逐笔成交数据 | 每一笔真实成交的明细,精确到毫秒 | 识别主力对倒、拆单行为、计算真实资金流向 |
说白了,Level2行情像看“快照”,逐笔成交像看“录像”。研究羊群效应时,我建议两者都拿。为什么?因为羊群行为往往体现在“小单跟随大单”的逐笔细节里,而Level2的盘口变化能帮你判断情绪拐点。
2. 数据清洗:别让脏数据毁了你的策略
数据拿到手,第一件事不是分析,是洗数据。我见过太多人上来就建模,结果发现异常值全是交易所测试数据。嗯,这里要注意。
2.1 异常值处理
常见的异常值有几种:
- 价格异常:比如某只股票突然出现0.01元的成交价。这通常是交易所测试或数据源错误。
- 成交量异常:单笔成交量超过该股票流通盘的1%,大概率是数据合并错误。
- 时间戳异常:比如下午3点之后还有成交记录,那是盘后数据混进来了。
我的处理方式很简单:
# 价格异常:剔除涨跌停板之外的极端值
df = df[(df['price'] >= df['price'].quantile(0.001)) &
(df['price'] <= df['price'].quantile(0.999))]
# 成交量异常:单笔成交超过流通股本0.5%的标记为异常
df = df[df['volume'] <= df['circulating_shares'] * 0.005]
# 时间戳异常:只保留交易时段数据
df = df[(df['time'] >= '09:30:00') & (df['time'] <= '15:00:00')]
2.2 缺失值填充
逐笔数据一般不会缺,但Level2行情偶尔会丢包。遇到缺失值,我的原则是:能不填就不填,非要填就谨慎。
- 连续缺失不超过3个周期:用前向填充(ffill),因为行情变化有惯性。
- 连续缺失超过3个周期:直接删除该时间段,避免引入噪声。
- 盘口数据缺失:用前后各5个周期的中位数填充,别用均值——盘口数据分布很偏。
# 前向填充连续缺失不超过3个
df['bid_price'].fillna(method='ffill', limit=3, inplace=True)
# 超过3个缺失的直接删除
df = df[df['bid_price'].notna()]
3. 数据对齐与重采样:统一时间尺度
不同数据源的时间戳精度不一样。逐笔数据精确到毫秒,Level2行情每3秒一次。你要把它们对齐到统一的K线周期上,才能做特征计算。
我个人习惯用1分钟K线做日内策略,用5分钟K线做波段策略。为什么?1分钟能捕捉到羊群效应的启动瞬间,5分钟能过滤掉部分噪音。
3.1 重采样到1分钟K线
# 将逐笔成交数据重采样为1分钟K线
df_1min = df.resample('1T', on='time').agg({
'price': 'ohlc', # 开盘价、最高价、最低价、收盘价
'volume': 'sum', # 成交量求和
'amount': 'sum', # 成交额求和
'buy_volume': 'sum', # 主动买入量
'sell_volume': 'sum' # 主动卖出量
})
这里有个细节:OHLC(开盘、最高、最低、收盘)的计算要小心。我见过有人直接用pandas的ohlc函数,结果开盘价取的是该分钟的第一笔成交价——但如果第一笔是异常值呢?所以我建议先清洗,再重采样。
3.2 对齐不同数据源
Level2行情和逐笔数据的时间戳可能差几毫秒。对齐时,我通常以逐笔数据的时间戳为准,把Level2的盘口数据向前对齐到最近的整秒。
# 将Level2数据对齐到逐笔数据的时间轴
df_level2['time_aligned'] = df_level2['time'].dt.floor('1S')
df_merged = pd.merge_asof(df_tick, df_level2,
left_on='time',
right_on='time_aligned',
direction='backward')
pd.merge_asof的direction='backward',意思是拿Level2最近一次的快照数据来匹配逐笔成交。这样能最大程度保留盘口信息的时效性。
4. 特征工程基础:从原始数据到有效信号
数据准备好了,接下来就是造特征。羊群效应相关的特征,我总结了三类:
- 资金流向类:主力净流入、散户净流入、大单占比。这些能直接反映“谁在买、谁在卖”。
- 盘口情绪类:买卖盘口厚度差、委买委卖比例、挂单撤单频率。这些能看出市场情绪是贪婪还是恐惧。
- 微观结构类:成交间隔时间、每笔成交量分布、价格冲击系数。这些能识别出“跟风盘”的痕迹。
举个例子,计算“散户跟风强度”这个特征:
# 定义:小单(散户)跟风强度 = 小单买入量 / 总成交量
df['small_buy_ratio'] = df['small_buy_volume'] / df['volume']
# 定义:大单异动系数 = 大单成交额 / 过去5分钟平均大单成交额
df['large_order_anomaly'] = df['large_amount'] / df['large_amount'].rolling(5).mean()
这些特征看起来简单,但组合起来就能刻画羊群效应的典型场景:大单先动,小单后跟,盘口挂单迅速堆积,然后价格加速上涨或下跌。
知识体系总览
下面这张图,是我做数据预处理时的完整流程。你可以把它当成一个检查清单,每次处理数据前过一遍。
你看,整个流程其实不复杂,但每一步都马虎不得。数据源选对了,清洗干净了,对齐准确了,特征造合理了——后面建模就是水到渠成的事。
好了,这一章就到这里。数据准备是苦活累活,但也是最有价值的活。你想想看,如果连数据都是错的,那策略再漂亮又有什么用?