数据基础设施:数据源的选择与清洗
做量化回测,第一件事就是搞定数据。我见过太多人,策略写得花里胡哨,结果数据源一塌糊涂,回测结果全是噪音。说白了,数据是地基,地基不稳,楼盖得再高也得塌。
今天咱们就聊聊数据基础设施怎么搭。我会从数据源选择、数据清洗对齐,再到OHLCV数据结构设计,一步步拆解。
数据源的三种选择
我个人习惯把数据源分成三类:本地CSV、数据库、API。每种都有它的适用场景,没有绝对的好坏。
| 数据源 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 本地CSV | 简单、离线可用、无依赖 | 加载慢、不适合大数据量 | 小规模回测、快速原型 |
| 数据库 | 查询快、支持复杂过滤 | 需要部署维护 | 中大规模回测、团队协作 |
| API | 实时、数据全 | 有延迟、有费用、依赖网络 | 实盘交易、高频策略 |
我在项目中遇到过最坑的事:用API做回测,结果某天网络波动,数据少了几根K线,回测结果直接翻车。从那以后,我坚持本地先缓存一份。
核心原则:回测数据必须可复现。API数据每次请求可能不同,一定要落地保存。
数据清洗与对齐
拿到原始数据,别急着用。先做三件事:去重、补缺、对齐。
去重:有些数据源会重复推送同一根K线。我习惯用时间戳+代码做唯一键,直接去重。
def deduplicate(df):
# 按时间戳和代码去重,保留最后一条
return df.drop_duplicates(subset=['timestamp', 'symbol'], keep='last')
补缺:停牌、节假日、数据缺失,都会导致K线不连续。你想想看,如果某天数据是空的,回测引擎会以为你那天没交易,但实际上可能是停牌。
我曾经踩过一个坑:某只股票停牌一周,回测时策略自动卖出了,但实盘根本卖不掉。嗯,这里要注意,停牌期间的数据要特殊处理。
我的做法:停牌日的数据用前一日收盘价填充,成交量设为0。这样回测时策略不会误操作。
对齐:不同数据源的时间戳可能不一致。有的用UTC,有的用本地时间。有的精确到秒,有的精确到毫秒。必须统一对齐。
def align_timestamps(df, freq='1min'):
# 统一对齐到整分钟
df['timestamp'] = df['timestamp'].dt.floor(freq)
return df
OHLCV数据结构设计
OHLCV是回测框架的核心数据结构。说白了,就是Open(开盘价)、High(最高价)、Low(最低价)、Close(收盘价)、Volume(成交量)。
我建议用Pandas的DataFrame来存储,但要注意列的顺序和类型。
import pandas as pd
import numpy as np
# 标准OHLCV结构
ohlcv_columns = ['timestamp', 'open', 'high', 'low', 'close', 'volume']
dtypes = {
'open': np.float64,
'high': np.float64,
'low': np.float64,
'close': np.float64,
'volume': np.float64
}
def create_ohlcv_frame(data):
df = pd.DataFrame(data, columns=ohlcv_columns)
df = df.astype(dtypes)
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp', inplace=True)
return df
注意:时间戳一定要设为索引。回测时大量操作是按时间切片,索引查询比列查询快10倍以上。
为什么用float64而不是float32?我在项目中测试过,float32在大量累加计算时精度会漂移,回测久了误差累积,结果不可信。
数据基础设施的核心逻辑
下面这张图,是我自己总结的数据处理流程。你看一遍就能明白整体架构。
你看,整个流程其实不复杂。数据源进来,经过清洗对齐,转成标准OHLCV结构,然后喂给回测引擎。但每一步都有坑。
我的建议:一开始就用标准化的OHLCV结构。别想着后面再改,数据格式一旦定下来,改起来牵一发动全身。
最后说一句,数据基础设施这件事,花再多时间都值得。我见过太多人为了省两天时间,随便找个数据源就开始回测,结果浪费了两周去排查数据问题。嗯,你想想看,哪个更划算?