数据准备:可转债行情数据获取、财务数据清洗、因子计算数据对齐

做量化,数据就是命根子。这话我常跟团队里的人讲。

可转债的因子组合优化,听起来高大上,但说白了,你因子算得再漂亮,数据源是脏的,结果就是垃圾进垃圾出。我见过太多人花90%的时间调模型,却不肯花10%的时间检查数据——嗯,最后模型跑出来的结果,连自己都不敢信。

这一章,我们就来聊聊数据准备那点事。说白了就三步:拿到行情数据、洗干净财务数据、把因子对齐到同一个时间轴上。

1. 可转债行情数据获取

行情数据,我习惯从两个渠道拿:一是聚宽、米筐这类量化平台,二是直接爬交易所的公开数据。个人建议,初期用聚宽就够了,省心。

你想想看,可转债的行情数据和股票不太一样。股票就一个价格,可转债有转股价值、溢价率、纯债价值这些衍生数据。所以获取的时候,字段要拿全。

核心字段清单:

  • 代码、名称、交易日期
  • 开盘价、收盘价、最高价、最低价
  • 成交量、成交额
  • 转股价值、转股溢价率
  • 纯债价值、到期收益率
  • 剩余规模、剩余年限

我曾经踩过一个坑:只拿了收盘价,没拿转股价值。结果算出来的因子全是价格相关的,完全忽略了债性。后来回测一塌糊涂,才意识到问题出在哪。

# 示例:使用聚宽获取可转债行情
from jqdatasdk import *
auth('你的账号', '你的密码')

# 获取所有可转债列表
bonds = get_all_securities(['bond_conv'])

# 获取某只转债的历史行情
df = get_price('123456.XSHE', 
               start_date='2023-01-01', 
               end_date='2023-12-31',
               fields=['open', 'close', 'volume', 'money', 
                       'conv_value', 'premium_ratio'])
print(df.head())

小技巧:行情数据最好按日频获取,不要偷懒用周频。因子计算时,日频数据能让你捕捉到更多细节。我一般会在每天收盘后跑一次数据更新脚本。

2. 财务数据清洗

财务数据,才是真正让人头疼的地方。

为什么?因为上市公司财报的发布时间、格式、口径都不一样。有的公司一季度报拖到4月底才发,有的提前一个月就发了。你想想看,如果不对齐时间,因子计算就会用到未来数据——这是量化里的大忌。

我个人习惯的清洗流程是这样的:

  1. 去重:同一家公司同一天发布多份财报?只保留最新的一份。
  2. 填充缺失值:有些财务指标可能为空,比如某季度没有研发费用。我一般用前值填充,或者用行业均值替代。
  3. 异常值处理:净利润突然暴涨100倍?大概率是数据错误。我会用3σ原则剔除。
  4. 时间对齐:把财报发布日期和报告期对应起来。比如2023年一季报,虽然可能在4月发布,但数据反映的是2023年3月底的情况。

注意:千万不要直接用财报的发布日期作为因子计算日期。我曾经犯过这个错,结果回测收益高得离谱——后来发现是因为用到了未来信息。正确的做法是:用报告期对应的截止日期,或者用财报发布后第一个交易日。

# 示例:财务数据清洗
import pandas as pd
import numpy as np

# 假设df是原始财务数据
df = pd.read_csv('financial_data.csv')

# 去重:按股票代码和报告期去重,保留最新记录
df = df.sort_values('report_date').drop_duplicates(
    subset=['code', 'report_period'], keep='last')

# 填充缺失值:用前值填充
df = df.fillna(method='ffill')

# 异常值处理:3σ原则
for col in ['net_profit', 'revenue']:
    mean = df[col].mean()
    std = df[col].std()
    df = df[(df[col] > mean - 3*std) & (df[col] < mean + 3*std)]

print(f"清洗后数据量: {len(df)}")

3. 因子计算数据对齐

这一步,说白了就是把行情数据和财务数据拼到一张表上。

但这里有个坑:行情数据是日频的,财务数据是季频的。怎么对齐?

我的做法是:

  • 以行情数据的日期为基准
  • 对于每个交易日,取最近一期已发布的财务数据
  • 注意:财务数据只有在发布之后才能使用,不能提前用

举个例子:今天是2023年5月15日,某公司2023年一季报在4月28日发布。那么5月15日这天,我们可以用一季报的数据。但如果今天是4月20日,一季报还没发,那就只能用2022年年报的数据。

对齐后的数据结构示例:

交易日期 转债代码 收盘价 转股价值 净利润(最近一期) 营收(最近一期) 因子A 因子B
2023-05-15 123456 128.50 115.20 1.2亿 5.6亿 0.85 0.32
2023-05-16 123456 129.00 115.80 1.2亿 5.6亿 0.86 0.33
# 示例:数据对齐
def align_data(market_data, financial_data):
    """
    market_data: 行情数据,日频
    financial_data: 财务数据,季频,包含报告期和发布日期
    """
    # 对每个交易日,找到最近一期已发布的财务数据
    aligned = []
    for date in market_data['date'].unique():
        # 筛选出在该日期之前已发布的财务数据
        available = financial_data[
            financial_data['publish_date'] <= date
        ]
        # 取最近一期
        latest = available.sort_values('report_date').groupby('code').last()
        # 合并
        day_data = market_data[market_data['date'] == date]
        merged = day_data.merge(latest, on='code', how='left')
        aligned.append(merged)
    
    return pd.concat(aligned)

# 运行对齐
result = align_data(market_df, financial_df)
print(result.head())

避坑指南:我曾经在数据对齐时,直接用财务数据的报告期去匹配行情数据,结果回测收益高得离谱。后来发现,有些公司财报发布得晚,但报告期早就过了。正确的做法是用发布日期去匹配,而不是报告期。这一点,你千万要记住。

本章知识体系

下面这张图,是我自己总结的数据准备流程。你看一眼,心里就有数了。

可转债因子数据准备流程 行情数据获取 日频:价格、成交量、转股价值 财务数据清洗 季频:去重、填充、异常处理 因子数据对齐 以行情日期为基准 关键注意事项 1. 行情数据必须包含转股价值、溢价率等衍生字段 2. 财务数据清洗时,注意报告期与发布日期的区别 3. 数据对齐时,用发布日期匹配,避免未来数据 4. 最终输出:一张日频的、包含行情+财务+因子的宽表

数据准备这一步,看起来繁琐,但做扎实了,后面的因子计算和模型训练就顺风顺水。我见过太多人急着跑模型,结果数据没对齐,白白浪费了几天时间。

嗯,这一章就到这里。记住:数据质量决定模型上限。你花在数据上的每一分钟,都会在回测结果里体现出来。


专注资料整理