第4章:金融数据获取——从Tushare到AkShare的实战之路

做量化交易,数据就是你的弹药库。没有干净的数据,再牛的策略也是白搭。

这一章,我带你搞定有色金属期货的数据获取、清洗和存储。说白了,就是让你知道数据从哪来、怎么处理、存哪去。

4.1 数据源选择:Tushare vs AkShare

国内做期货量化,主流就两个库:Tushare和AkShare。我两个都用过,说说我的感受。

对比项 Tushare AkShare
数据覆盖 全面,含基本面 更广,含另类数据
获取方式 需注册Token 免费,部分需积分
速度 较快(付费更快) 中等
文档 清晰,社区活跃 更新快,但略乱
我的建议:新手先用AkShare上手,免费且数据够用。等你要做高频或深度研究时,再考虑Tushare的付费接口。我在项目中遇到过,AkShare偶尔会因网站改版导致接口失效,所以记得加异常处理。

4.2 实战:用AkShare获取沪铜期货数据

直接上代码。我习惯先写一个通用的获取函数,方便后续复用。

import akshare as ak
import pandas as pd
from datetime import datetime, timedelta

def get_futures_data(symbol='CU', start_date='20200101', end_date=None):
    """
    获取期货主力连续合约数据
    symbol: 合约代码,如'CU'为沪铜
    """
    if end_date is None:
        end_date = datetime.now().strftime('%Y%m%d')
    
    try:
        # 获取主力连续合约
        df = ak.futures_main_sina(symbol=symbol)
        # 筛选日期范围
        df = df[(df['date'] >= start_date) & (df['date'] <= end_date)]
        return df
    except Exception as e:
        print(f"数据获取失败: {e}")
        return None

# 获取沪铜近3年数据
cu_data = get_futures_data('CU', '20210101')
print(cu_data.head())

嗯,这里要注意:AkShare返回的数据列名是中文的,我建议你统一转成英文,方便后续处理。

4.3 数据清洗与预处理

拿到原始数据后,你会发现各种问题。我总结了三类常见坑:

4.3.1 处理缺失值

期货数据偶尔会缺一天,比如节假日或者数据源抽风。我的处理原则是:

  • 连续缺失不超过3天:用前向填充(ffill)
  • 超过3天:直接删除,别硬补
  • 开盘价/收盘价缺失:必须删除,不能填充
# 缺失值处理
def handle_missing(df):
    # 检查缺失比例
    missing_ratio = df.isnull().sum() / len(df)
    print(f"缺失比例:\n{missing_ratio}")
    
    # 对价格列严格处理
    price_cols = ['open', 'high', 'low', 'close']
    df = df.dropna(subset=price_cols)
    
    # 对成交量等用前向填充
    df['volume'] = df['volume'].ffill()
    df['open_interest'] = df['open_interest'].ffill()
    
    return df
避坑指南:我曾经因为没检查缺失值,直接跑策略,结果回测曲线漂亮得不像话。后来发现是某个月数据全空,策略自动用前一天数据填充,造成了假信号。从那以后,我每次拿到数据第一件事就是画缺失值热力图。

4.3.2 异常值检测

期货市场偶尔会有极端行情,但有些异常是数据错误。我常用的方法是:

  1. 3σ原则:超过均值±3倍标准差的数据标记为异常
  2. IQR方法:用四分位距检测,更稳健
  3. 涨跌停检查:超过涨跌停板的价格直接剔除
def detect_outliers(df, col='close', method='iqr'):
    if method == 'iqr':
        Q1 = df[col].quantile(0.25)
        Q3 = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower = Q1 - 1.5 * IQR
        upper = Q3 + 1.5 * IQR
        outliers = df[(df[col] < lower) | (df[col] > upper)]
        print(f"检测到 {len(outliers)} 个异常值")
        return outliers
    return None

4.3.3 复权处理

期货和股票不一样,没有除权除息,但有合约换月。主力连续合约在换月时会有跳空,必须处理。

我常用的方法是:

  • 前复权:以当前合约为基准,调整历史数据
  • 后复权:以最早合约为基准,调整后续数据
  • 等比复权:按比例调整,保持收益率不变
def adjust_futures_price(df, method='forward'):
    """
    期货复权处理
    method: 'forward' 前复权, 'backward' 后复权
    """
    df = df.copy()
    # 计算换月跳空比例
    df['gap_ratio'] = df['close'] / df['close'].shift(1)
    
    if method == 'forward':
        # 以最新数据为基准
        base_price = df['close'].iloc[-1]
        df['adj_close'] = base_price / (df['gap_ratio'].iloc[::-1].cumprod().iloc[::-1])
    else:
        # 以最早数据为基准
        base_price = df['close'].iloc[0]
        df['adj_close'] = base_price * df['gap_ratio'].cumprod()
    
    return df
核心要点:复权后的数据只能用于策略回测,不能用于实盘交易。实盘时,你交易的是当前主力合约,不是复权后的虚拟价格。

4.4 数据存储方案

数据存哪?我根据使用场景分三种:

存储方式 适用场景 优缺点
CSV 小数据量、快速验证 简单直观,但读写慢
HDF5 中等数据量、频繁读写 压缩率高,支持快速切片
数据库(MySQL/PostgreSQL) 大数据量、多用户协作 支持复杂查询,但部署麻烦

我个人习惯:

  • 日常研究用HDF5,pandas直接读写,方便
  • 生产环境用数据库,配合SQL做数据校验
  • CSV只用来做数据交换,比如给同事发数据
# HDF5存储示例
def save_to_hdf5(df, filename='futures_data.h5', key='cu'):
    df.to_hdf(filename, key=key, mode='a', 
              format='table', data_columns=True)
    print(f"数据已保存至 {filename}")

# 读取
def load_from_hdf5(filename='futures_data.h5', key='cu'):
    return pd.read_hdf(filename, key=key)

# 数据库存储(以MySQL为例)
def save_to_mysql(df, table_name='futures_cu'):
    from sqlalchemy import create_engine
    engine = create_engine('mysql+pymysql://user:pass@localhost/db')
    df.to_sql(table_name, engine, if_exists='replace', index=False)
    print(f"数据已写入MySQL表 {table_name}")

4.5 本章知识体系

下面这张图,是我做数据流程时画的,帮你理清思路:

有色金属数据获取与处理流程 数据源 Tushare / AkShare 数据获取 主力连续合约 数据清洗 缺失值 / 异常值 复权处理 前复权 / 后复权 数据存储 CSV / HDF5 / 数据库 策略回测 择时信号生成 数据更新与维护(每日增量)
我的工作流:每天早上开盘前,先跑一遍数据获取脚本,自动更新到HDF5文件。然后做一次简单的数据质量检查——看看有没有缺失、有没有异常跳空。整个过程不到5分钟,但能避免很多坑。

好了,数据获取和清洗这块就这些。记住一个原则:垃圾进,垃圾出。数据质量决定了策略的上限,别在这步偷懒。

专注资料整理