数据获取与清洗:用Python搞定正股与转债的实时行情

做转债交易的朋友都知道,正股和转债的联动关系是核心。但说实话,很多人第一步就卡住了——数据拿不到,或者拿到的数据对不上。我刚开始做量化那会儿,也踩过不少坑。今天咱们就聊聊,怎么用Python把正股和转债的实时行情数据搞到手,再清洗对齐。

数据源的选择:别在起跑线上摔跤

我个人习惯用两个数据源:aksharetushare。前者免费,适合日常研究;后者付费,但数据质量更稳定。你想想看,如果数据源本身就有问题,后面再清洗也是白搭。

核心原则:正股和转债的数据必须来自同一数据源,否则时间戳、字段定义都可能不一致,对齐时会很痛苦。

第一步:获取实时行情数据

先看代码。我用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',只保留两边都有的数据,虽然数据量少了,但质量高了很多。

实战中的小技巧

做数据清洗这么多年,我总结了几条经验:

  1. 先看数据概览:用df.describe()看看每列的分布,心里有个数
  2. 可视化检查:画个折线图,一眼就能看出异常点
  3. 保存原始数据:清洗前先备份,万一洗错了还能恢复

你想想看,如果数据清洗这一步没做好,后面再牛的策略也是空中楼阁。我见过太多人花大量时间调参数,结果问题出在数据上。

知识体系总览

下面这张图,把整个数据获取与清洗的流程串起来了。建议你保存下来,做项目时对照着看。

数据获取与清洗流程 数据源选择 获取实时行情数据 数据清洗 缺失值处理 异常值过滤 重复数据删除 数据对齐(时间戳+代码)

这张图把整个流程分成了四个阶段:数据源选择、数据获取、数据清洗、数据对齐。每个阶段都有对应的处理方法和注意事项。做项目时,按这个流程走,基本不会出大问题。

最后说一句:数据清洗是个细致活,急不得。我刚开始做的时候,总想快点出结果,结果数据没洗干净,策略回测效果很好,实盘一塌糊涂。后来学乖了,每次都在数据清洗上花足够的时间。

好了,数据获取与清洗就聊到这儿。记住一句话:垃圾进,垃圾出。数据质量决定了策略的上限,别在这个环节偷懒。