声明:本文为个人学习笔记,仅供技术交流,不构成任何投资建议。
一、前言
在期货量化这条路上,我已经走了整整二十年。从青涩的新手到现在的老油条,踩过的坑数都数不清。
这些年最深刻的体会之一就是:数据质量决定策略上限。
很多人花大量时间调策略参数,却忽略了数据本身的问题。脏数据进去,垃圾结果出来,这是铁律。
今天这篇文章,我想分享一下Python期货数据清洗的实践经验,包括常见的数据问题和处理方法。
二、期货数据常见的质量问题
做量化这么多年,遇到过各种奇葩的数据问题,总结下来主要有这几类:
1. 缺失数据
- 跳空缺失:某些时段没有数据,导致K线不连续
- Tick缺失:行情抖动或网络问题导致部分Tick丢失
- 字段缺失:成交量、持仓量等字段偶尔为空
2. 异常值
- 价格跳针:某个Tick价格突然异常偏离(数据源问题)
- 成交量异常:单笔成交量远超正常范围
- 时间戳错乱:Tick时间不递增
3. 重复数据
- 重复Tick:同一时间戳出现多条相同数据
- 重复K线:K线时间重叠
4. 格式问题
- 时区不统一:不同数据源时区不一致
- 合约代码不规范:rb2505、SHFE.rb2505、rb.SHFE等格式混乱
三、数据获取:几种方式的体验对比
处理数据之前,首先要获取数据。以下是我尝试过的几种方式:
1. 自建数据库 + CTP接口
最原始的方式,自己写程序从CTP接口录制行情数据。
优点:完全可控,成本低
缺点:需要24小时运行,数据维护麻烦,历史数据缺失难以补录
2. TqSdk 数据接口
天勤量化提供了完整的历史数据服务,用起来比较省心:
fromtqsdkimportTqApi,TqAuth api=TqApi(auth=TqAuth("账户","密码"))# 获取历史K线klines=api.get_kline_serial("SHFE.rb2505",60,3000)# 获取历史Tickticks=api.get_tick_serial("SHFE.rb2505")print(f"K线数据条数:{len(klines)}")print(f"Tick数据条数:{len(ticks)}")数据从合约上市就有,不用自己建库维护,对于研究历史策略很方便。
3. VnPy + 第三方数据源
VnPy本身不提供数据,需要自己对接数据源或购买第三方数据。
我的体验:自由度高但折腾多,适合有数据工程能力的团队。
四、Python数据清洗实战
下面分享几个常用的数据清洗方法,用pandas实现:
1. 缺失值处理
importpandasaspdimportnumpyasnp# 检测缺失值print(df.isnull().sum())# 方法1:删除缺失行(数据量大时可用)df_clean=df.dropna()# 方法2:前向填充(时间序列常用)df['close']=df['close'].fillna(method='ffill')# 方法3:线性插值df['close']=df['close'].interpolate(method='linear')2. 异常值检测与处理
# 使用Z-score检测异常值defdetect_outliers_zscore(series,threshold=3):z_scores=np.abs((series-series.mean())/series.std())returnz_scores>threshold# 检测价格异常outliers=detect_outliers_zscore(df['close'])print(f"检测到{outliers.sum()}个异常值")# 方法1:删除异常值df_clean=df[~outliers]# 方法2:用前值替换df.loc[outliers,'close']=np.nan df['close']=df['close'].fillna(method='ffill')3. 重复数据处理
# 检测重复duplicates=df.duplicated(subset=['datetime'],keep='first')print(f"重复数据:{duplicates.sum()}条")# 删除重复df_clean=df.drop_duplicates(subset=['datetime'],keep='first')4. 时间戳规范化
# 统一时区df['datetime']=pd.to_datetime(df['datetime'])df['datetime']=df['datetime'].dt.tz_localize('Asia/Shanghai')# 检查时间递增is_sorted=df['datetime'].is_monotonic_increasingifnotis_sorted:df=df.sort_values('datetime').reset_index(drop=True)5. 合约代码标准化
defnormalize_symbol(symbol):"""统一合约代码格式为 EXCHANGE.symbol"""# 处理各种格式symbol=symbol.upper().replace(' ','')if'.'insymbol:parts=symbol.split('.')iflen(parts[0])<=4:# SHFE.rb2505 格式returnsymbolelse:# rb2505.SHFE 格式returnf"{parts[1]}.{parts[0]}"else:# 推断交易所ifsymbol.startswith('RB')orsymbol.startswith('CU'):returnf"SHFE.{symbol.lower()}"# ... 其他交易所判断returnsymbol df['symbol']=df['symbol'].apply(normalize_symbol)五、数据质量验证
清洗完成后,需要验证数据质量:
defvalidate_data(df):"""数据质量检查"""issues=[]# 1. 检查缺失值null_count=df.isnull().sum().sum()ifnull_count>0:issues.append(f"存在{null_count}个缺失值")# 2. 检查时间连续性ifnotdf['datetime'].is_monotonic_increasing:issues.append("时间戳不递增")# 3. 检查价格合理性if(df['close']<=0).any():issues.append("存在非正价格")# 4. 检查涨跌幅异常(单日超过20%)returns=df['close'].pct_change()if(abs(returns)>0.2).any():issues.append("存在涨跌幅超过20%的数据")ifissues:print("数据质量问题:")forissueinissues:print(f" -{issue}")else:print("数据质量检查通过")returnlen(issues)==0validate_data(df_clean)六、不同工具的数据质量对比
用了这么多工具,对它们的数据质量有一些体会:
| 工具 | 数据完整度 | 数据质量 | 维护成本 |
|---|---|---|---|
| 自建CTP录制 | 看自己维护 | 需要自己清洗 | 高 |
| TqSdk | 高(有历史数据) | 已做基础清洗 | 低 |
| VnPy | 取决于数据源 | 取决于数据源 | 中 |
| 文华财经 | 高 | 高 | 低 |
从实际体验来说,我目前主要使用TqSdk获取数据,主要是因为:
- 数据从合约上市就有,不用自己补录
- 数据已经做过基础清洗,质量可接受
- 和回测、实盘代码无缝衔接
当然,这只是我个人的选择,每个人需求不同,建议多试用比较。
七、总结
数据清洗是量化交易的基础工作,虽然繁琐但非常重要。希望这篇文章的实践经验能帮到正在做数据处理的朋友。
几点建议:
- 尽量选择数据质量好的源头,后期清洗工作量会小很多
- 建立标准化的清洗流程,形成可复用的代码
- 做好数据质量监控,定期检查数据是否正常
学习量化交易是一个漫长的过程,工具只是手段,核心还是对市场和策略的理解。本文只是我学习过程中的一些记录,仅供参考。
声明:本文基于个人学习经验整理,仅供技术交流参考,不构成任何投资建议。