第二章:数据基础——从原始数据到可交易特征
做量化交易,数据就是你的石油。没有数据,再牛的策略也是空中楼阁。
我个人习惯把数据工作分成四步:获取、清洗、特征工程、可视化。每一步都有坑,我踩过不少,今天一并告诉你。
核心观点:数据质量决定策略上限。80%的时间花在数据上,20%的时间写策略,这是常态。
2.1 数据源获取:从哪里搞到靠谱的数据?
数据源分两类:免费的和付费的。免费的有坑,付费的也有坑。我一个个说。
2.1.1 免费数据源
- Yahoo Finance (yfinance):适合美股,A股数据不全。我早期用它做回测,结果发现分红除权数据经常丢。
- Tushare:国内老牌数据平台,免费版有调用次数限制。嗯,这个要注意,写循环的时候容易触发限流。
- AKShare:开源免费,数据源多,但稳定性看运气。我曾经半夜跑策略,它突然挂了,第二天才发现回测结果全是NaN。
- 东方财富/新浪财经接口:爬虫方式获取,但接口经常变。说白了,维护成本高。
2.1.2 付费数据源
| 数据源 | 特点 | 价格 |
|---|---|---|
| Wind | 机构标配,数据全,API好用 | 贵(年费几万) |
| 聚宽/米筐 | 回测平台自带数据,省心 | 中等 |
| QuantConnect | 全球数据,适合多市场 | 按量收费 |
我的建议:个人学习先用免费数据,跑通流程。实盘前,至少用两个数据源交叉验证。我曾经因为数据源不一致,白白亏了半个月的模拟盘。
2.2 数据清洗与预处理:脏数据是策略的毒药
数据拿到手,第一件事不是分析,是清洗。你想想看,如果数据里有空值、异常值、复权没处理好,策略再漂亮也是白搭。
2.2.1 常见脏数据问题
- 缺失值:停牌日、节假日、数据源抽风都会导致NaN
- 异常值:比如某天涨幅1000%,明显是数据错误
- 复权问题:前复权还是后复权?选错了,回测结果天差地别
- 时间戳对齐:不同数据源的时间格式可能不同,UTC和北京时间差8小时
2.2.2 清洗实战代码
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('stock_data.csv', parse_dates=['date'])
# 1. 处理缺失值
df = df.dropna(subset=['close']) # 删除收盘价为空的记录
df['volume'] = df['volume'].fillna(0) # 成交量缺失填0
# 2. 检测异常值(3倍标准差法)
z_scores = np.abs((df['close'] - df['close'].mean()) / df['close'].std())
df = df[z_scores < 3]
# 3. 复权处理(前复权)
df['adj_close'] = df['close'] * df['adj_factor'] # adj_factor来自数据源
# 4. 时间戳统一
df['date'] = pd.to_datetime(df['date']).dt.tz_localize('Asia/Shanghai')
print(f"清洗后数据量: {len(df)} 条")
避坑指南:我曾经在复权问题上栽过大跟头。用后复权数据做回测,策略表现完美,实盘却一塌糊涂。后来才发现,后复权会改变历史价格形态,导致信号失真。记住:回测用前复权,实盘用原始价格。
2.3 特征工程入门:从价格到预测信号
特征工程说白了,就是把原始价格数据变成能预测未来涨跌的信号。这是量化策略的核心竞争力。
2.3.1 基础特征分类
- 价格衍生特征:收益率、对数收益率、最高最低价差
- 技术指标特征:均线、RSI、MACD、布林带
- 统计特征:滚动均值、滚动标准差、滚动相关系数
- 时间特征:星期几、月份、季度、是否财报季
2.3.2 特征构建示例
# 收益率特征
df['return_1d'] = df['close'].pct_change(1)
df['return_5d'] = df['close'].pct_change(5)
# 技术指标(简单版)
df['ma_20'] = df['close'].rolling(20).mean()
df['std_20'] = df['close'].rolling(20).std()
df['upper_band'] = df['ma_20'] + 2 * df['std_20']
df['lower_band'] = df['ma_20'] - 2 * df['std_20']
# RSI
delta = df['close'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(14).mean()
avg_loss = loss.rolling(14).mean()
rs = avg_gain / avg_loss
df['rsi_14'] = 100 - (100 / (1 + rs))
# 时间特征
df['day_of_week'] = df['date'].dt.dayofweek
df['month'] = df['date'].dt.month
个人经验:特征不是越多越好。我见过有人搞了200个特征,结果过拟合得一塌糊涂。我的习惯是:先做20-30个核心特征,然后通过相关性分析和特征重要性筛选,留下10个左右。
2.4 数据可视化基础:一眼看出问题
可视化不是为了好看,是为了快速发现问题。数据有没有异常?特征分布是否合理?这些用眼睛看比用统计检验快得多。
2.4.1 必会图表类型
- K线图:看价格走势、趋势、支撑阻力
- 折线图:看收益率曲线、指标变化
- 直方图:看收益率分布、特征分布
- 散点图:看两个特征之间的关系
- 热力图:看特征之间的相关性
2.4.2 可视化代码示例
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. K线图(简化版)
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['close'], label='收盘价', color='blue')
plt.plot(df['date'], df['ma_20'], label='20日均线', color='orange')
plt.title('价格与均线')
plt.legend()
plt.show()
# 2. 收益率分布
plt.figure(figsize=(8, 5))
df['return_1d'].hist(bins=100, alpha=0.7)
plt.title('日收益率分布')
plt.xlabel('收益率')
plt.ylabel('频次')
plt.show()
# 3. 相关性热力图
corr_matrix = df[['return_1d', 'rsi_14', 'volume', 'ma_20']].corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')
plt.title('特征相关性')
plt.show()
注意:可视化时一定要检查数据的时间范围。我遇到过有人用2020年的数据画图,发现收益率分布特别漂亮,结果是因为包含了疫情暴跌那几天。嗯,这种极端事件会扭曲你的认知。
本章知识体系
下面这张图概括了数据基础的核心流程。我建议你把它打印出来贴在工位上。
数据基础这部分,说白了就是四个字:干净、有用。干净的数据加上有用的特征,你的策略就成功了一半。剩下的,就是不断迭代和优化。
本章小结:
- 数据源选择:免费够用,付费省心,交叉验证是王道
- 数据清洗:缺失值、异常值、复权、时间戳,一个都不能少
- 特征工程:从价格衍生到技术指标,20个核心特征起步
- 数据可视化:K线、分布、相关性,一眼看出问题