第二章:数据基础——从原始数据到可交易特征

做量化交易,数据就是你的石油。没有数据,再牛的策略也是空中楼阁。

我个人习惯把数据工作分成四步:获取、清洗、特征工程、可视化。每一步都有坑,我踩过不少,今天一并告诉你。

核心观点:数据质量决定策略上限。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年的数据画图,发现收益率分布特别漂亮,结果是因为包含了疫情暴跌那几天。嗯,这种极端事件会扭曲你的认知。

本章知识体系

下面这张图概括了数据基础的核心流程。我建议你把它打印出来贴在工位上。

数据基础核心流程 数据获取 免费/付费数据源 数据清洗 缺失值/异常值/复权 特征工程 技术指标/统计特征 数据可视化 K线/分布/相关性 发现问题,返回清洗 关键原则 1. 数据质量 > 策略复杂度 2. 特征不是越多越好,20个核心特征足够 3. 可视化是发现问题的第一工具

数据基础这部分,说白了就是四个字:干净、有用。干净的数据加上有用的特征,你的策略就成功了一半。剩下的,就是不断迭代和优化。

本章小结:

  • 数据源选择:免费够用,付费省心,交叉验证是王道
  • 数据清洗:缺失值、异常值、复权、时间戳,一个都不能少
  • 特征工程:从价格衍生到技术指标,20个核心特征起步
  • 数据可视化:K线、分布、相关性,一眼看出问题

蓝海数据掘金营,专注资料整理