4. 金融数据获取:使用 Tushare/Akshare 获取股票日线数据、数据清洗与预处理

在量化策略灰度回测中,数据是模型训练的“原材料”。本章将系统讲解如何通过 Tushare 和 Akshare 两个主流 Python 金融数据接口获取股票日线数据,并完成数据清洗与预处理,为后续 LightGBM 特征工程和模型训练奠定基础。

4.1 数据源选型对比

选择合适的数据源是策略开发的第一步。下表从数据覆盖、更新频率、免费额度、接口稳定性四个维度对比 Tushare 与 Akshare:

对比维度 Tushare Pro Akshare
数据覆盖 A 股、港股、期货、基金、指数、宏观经济 A 股、港股、期货、基金、外汇、债券
更新频率 交易日 17:00 后更新当日数据 实时行情 + 盘后数据
免费额度 注册即送 200 积分,日调用 200 次 完全免费,无调用次数限制
接口稳定性 高,需 token 鉴权 中,依赖上游数据源
适用场景 专业回测、因子研究 快速原型、教学演示
选型建议: 本课程以 Tushare Pro 为主数据源,因其数据质量高、字段规范,适合构建生产级回测流水线。Akshare 作为备选方案,用于快速验证或补充特殊数据。

4.2 数据获取流程

数据获取遵循“初始化 → 参数配置 → 请求 → 存储”的标准流程。以下为使用 Tushare 获取沪深 300 成分股日线数据的核心步骤:

  1. 注册与鉴权: 在 Tushare 官网注册账号,获取个人 token。
  2. 安装与导入: pip install tushare,并设置 token。
  3. 参数配置: 指定股票代码、起始日期、结束日期、复权类型。
  4. 数据请求: 调用 pro.daily() 或 pro.daily_basic() 接口。
  5. 本地存储: 保存为 CSV 或 Parquet 格式,便于后续读取。
import tushare as ts
import pandas as pd

# 设置 token(请替换为你的实际 token)
ts.set_token('your_tushare_token_here')
pro = ts.pro_api()

# 获取平安银行(000001.SZ)2023年日线数据
df = pro.daily(
    ts_code='000001.SZ',
    start_date='20230101',
    end_date='20231231',
    fields='ts_code,trade_date,open,high,low,close,vol,amount'
)

# 查看数据前5行
print(df.head())
字段说明: open(开盘价)、high(最高价)、low(最低价)、close(收盘价)、vol(成交量,手)、amount(成交额,千元)。

4.3 数据清洗与预处理

原始数据通常存在缺失值、异常值、非交易时间戳等问题,必须经过清洗才能用于模型训练。清洗流程包括以下五个环节:

  • 缺失值处理: 检查 isnull(),对缺失的 OHLC 数据采用前向填充或插值法。
  • 异常值检测: 使用 Z-score 或 IQR 方法识别价格突变、成交量异常。
  • 时间序列排序: 按 trade_date 升序排列,确保时间顺序正确。
  • 复权处理: 调用 pro.adj_factor() 获取复权因子,计算后复权价格。
  • 数据类型转换: 将 trade_date 转为 datetime 类型,数值列转为 float。
# 数据清洗示例
def clean_daily_data(df):
    # 1. 排序
    df = df.sort_values('trade_date').reset_index(drop=True)
    
    # 2. 日期转换
    df['trade_date'] = pd.to_datetime(df['trade_date'])
    
    # 3. 缺失值处理(前向填充)
    df = df.fillna(method='ffill')
    
    # 4. 异常值处理(成交量异常)
    q1 = df['vol'].quantile(0.25)
    q3 = df['vol'].quantile(0.75)
    iqr = q3 - q1
    df = df[(df['vol'] >= q1 - 1.5 * iqr) & (df['vol'] <= q3 + 1.5 * iqr)]
    
    # 5. 添加复权价格(示例:后复权)
    # 实际需合并 adj_factor 表
    return df

df_clean = clean_daily_data(df)
print(f"清洗后数据量: {len(df_clean)} 行")

4.4 数据预处理流程架构

下图展示了从原始数据到模型可用特征矩阵的完整预处理流水线:

数据预处理流水线架构 原始日线数据 缺失值处理 异常值检测 复权计算 时间排序 特征衍生 标准化 最终特征矩阵 (X_train, y_train) 说明:特征衍生包括涨跌幅、换手率、波动率等;标准化使用 Z-score 或 Min-Max 方法

4.5 数据质量检查清单

在将数据送入 LightGBM 模型之前,建议逐项核对以下质量指标:

检查项 合格标准 处理方法
缺失值比例 < 5% 前向填充 / 删除
日期连续性 无交易日跳空 补全交易日历
价格合理性 open/high/low/close 逻辑一致 修正或删除异常行
成交量非负 vol >= 0 替换为 NaN 后填充
复权因子 与原始价格匹配 重新计算复权因子
常见陷阱: 使用 Tushare 时,daily 接口返回的是未复权数据,直接用于计算收益率会导致偏差。务必先获取 adj_factor 表,计算后复权价格后再进行特征工程。

4.6 数据存储与版本管理

为支持灰度回测的多次迭代,建议采用分层存储策略:

  • 原始层(raw): 保存从 Tushare 获取的原始 CSV,按日期分区。
  • 清洗层(clean): 经过缺失值、异常值处理后的 Parquet 文件。
  • 特征层(feature): 包含衍生特征和标准化后的最终矩阵,直接供模型调用。
# 分层存储示例
import os

base_path = './data/'
os.makedirs(f'{base_path}raw', exist_ok=True)
os.makedirs(f'{base_path}clean', exist_ok=True)
os.makedirs(f'{base_path}feature', exist_ok=True)

# 保存原始数据
df.to_csv(f'{base_path}raw/000001_SZ_2023.csv', index=False)

# 保存清洗后数据
df_clean.to_parquet(f'{base_path}clean/000001_SZ_2023.parquet')

# 保存特征矩阵(示例)
# X_train.to_parquet(f'{base_path}feature/X_train.parquet')

通过本章的学习,你已经掌握了从数据获取到清洗预处理的完整流程。下一阶段将基于清洗后的数据,构建 LightGBM 所需的特征工程体系。