数据获取与清洗:用Python搞定正股与转债的实时行情
做转债交易的朋友都知道,正股和转债的联动关系是核心。但说实话,很多人第一步就卡住了——数据拿不到,或者拿到的数据对不上。我刚开始做量化那会儿,也踩过不少坑。今天咱们就聊聊,怎么用Python把正股和转债的实时行情数据搞到手,再清洗对齐。
数据源的选择:别在起跑线上摔跤
我个人习惯用两个数据源:akshare 和 tushare。前者免费,适合日常研究;后者付费,但数据质量更稳定。你想想看,如果数据源本身就有问题,后面再清洗也是白搭。
核心原则:正股和转债的数据必须来自同一数据源,否则时间戳、字段定义都可能不一致,对齐时会很痛苦。
第一步:获取实时行情数据
先看代码。我用akshare举个例子,因为它上手快,不用注册。
import akshare as ak
import pandas as pd
from datetime import datetime
# 获取转债实时行情
def get_bond_realtime():
bond_df = ak.bond_zh_cov()
# 只保留我们需要的字段
bond_df = bond_df[['债券代码', '债券简称', '最新价', '涨跌幅',
'成交量', '成交额', '换手率']]
bond_df.columns = ['bond_code', 'bond_name', 'bond_price',
'bond_pct', 'bond_vol', 'bond_amount', 'bond_turnover']
return bond_df
# 获取正股实时行情
def get_stock_realtime(bond_df):
# 从转债数据中提取正股代码
stock_codes = bond_df['bond_code'].str[:6].tolist()
stock_df = ak.stock_zh_a_spot()
stock_df = stock_df[stock_df['代码'].isin(stock_codes)]
stock_df = stock_df[['代码', '名称', '最新价', '涨跌幅',
'成交量', '成交额', '换手率']]
stock_df.columns = ['stock_code', 'stock_name', 'stock_price',
'stock_pct', 'stock_vol', 'stock_amount', 'stock_turnover']
return stock_df
嗯,这里要注意:转债代码和正股代码的对应关系。转债代码是12开头,正股代码是6位数字。我一般直接从转债代码里截取前6位,但有些转债对应的正股代码可能不同,比如创业板转债。我在项目中遇到过这种情况,后来加了个映射表才搞定。
第二步:数据清洗——脏数据是最大的敌人
数据拿到手,别急着用。先看看有没有脏数据。我总结了几种常见情况:
- 缺失值:有些股票停牌,成交量、价格都是NaN
- 异常值:价格突然变成0,或者成交量突然放大100倍
- 重复数据:同一个时间点出现两条记录
我的习惯:清洗数据时,先做缺失值处理,再做异常值过滤。顺序别搞反了,否则异常值检测可能会被缺失值干扰。
def clean_data(bond_df, stock_df):
# 1. 删除缺失值严重的行
bond_df = bond_df.dropna(subset=['bond_price', 'bond_vol'])
stock_df = stock_df.dropna(subset=['stock_price', 'stock_vol'])
# 2. 过滤异常价格(价格不能为0或负数)
bond_df = bond_df[bond_df['bond_price'] > 0]
stock_df = stock_df[stock_df['stock_price'] > 0]
# 3. 过滤异常成交量(用3倍标准差法)
for col in ['bond_vol', 'stock_vol']:
df = bond_df if 'bond' in col else stock_df
mean = df[col].mean()
std = df[col].std()
df = df[df[col].between(mean - 3*std, mean + 3*std)]
return bond_df, stock_df
为什么用3倍标准差?说白了,这是统计学里的常用方法。正常情况下,99.7%的数据都在3倍标准差范围内。超出这个范围的,大概率是异常。
第三步:数据对齐——让正股和转债对上号
这是最关键的步骤。正股和转债的交易时间虽然一样,但数据推送可能有延迟。我见过有人直接按代码合并,结果时间戳对不上,分析出来的联动关系全是错的。
正确的做法是:按时间戳对齐。如果数据是分钟级的,就按分钟对齐;如果是日级的,就按日期对齐。
def align_data(bond_df, stock_df):
# 假设数据已经包含时间戳字段 'timestamp'
# 按时间戳和代码进行合并
merged = pd.merge(bond_df, stock_df,
left_on=['timestamp', 'bond_code'],
right_on=['timestamp', 'stock_code'],
how='inner')
# 计算联动指标
merged['price_ratio'] = merged['bond_price'] / merged['stock_price']
merged['vol_ratio'] = merged['bond_vol'] / merged['stock_vol']
return merged
我曾经踩过的坑:用how='left'或how='right'合并,结果导致大量数据错位。后来我改成how='inner',只保留两边都有的数据,虽然数据量少了,但质量高了很多。
实战中的小技巧
做数据清洗这么多年,我总结了几条经验:
- 先看数据概览:用df.describe()看看每列的分布,心里有个数
- 可视化检查:画个折线图,一眼就能看出异常点
- 保存原始数据:清洗前先备份,万一洗错了还能恢复
你想想看,如果数据清洗这一步没做好,后面再牛的策略也是空中楼阁。我见过太多人花大量时间调参数,结果问题出在数据上。
知识体系总览
下面这张图,把整个数据获取与清洗的流程串起来了。建议你保存下来,做项目时对照着看。
这张图把整个流程分成了四个阶段:数据源选择、数据获取、数据清洗、数据对齐。每个阶段都有对应的处理方法和注意事项。做项目时,按这个流程走,基本不会出大问题。
最后说一句:数据清洗是个细致活,急不得。我刚开始做的时候,总想快点出结果,结果数据没洗干净,策略回测效果很好,实盘一塌糊涂。后来学乖了,每次都在数据清洗上花足够的时间。
好了,数据获取与清洗就聊到这儿。记住一句话:垃圾进,垃圾出。数据质量决定了策略的上限,别在这个环节偷懒。