4、数据获取与清洗:用akshare搞定可转债行情数据

做量化投资,有一句老话叫「垃圾进,垃圾出」。数据质量不行,再牛的策略也是白搭。这一章,我们就来聊聊怎么用 akshare 把可转债的行情数据拿到手,再把它收拾得干干净净。

我个人习惯把数据获取和清洗放在一起做。为什么?因为拿到的原始数据,十有八九是「脏」的。缺字段、格式不对、甚至还有乱码。你想想看,要是数据没洗干净,后面的轮动信号算出来能准吗?

4.1 用akshare获取可转债行情数据

akshare 这个库,说白了就是A股数据的「瑞士军刀」。它把各种公开数据源封装成了统一的接口,用起来非常方便。我最早接触它的时候,还担心数据源不稳定,后来发现它支持多个数据源切换,心里踏实多了。

获取可转债行情,核心就一个函数:ak.bond_zh_cov()。它会返回所有上市可转债的实时行情数据。

import akshare as ak
import pandas as pd

# 获取可转债实时行情
df_cov = ak.bond_zh_cov()
print(df_cov.head())

运行之后,你会得到一个DataFrame。里面包含的字段大概有这些:

字段名 含义 备注
代码 可转债代码 如 123456
名称 可转债名称 如 某某转债
现价 当前价格 单位:元
涨跌幅 当日涨跌幅 百分比
正股价 对应正股价格 单位:元
转股价 转股价格 单位:元
转股价值 转股后的价值 单位:元
溢价率 转股溢价率 百分比
剩余规模 剩余未转股规模 单位:亿元
到期时间 剩余到期年限 单位:年
小提示:akshare 的数据源偶尔会更新接口。如果你发现报错,可以试试升级到最新版本:pip install akshare --upgrade。我在项目中遇到过两次接口变更,升级后就好了。

4.2 数据清洗与预处理

拿到原始数据后,别急着用。先看看它长什么样。我一般会做这几步:

4.2.1 检查缺失值

原始数据里,有些字段可能是空的。比如刚上市的可转债,可能还没有成交数据。或者某些指标因为计算原因暂时缺失。

# 检查缺失值
print(df_cov.isnull().sum())

# 处理缺失值:直接删除缺失严重的行
df_cov = df_cov.dropna(subset=['现价', '转股价', '溢价率'])

嗯,这里要注意:不要一股脑把所有缺失行都删了。有些字段缺失是正常的,比如「到期时间」对于永续债来说就是空的。我建议只删除那些对策略计算关键字段缺失的行。

4.2.2 数据类型转换

原始数据里,价格、百分比这些字段,经常是字符串类型。比如「现价」可能是 '128.50' 这样的字符串。不转成浮点数,后面没法算。

# 将价格字段转为浮点数
df_cov['现价'] = pd.to_numeric(df_cov['现价'], errors='coerce')
df_cov['转股价'] = pd.to_numeric(df_cov['转股价'], errors='coerce')
df_cov['溢价率'] = pd.to_numeric(df_cov['溢价率'], errors='coerce')
避坑指南:我曾经遇到过「溢价率」字段里混入了 '--' 这样的占位符。用 pd.to_numeric 加上 errors='coerce' 参数,会自动把这些非法值变成 NaN,然后再统一处理。

4.2.3 过滤无效数据

有些可转债已经退市了,或者处于停牌状态。这些数据如果不剔除,会干扰轮动信号的计算。

# 过滤:只保留价格大于0的可转债
df_cov = df_cov[df_cov['现价'] > 0]

# 过滤:只保留溢价率在合理范围内的(比如 -50% 到 100%)
df_cov = df_cov[(df_cov['溢价率'] > -50) & (df_cov['溢价率'] < 100)]

为什么溢价率要设上下限?你想想看,溢价率超过100%的可转债,基本就是深度价外,转股无望。这种债的股性很弱,不太适合做轮动。当然,如果你有特殊策略,可以自己调整阈值。

4.3 构建基础数据DataFrame

数据洗干净了,接下来就是构建我们自己的基础数据表。我习惯把常用的计算字段都提前算好,存到一个干净的DataFrame里。

# 构建基础数据DataFrame
df_base = pd.DataFrame()
df_base['代码'] = df_cov['代码']
df_base['名称'] = df_cov['名称']
df_base['现价'] = df_cov['现价']
df_base['转股价'] = df_cov['转股价']
df_base['正股价'] = df_cov['正股价']
df_base['溢价率'] = df_cov['溢价率']
df_base['剩余规模'] = df_cov['剩余规模']
df_base['到期时间'] = df_cov['到期时间']

# 计算转股价值
df_base['转股价值'] = df_base['正股价'] / df_base['转股价'] * 100

# 计算到期收益率(简化版)
df_base['到期收益率'] = (100 - df_base['现价']) / df_base['现价'] / df_base['到期时间'] * 100

# 排序:按溢价率升序排列
df_base = df_base.sort_values(by='溢价率', ascending=True)

print(df_base.head())
核心思路:基础DataFrame是后续所有轮动策略的「原材料」。字段不用太多,但每个字段都要有意义。我个人习惯把「溢价率」和「到期收益率」作为核心字段,因为它们是判断可转债「股性」和「债性」的关键指标。

4.4 知识体系总览

这一章的内容,可以用下面这张图来概括。它展示了从数据获取到基础DataFrame构建的完整流程。

数据获取与清洗流程 步骤1:数据获取 akshare.bond_zh_cov() 步骤2:数据清洗 缺失值处理 类型转换 步骤3:数据预处理 过滤无效数据 字段计算 步骤4:构建基础DF 基础DataFrame字段 • 代码 / 名称 • 现价 / 转股价 / 正股价 • 溢价率 / 剩余规模 • 到期时间 / 到期收益率 • 转股价值 输出:干净、结构化的可转债基础数据表,用于后续轮动策略计算

这张图把整个流程串起来了。从akshare获取原始数据,到清洗、预处理,最后构建出我们自己的基础DataFrame。每一步都有坑,但踩过之后,后面的路就好走了。

我的习惯:每次获取数据后,我都会把原始数据存一份备份(比如存成CSV)。这样万一后面发现数据有问题,还能回溯检查。别问我为什么有这个习惯——有一次我凌晨跑策略,发现信号异常,就是靠备份数据定位到是数据源临时出了问题。

好了,数据已经准备好了。干净、完整、结构清晰。接下来,我们就可以用它来构建轮动策略了。


公众号:蓝海数据掘金营,微信deep3321