📈 CTA 趋势跟踪 · 数据工厂

#3 数据获取与处理
tushare · akshare

⚡ 实战核心 :使用 Python 获取期货主力连续合约行情,清洗异常值、对齐时间戳,为趋势跟踪策略提供纯净、可靠的数据底座。本讲覆盖 tushare pro 与 akshare 双工具链,并演示数据对齐与重采样。

🧩 数据获取 · 清洗 · 对齐 流程

📡 数据源 tushare / akshare 🧹 清洗模块 去重 · 缺失填充 异常值过滤 ⚙️ 对齐引擎 时间戳对齐 · 重采样 多合约同步 📊 ⏱️ 日线/1小时/15分钟 · 主力连续合约
字段tushare (pro)akshare清洗对齐说明
代码ts_codesymbol统一为 主力连续 格式
日期trade_datedate转为 datetime,对齐至交易日历
开盘openopen向前填充非交易日
最高highhigh去极值 (MAD / 分位数)
最低lowlow去极值
收盘closeclose复权处理 (若需)
成交量volvolume负值置零,缺失插值
持仓量holdopen_interest对齐到主力合约切换日

🧽 数据清洗

  • 缺失值前向填充
  • 涨跌停过滤
  • 跳跃价格修正
  • 非交易时间剔除

🔗 对齐策略

  • 统一频率 (日/小时)
  • 主力合约拼接
  • 换月价差调整
  • 多品种时间戳对齐

🐍 Python 工具

  • pandas / numpy
  • tushare (pro)
  • akshare
  • datetime / re
# ========== 1. 使用 tushare 获取期货日线 ==========
import tushare as ts
import pandas as pd

ts.set_token('your_tushare_token')
pro = ts.pro_api()

# 获取螺纹钢主力连续 (rb888)
df_ts = pro.fut_daily(
    ts_code='rb888.SHF',
    start_date='20230101',
    end_date='20250301',
    fields='trade_date,open,high,low,close,vol,hold'
)
df_ts['trade_date'] = pd.to_datetime(df_ts['trade_date'])
df_ts.sort_values('trade_date', inplace=True)
print('tushare 数据行数:', len(df_ts))

# ========== 2. 使用 akshare 获取相同品种 ==========
import akshare as ak

df_ak = ak.futures_main_sina(
    symbol='RB0',   # 螺纹钢主连
    start_date='20230101',
    end_date='20250301'
)
df_ak.rename(columns={ '日期': 'date', '开盘价': 'open',
                       '最高价': 'high', '最低价': 'low',
                       '收盘价': 'close', '成交量': 'volume',
                       '持仓量': 'open_interest' }, inplace=True)
df_ak['date'] = pd.to_datetime(df_ak['date'])
print('akshare 数据行数:', len(df_ak))
            

📋 数据清洗与对齐 5 步骤

  1. ① 获取原始数据 (tushare / akshare) 并检查缺失
  2. ② 统一列名、日期格式,按时间排序
  3. ③ 去重 (相同交易日保留最后记录) ,处理涨跌停异常
  4. ④ 主力合约换月拼接,调整跳空缺口 (价差对齐)
  5. ⑤ 重采样至目标周期 (如1小时) ,向前填充非交易时段
# ========== 数据清洗 & 对齐 核心 ==========
def clean_align(df, date_col='trade_date'):
    # 去重 & 排序
    df = df.drop_duplicates(subset=[date_col]).sort_values(date_col)
    # 填充缺失值 (前向)
    df = df.fillna(method='ffill')
    # 剔除成交量<=0 的异常行
    df = df[df['vol'] > 0] if 'vol' in df.columns else df
    # 重置索引
    df.reset_index(drop=True, inplace=True)
    return df

# 对齐到统一时间索引 (以tushare日期为基准)
df_ts_clean = clean_align(df_ts, date_col='trade_date')
df_ak_clean = clean_align(df_ak, date_col='date')

# 合并对齐 (inner join 共同时段)
df_aligned = pd.merge(
    df_ts_clean[['trade_date', 'close', 'vol']],
    df_ak_clean[['date', 'close', 'volume']],
    left_on='trade_date', right_on='date',
    how='inner'
)
print(f'对齐后样本数: {len(df_aligned)}')
            

💡 主力连续合约 :tushare 使用 rb888 / MA888 等,akshare 使用 RB0 / MA0 后缀。换月时自动拼接,但需额外进行 价差调整 以避免趋势信号失真。