作为一名在量化金融领域摸爬滚打十年的从业者,我深知高质量历史交易数据对策略研发的决定性作用。今天要剖析的这个数据集,覆盖了2016-2021年美股市场6192只股票的完整OHLCV数据,总量达780万条记录。这相当于每天为每只股票保存了开盘价、最高价、最低价、收盘价和成交量这五个关键维度,构建起一个五维的市场观测矩阵。
特别提示:处理极端价格值时需格外谨慎,数据中存在172,800,000美元的单日最高价记录,这显然是某些特殊金融工具或数据异常导致,实际分析时应设置合理的价格过滤阈值。
这个时间窗口特别有意思:2016年美联储开启加息周期,2018年贸易摩擦升级,2020年遭遇世纪疫情,最后以2021年史诗级散户大战华尔街收尾。五年间市场经历了完整的牛熊转换,对策略压力测试而言堪称完美样本。
字段设计遵循经典的OHLCV范式:
在清洗数据时我常用三板斧:
sql复制WITH calendar AS (
SELECT generate_series('2016-02-16'::date, '2021-02-12'::date, '1 day'::interval)::date AS trading_date
)
SELECT c.trading_date
FROM calendar c
WHERE NOT EXISTS (
SELECT 1 FROM stock_data d
WHERE d.datetime::date = c.trading_date
AND d.symbol = 'A' --示例股票
)
从年度分布看,2020年数据量突然激增20万条,这与当年SPAC上市潮导致新股数量暴增直接相关。价格统计中那个1.7亿的极端值,经查是BRK.A(伯克希尔A类股)在2019年6月的收盘价,这类特殊案例需要单独处理。
以布林带策略为例,Python实现核心代码:
python复制def calculate_bollinger_bands(df, window=20, num_std=2):
rolling_mean = df['close_price'].rolling(window=window).mean()
rolling_std = df['close_price'].rolling(window=window).std()
df['upper_band'] = rolling_mean + (rolling_std * num_std)
df['lower_band'] = rolling_mean - (rolling_std * num_std)
return df
# 应用示例
aapl_data = df[df['symbol']=='AAPL'].copy()
aapl_data = calculate_bollinger_bands(aapl_data)
血泪教训:回测时一定要考虑幸存者偏差!数据中包含的股票中有23%在2021年前已退市,若只使用现存股票回测会严重高估策略表现。
如何从OHLCV中提取有效因子?我的经验公式:
用PyPortfolioOpt库实现马科维茨优化:
python复制from pypfopt import EfficientFrontier
from pypfopt.risk_models import CovarianceShrinkage
# 准备收益率矩阵
returns = df.pivot(index='datetime', columns='symbol', values='close_price').pct_change().dropna()
# 使用Ledoit-Wolf收缩估计
cov_matrix = CovarianceShrinkage(returns).ledoit_wolf()
# 优化夏普比率
ef = EfficientFrontier(None, cov_matrix)
weights = ef.max_sharpe()
面对780万条记录,我推荐以下存储架构:
现象:同一股票在同一天出现多条记录
解决方案:
python复制# 检查重复记录
duplicates = df[df.duplicated(['symbol', 'datetime'], keep=False)]
# 处理方案:保留最后一条
df = df.drop_duplicates(['symbol', 'datetime'], keep='last')
用Transformer架构预测股价走势:
python复制from transformers import TimeSeriesTransformerModel
model = TimeSeriesTransformerModel(
input_size=5, # OHLCV
prediction_length=1,
context_length=30
)
# 输入形状:[batch_size, context_length, input_size]
通过tick数据重构订单簿(需额外数据):
这五年数据里藏着几个金矿:
建议重点研究三个方向:
最后分享一个数据预处理的神器:使用fuzzywuzzy库解决股票代码变异问题(如BRK.A vs BRKA):
python复制from fuzzywuzzy import fuzz
def match_symbol(s1, s2):
return fuzz.ratio(s1.replace('.',''), s2.replace('.','')) > 90