第一章:数据获取与清洗——打好量化分析的地基

各位同学,欢迎来到《盘口能量分布量化分析》的第一课。

做量化交易,尤其是盘口分析,最怕什么?

我个人觉得,最怕数据不准。数据不准,后面所有模型都是空中楼阁。我见过太多人,模型写得花里胡哨,结果一跑,发现是数据源出了问题,白白浪费几个星期。

所以,这一章我们先把地基打牢。说白了,就是三件事:拿到数据、洗干净数据、存好数据

核心观点:数据质量决定了量化策略的上限。Level-2行情数据颗粒度细,但噪声也多。清洗这一步,省不了。

本章知识体系 数据获取与清洗 Level-2 数据获取 数据清洗(去重/缺失值) 数据标准化与存储 API / 数据商 逐笔成交/委托 去重 & 填充 Z-score / MinMax CSV / HDF5

1.1 获取Level-2行情数据

Level-2数据,说白了就是比普通行情多一层的“内幕”。普通行情只能看到五档买卖盘,Level-2能看到十档,还能看到逐笔成交和逐笔委托。这对我们做盘口能量分布分析来说,简直是命根子。

获取方式主要有两种:

  • 直接对接数据商:比如万得、聚宽、米筐、恒生等。优点是稳定,缺点是贵。我早期做私募的时候,一年光数据费就几十万。
  • 使用开源库或券商API:比如 tushareaksharebaostock。免费或低价,适合个人研究。但要注意,免费数据可能有延迟或缺失。

我个人习惯用 akshare 做快速原型验证。它接口简单,覆盖广。下面是一个获取某只股票Level-2逐笔成交数据的例子:

import akshare as ak
import pandas as pd

# 获取逐笔成交数据(示例:平安银行,2024-01-15)
df_tick = ak.stock_individual_tick_em(
    symbol="000001",
    start_date="2024-01-15",
    end_date="2024-01-15"
)

print(df_tick.head())
print(f"数据行数: {len(df_tick)}")

小提示:Level-2数据量很大。一只股票一天可能有几万笔逐笔成交。如果你同时监控几百只股票,内存会爆炸。我建议先只关注你策略池里的核心标的。

1.2 数据清洗——去重与缺失值处理

数据拿到手,别急着分析。先看看有没有脏数据。

我遇到过最坑的一次:某数据商在行情波动剧烈时,重复推送了同一笔成交记录。结果我的策略以为成交量突然放大,开仓了……嗯,亏了不少。

去重是第一步。Level-2数据通常有唯一标识,比如 trade_idseq(序列号)。直接用 drop_duplicates() 干掉重复行。

# 去重
df_tick_clean = df_tick.drop_duplicates(subset=['trade_id'])
print(f"去重后行数: {len(df_tick_clean)}")

缺失值处理是第二步。盘口数据中,缺失值通常出现在某些字段(比如 ask_price 在无挂单时为空)。处理方法要看情况:

  • 直接删除:如果缺失比例很小(比如 < 1%),直接删掉最省事。
  • 向前填充:对于价格类数据,用前一个有效值填充。因为价格变化是连续的,这个做法比较合理。
  • 插值法:对于成交量等指标,可以用线性插值。但要注意,盘口数据波动大,插值可能引入偏差。
# 检查缺失值
print(df_tick_clean.isnull().sum())

# 向前填充价格字段
df_tick_clean['price'] = df_tick_clean['price'].ffill()

# 删除成交量缺失的行(如果很少)
df_tick_clean = df_tick_clean.dropna(subset=['volume'])

警告:千万不要对盘口数据做全局均值填充。盘口数据是非平稳的,均值填充会严重扭曲分布特征。我曾经见过有人这么干,结果策略回测曲线漂亮得不行,实盘一跑就崩。

1.3 数据标准化

为什么要标准化?你想想看,价格是几十块,成交量是几万手,量纲完全不一样。如果你直接拿原始数据做聚类或回归,价格会主导一切,成交量根本没话语权。

常用的标准化方法有两种:

方法 公式 适用场景
Z-score 标准化 (x - μ) / σ 数据近似正态分布,或需要保留异常值信息
Min-Max 归一化 (x - min) / (max - min) 数据有明确上下界,或需要映射到 [0,1] 区间

我个人习惯在盘口能量分析中用 Z-score。因为盘口数据经常有极端值(比如瞬间大单),Z-score 能保留这些极端值的信息,而 Min-Max 会把它们压缩到很窄的区间。

from sklearn.preprocessing import StandardScaler

# 选择需要标准化的列
cols_to_scale = ['price', 'volume', 'bid_volume', 'ask_volume']

scaler = StandardScaler()
df_tick_clean[cols_to_scale] = scaler.fit_transform(df_tick_clean[cols_to_scale])

print(df_tick_clean[cols_to_scale].describe())

小提示:标准化时,记得用 fit_transform 在训练集上拟合,然后用 transform 在测试集上转换。不要在整个数据集上一次性做,否则会引入未来信息。

1.4 数据存储——CSV vs HDF5

数据洗干净了,得存起来。存哪里?

CSV 是最简单的格式。人类可读,Excel 能打开。但缺点也很明显:

  • 文件大(文本存储,冗余多)
  • 读写慢(尤其几百万行时)
  • 不支持数据类型(所有数字都存成字符串)

HDF5 是二进制格式,专门为大规模科学计算设计。优点:

  • 压缩率高(文件体积小很多)
  • 读写快(支持索引和分块读取)
  • 支持复杂数据结构(多维数组、分组)

我个人的经验是:日常探索用 CSV,正式回测和实盘用 HDF5。CSV 方便肉眼检查,HDF5 性能好。

# 存储为 CSV
df_tick_clean.to_csv('level2_tick_20240115.csv', index=False)

# 存储为 HDF5
df_tick_clean.to_hdf('level2_tick_20240115.h5', key='tick_data', mode='w', complevel=5)

关键点:HDF5 的 complevel 参数控制压缩级别(0-9)。级别越高,文件越小,但写入越慢。我一般设 5,平衡速度和体积。

1.5 避坑指南——我踩过的那些坑

做数据清洗这么多年,有些坑真的是刻骨铭心。分享几个给你:

  • 时间戳对齐:不同数据源的时间戳精度可能不同(秒级 vs 毫秒级)。合并时一定要先统一精度,否则会错位。
  • 除权除息:股票分红送股后,价格会跳空。如果你不做复权处理,回测结果会失真。Level-2 数据通常提供复权因子,记得用上。
  • 盘口数据的时间切片:Level-2 数据是事件驱动的,不是等间隔的。如果你要做时间序列分析,需要先重采样到固定频率(比如 1 秒或 1 分钟)。

嗯,数据获取与清洗这部分,看起来基础,但真的决定了你后面所有工作的成败。别嫌麻烦,把这一步做扎实了,后面的分析会顺畅很多。

好了,这一章就到这里。记住:数据干净,策略才干净。


专注资料整理