3、数据清洗实战:Wind/彭博数据获取、异常值处理、插值方法对比

做信用利差曲线,最头疼的其实不是模型本身。

是数据。

我入行头两年,有一半时间都在跟数据较劲。从Wind和彭博拉下来的数据,看着整整齐齐,一跑模型就崩。后来我学乖了——数据清洗花的时间,永远不要省。今天咱们就把这块硬骨头啃下来。

3.1 数据源:Wind vs 彭博,我该怎么选?

国内做信用债,Wind是主流。彭博的数据更全,但贵。我个人习惯是:

  • 境内信用债:优先用Wind。中债估值、中证估值都有,接口也稳定。
  • 跨境或美元债:必须上彭博。它的定价模型和参考曲线更丰富。

但不管用哪个,你都会遇到同一个问题——数据缺失。比如某只债今天没成交,估值就断档了。这时候怎么办?别急,后面会讲插值。

我的小习惯:每次拉数据,我都会多拉一个字段——交易状态。有些债明明停牌了,估值还在更新,这种数据必须剔除。

3.2 异常值处理:那些让你怀疑人生的数据点

我记得有一次,回测策略跑出来年化收益30%,我差点以为自己要封神了。结果一查,是某只城投债的收益率数据多了一个零——6.5%变成了65%。

这种坑,踩过一次就记住了。

异常值通常分三类:

类型 典型表现 处理方法
明显错误 收益率>100%,或为负值 直接剔除
极端偏离 偏离同期限均值超过3个标准差 用中位数或插值替换
逻辑矛盾 剩余期限为负,或票息率异常 核对原始数据,确认后剔除

具体到代码,我一般这么干:

import pandas as pd
import numpy as np

def clean_yield_data(df, column='yield', z_thresh=3):
    """
    清洗收益率数据:剔除明显错误 + 3sigma去极值
    """
    # 第一步:剔除明显错误
    df = df[(df[column] > 0) & (df[column] < 100)]
    
    # 第二步:计算Z-score
    mean = df[column].mean()
    std = df[column].std()
    df['z_score'] = (df[column] - mean) / std
    
    # 第三步:剔除极端值
    df_clean = df[df['z_score'].abs() <= z_thresh]
    
    return df_clean.drop(columns='z_score')
注意:3sigma法则对正态分布有效。信用债收益率往往偏态分布,尤其是高收益债。我建议先用分位数法(比如1%和99%分位)做第一道过滤,再用Z-score。

3.3 插值方法对比:把断点连成曲线

数据清洗完了,你会发现——很多期限点上没有数据。比如3年期和5年期都有,但4年期是空的。这时候就需要插值。

我试过好几种方法,直接说结论:

方法 适用场景 优点 缺点
线性插值 期限点密集,曲线平滑 简单、稳定 无法捕捉弯曲
三次样条 需要平滑曲线 曲线光滑,连续可导 容易过拟合
分段常数 短期流动性差 保守,不引入虚假信息 曲线不平滑
Nelson-Siegel 收益率曲线建模 参数少,经济含义明确 对短期数据敏感

我个人最常用的是三次样条。为什么?因为信用利差曲线通常需要平滑,而且监管报送也要求曲线连续可导。但要注意——样条插值在端点处容易「翘尾巴」,我一般会在两端各加一个虚拟点来约束。

代码实现也不复杂:

from scipy.interpolate import CubicSpline
import numpy as np

# 假设我们有3年、5年、7年的收益率
years = np.array([3, 5, 7])
yields = np.array([3.2, 3.5, 3.8])

# 创建三次样条插值函数
cs = CubicSpline(years, yields, bc_type='natural')

# 插值到4年、6年
target_years = np.array([4, 6])
interpolated_yields = cs(target_years)

print(interpolated_yields)  # 输出:[3.35, 3.65]
避坑指南:我曾经在插值后直接用了结果,没检查单调性。结果某条曲线在5-7年之间出现了「倒挂」,被风控部门打回来重做。现在我的代码里一定会加一句:np.all(np.diff(interpolated_yields) >= 0),确保曲线单调递增。

3.4 实战流程:一张图说清楚

说了这么多,咱们把整个流程串起来。下面这张图是我自己项目里用的数据清洗流水线:

信用利差曲线数据清洗流程 1. 数据获取 Wind / 彭博 API 2. 初步清洗 剔除停牌、缺失值 3. 异常值检测 Z-score / 分位数法 4. 插值填充 三次样条 / 线性 5. 质量检查 单调性 / 平滑度 6. 输出曲线 信用利差曲线 不合格则返回重新插值 核心原则:先清洗,后插值,再检查

你看,整个流程其实是个闭环。数据清洗不是一次性的,插值完发现曲线不平滑,还得回去调整参数。我一般会迭代两到三轮,直到曲线既平滑又符合市场直觉。

3.5 几个让你少掉头发的建议

  • 永远保留原始数据。我吃过亏——清洗完直接覆盖原文件,后来发现有个参数设错了,想回退都回不去。现在我的习惯是:df_rawdf_clean 分开存。
  • 日志要打全。每一步清洗掉了多少条数据,插值用了什么方法,都记下来。不是为了给别人看,是为了三个月后的自己还能看懂。
  • 别迷信一种方法。线性插值简单,但遇到曲线弯曲大的时候会失真。三次样条漂亮,但数据稀疏时容易「放飞自我」。我的做法是:先用线性插值打底,再用样条做平滑,最后人工看一眼。
一个小技巧:如果你用彭博数据,记得检查 BIDASK 的价差。价差太大的债,即使有数据,也不建议纳入曲线构建。我一般设定价差超过50bp的直接剔除。

好了,数据清洗这块就聊到这儿。说白了,这是个脏活累活,但也是整个信用利差曲线构建的基石。数据干净了,后面的模型才能跑得稳。下一节咱们会聊到曲线拟合的具体方法,到时候这些清洗好的数据就能派上用场了。

专注资料整理