第二章:数据准备与清洗——可转债行情数据获取、复权处理、异常值识别与处理

做量化研究,有一句老话叫「垃圾进,垃圾出」。
因子模型再漂亮,数据源出了问题,结果就是废纸一张。
我个人习惯,花在数据清洗上的时间,至少占整个研究周期的40%。
这一章,咱们就聊聊可转债行情数据怎么拿、怎么复权、怎么把那些「脏数据」揪出来。

2.1 数据获取:从哪里来,拿什么

可转债行情数据,市面上常见的来源有几个:

  • Wind / Choice / iFinD:机构常用,数据全,但贵。
  • 聚宽 / 米筐 / Tushare:量化平台自带,适合回测。
  • 交易所官网:免费,但需要自己解析。

我个人建议,初期用聚宽或Tushare就够了。
我在项目中遇到过,用Wind拉数据时,某些老债的复权因子是空的,得自己补。
嗯,这里要注意:可转债的行情数据,核心字段包括

字段 说明 重要性
代码 如 123456.SZ 必选
日期 交易日 必选
收盘价 后复权或前复权?后面讲 必选
转股价 用于计算转股价值 必选
纯债价值 可自己算,也可用平台数据 推荐
成交量 / 成交额 流动性判断 推荐
溢价率 常用因子,但注意计算口径 可选
小技巧: 我习惯把「转股价」和「正股收盘价」也一并拉下来。因为很多因子(比如转股溢价率)需要实时计算,平台给的溢价率有时是静态的,不够准。

2.2 复权处理:为什么必须做?怎么做?

可转债有「下修转股价」这个机制。
一旦下修,转股价值会跳变,转债价格也会跟着调整。
如果不做复权,你的因子计算就会「断崖式」失真。

举个例子:
某转债原本转股价20元,正股18元,转股价值90元。
突然下修到10元,转股价值变成180元,转债价格从95元跳到150元。
你想想看,如果不复权,你的「价格动量因子」会显示一天涨了50%多,这明显是结构变化,不是真实交易行为。

复权方法有两种:

  1. 前复权:调整历史价格,让历史数据与当前一致。适合回测。
  2. 后复权:调整当前价格,让当前价格反映历史累计变化。适合看真实收益。

我个人习惯用前复权做因子计算。
原因很简单:回测时,你用的是历史价格,前复权能让历史价格「看起来」像今天的样子,避免因子突变。

核心公式:
前复权因子 = 当日转股价 / 最新转股价
前复权价格 = 原始价格 × 前复权因子

代码实现也不复杂:

# 伪代码示例
def adjust_price(df):
    # df 包含 columns: ['date', 'close', 'convert_price']
    # 按转债代码分组
    for bond in df['code'].unique():
        sub = df[df['code'] == bond].copy()
        # 获取最新转股价
        latest_cp = sub.iloc[-1]['convert_price']
        # 计算复权因子
        sub['adj_factor'] = sub['convert_price'] / latest_cp
        sub['adj_close'] = sub['close'] * sub['adj_factor']
        # 更新回原df
        df.loc[sub.index, 'adj_close'] = sub['adj_close']
    return df
注意: 有些平台(如Wind)会直接提供「复权因子」字段。但我在项目中遇到过,某些老债的复权因子在特定日期缺失,需要自己用转股价补算。千万别直接拿过来用,一定要交叉验证。

2.3 异常值识别:哪些数据是「脏」的?

数据清洗,说白了就是「找茬」。
可转债行情数据常见的异常有这几类:

  • 缺失值:某天停牌、或数据源漏了。
  • 极端值:比如收盘价突然变成0.01元,或者涨了1000%。
  • 逻辑错误:转股价为0、纯债价值为负、溢价率超过1000%。
  • 重复值:同一只债同一天出现两条记录。

我曾经遇到过一个案例:某只小盘转债,某天成交额显示为0,但成交量却有1000手。
这明显是数据源把成交额字段写错了。如果不处理,你的「换手率因子」就会变成无穷大。

2.4 异常值处理方法:我的「三板斧」

处理异常值,我有一套固定的流程,分享给你:

  1. 第一步:硬性过滤
    价格 < 0.1元 或 > 1000元,直接剔除。
    转股价 < 0.1元,剔除。
    溢价率 < -50% 或 > 200%,标记为异常。
  2. 第二步:统计过滤
    用「3σ原则」或「IQR方法」识别极端值。
    我个人偏好IQR,因为可转债价格分布不是正态的,3σ会误杀太多。
  3. 第三步:逻辑校验
    检查「转股价值 = 100 / 转股价 × 正股价」是否合理。
    检查「纯债价值」是否在合理区间(比如50-150元)。
    检查「到期收益率」是否为正且不过于离谱。
避坑指南: 我曾经在清洗数据时,发现某只债的「纯债价值」连续三天都是同一个数。一开始以为是数据源问题,后来发现是那几天该债停牌,平台用前一天的估值填充了。这种「伪正常值」最坑人,一定要结合停牌标记一起看。

2.5 知识体系总览

下面这张图,是我自己梳理的数据准备与清洗流程。你可以把它当作操作手册:

可转债数据准备与清洗流程 数据获取 Wind / 聚宽 / 交易所 复权处理 前复权 / 后复权 异常值识别 缺失 / 极端 / 逻辑错误 硬性过滤 价格 < 0.1 剔除 转股价 < 0.1 剔除 统计过滤 3σ 或 IQR 方法 推荐 IQR(非正态分布) 逻辑校验 转股价值合理性 纯债价值区间检查 清洗后的可用数据集

2.6 实战中的几个「坑」

最后,分享几个我踩过的坑,希望能帮你省点时间:

  • 坑一:复权因子更新滞后。 有些数据源在下修公告当天就更新转股价,但复权因子要第二天才更新。如果你当天拉数据,前后价格对不上。我建议自己算复权因子,别完全依赖平台。
  • 坑二:停牌期间的数据填充。 很多平台会用前收盘价填充停牌日的数据。这会导致你的「波动率因子」出现连续零值。我的做法是:停牌日直接标记为缺失,不填充。
  • 坑三:新债上市首日的数据。 新债上市首日没有前复权因子,有些平台会填0或NaN。我习惯用上市首日的转股价作为基准,手动计算首日的复权因子。
一句话总结: 数据清洗不是一次性工作,而是贯穿整个研究过程的「日常维护」。每次新增数据,都要跑一遍清洗流程。别偷懒,偷懒的代价就是因子失效。

公众号:蓝海资料掘金营,微信deep3321