跳转到内容

行情数据:粒度、复权与合约换月

  • 前复权:以今天为基准反推历史价格——分红除权日一过,全部历史价格都会变。用它存数据,等于把未来的分红信息写进了历史,是典型前视偏差;
  • 后复权:以上市首日为基准向后累乘,历史值一旦确定不再变化——回测应使用后复权;
  • 不复权 + 复权因子:最干净的做法——存原始价格与因子,收益在计算时用 ∏(1+因子调整)\prod (1 + \text{因子调整}) 逐日拼接,任何基准都可重建。
adjust.py
import numpy as np
import pandas as pd
def adjusted_returns(raw: pd.DataFrame, factor: pd.Series) -> pd.Series:
"""raw: 未复权收盘价;factor: 复权因子(向后累乘)。返回真实日收益。"""
px_adj = raw["close"] * factor # 等价于后复权价
return px_adj.pct_change().dropna()
  1. 停牌日:不能简单前值填充后再算收益——停牌期间的真实收益为零,填充后复牌日的收益会被压缩到错误的位置。正确做法是停牌日剔除、复牌日收益一次性计算;
  2. 指数成分:用今天的名单回溯历史,是幸存者偏差的另一形态,见财务与公告数据;
  3. 分钟与 tick:数据量呈两个数量级增长,存储见存储格式与查询;tick 数据还要处理集合竞价、异常报价与交易所规则变化。

期货没有"一只股票"的概念,只有不断到期的合约。连续价格序列必须拼接,两种方式:

方式做法适用
比例调整(后复权式)换月日乘以新旧价比,百分比收益连续趋势/动量策略、收益率统计
价差调整(差价平移)换月日减去新旧价差,价格变动连续只关心价差绝对水平的场合

比例调整是默认选择:趋势信号与波动率都以百分比收益为对象,见期货:保证金、换月与限仓。换月日的选择(成交量规则:旧合约成交量被新合约超过)本身也要按当时的成交量判定,不能事后固定。

  • 存原始价 + 复权因子,收益计算时再调整;
  • 停牌日剔除而非填充;
  • 期货用比例调整拼接,换月日按当时成交量规则判定。
  • 回测应使用后复权或直接用复权因子计算收益,避免前复权带来的前视
  • 停牌日不能简单前值填充后再计算收益
  • 期货连续合约:价差调整 vs 比例调整,趋势策略更适合后者