可转债数据获取与分析:用Python构建可转债投资决策系统

可转债数据获取与分析:用Python构建可转债投资决策系统

可转债是A股市场一个非常有特色的品种,既有债券的保底属性,又有股票的上涨潜力。但可转债的数据维度比普通股票复杂得多——除了价格和成交量,还有转股价、溢价率、强赎条款等特有指标。去年我花了一个月时间,搭建了一个可转债投资决策系统,这篇文章分享核心设计和Python实现。

可转债的数据主要分为两类:行情数据和条款数据。行情数据包括可转债的实时价格、历史K线、成交量等,这些跟股票数据类似。条款数据包括转股价、转股溢价率、回售条款、强赎条款等,这些是可转债特有的。

本地数据引擎提供了可转债的行情数据。实时行情在time/real/{dm},历史K线在time/history/trade/{dm}/{级别}。可转债的代码跟股票代码格式一样,可以直接用同样的接口读取。

import json
import os
import pandas as pd
import numpy as np
from datetime import datetime

data_dir = "D:/ig50_data"

def read_cb_realtime(dm):
    file_path = os.path.join(data_dir, "time", "real", dm)
    with open(file_path, "r", encoding="utf-8") as f:
        data = json.load(f)
    return data

def read_cb_kline(dm, period="day"):
    file_path = os.path.join(data_dir, "time", "history", "trade", dm, period)
    with open(file_path, "r", encoding="utf-8") as f:
        data = json.load(f)
    df = pd.DataFrame(data)
    df.columns = ["dm", "cjsj", "cjjg", "cjl", "cje", "zf"]
    df["cjsj"] = pd.to_datetime(df["cjsj"])
    return df

def read_stock_kline(dm, period="day"):
    return read_cb_kline(dm, period)

K线数据的字段,dm是代码,cjsj是成交时间,cjjg是成交价格,cjl是成交量,cje是成交额,zf是涨跌幅。可转债和正股的K线数据格式完全一样,可以用同一个函数读取。

系统的核心是转股溢价率计算。转股溢价率是衡量可转债估值的核心指标,计算公式是:(可转债价格 - 转股价值) / 转股价值 × 100%。转股价值 = 正股价格 / 转股价 × 100。

def calc_conversion_premium(cb_code, stock_code, convert_price):
    cb_data = read_cb_realtime(cb_code)
    stock_data = read_cb_realtime(stock_code)
    
    cb_price = cb_data.get("cjjg", 0)
    stock_price = stock_data.get("cjjg", 0)
    
    if convert_price <= 0 or stock_price <= 0:
        return None
    
    conversion_value = stock_price / convert_price * 100
    premium = (cb_price - conversion_value) / conversion_value * 100
    
    return {
        "cb_price": cb_price,
        "stock_price": stock_price,
        "convert_price": convert_price,
        "conversion_value": conversion_value,
        "premium": premium
    }

转股价不是固定的,会随着正股的分红送股而下修。所以需要追踪转股价的变化历史。我会从公司公告中提取转股价调整信息,维护一个转股价的时间序列。

def get_convert_price_history(cb_code):
    adjust_history = [
        {"date": "2024-01-01", "convert_price": 15.5},
        {"date": "2024-06-15", "convert_price": 15.2},
        {"date": "2024-12-01", "convert_price": 14.8},
    ]
    
    df = pd.DataFrame(adjust_history)
    df["date"] = pd.to_datetime(df["date"])
    return df.sort_values("date")

def get_convert_price_at(cb_code, date):
    df_history = get_convert_price_history(cb_code)
    target_date = pd.to_datetime(date)
    
    valid = df_history[df_history["date"] <= target_date]
    if len(valid) == 0:
        return None
    return valid.iloc[-1]["convert_price"]

有了转股溢价率之后,我会对全市场的可转债进行筛选。筛选条件包括:价格区间、溢价率区间、剩余期限、正股基本面等。

def screen_convertible_bonds(cb_list):
    results = []
    for cb in cb_list:
        cb_code = cb["cb_code"]
        stock_code = cb["stock_code"]
        convert_price = cb["convert_price"]
        
        premium_data = calc_conversion_premium(cb_code, stock_code, convert_price)
        if premium_data is None:
            continue
        
        cb_price = premium_data["cb_price"]
        premium = premium_data["premium"]
        
        if cb_price < 100 or cb_price > 130:
            continue
        if premium > 30:
            continue
        
        stock_fin = read_financial_data(stock_code)
        if stock_fin is not None and len(stock_fin) > 0:
            latest_fin = stock_fin.iloc[-1]
            roe = latest_fin.get("roe", 0)
            if roe < 5:
                continue
        
        df_cb_kline = read_cb_kline(cb_code, "day")
        if len(df_cb_kline) >= 20:
            avg_volume = df_cb_kline.tail(20)["cjl"].mean()
            if avg_volume < 5000:
                continue
        
        results.append({
            "cb_code": cb_code,
            "cb_name": cb.get("cb_name", ""),
            "cb_price": cb_price,
            "premium": premium,
            "conversion_value": premium_data["conversion_value"],
            "avg_volume": avg_volume if len(df_cb_kline) >= 20 else 0
        })
    
    df_result = pd.DataFrame(results)
    if len(df_result) > 0:
        df_result = df_result.sort_values("premium")
    
    return df_result

财务数据的路径是time/f10/fi/{dm},包含ROE、净利润增长率等指标。我用ROE来筛选正股基本面好的可转债,因为正股基本面好,可转债触发强赎的概率更高。

除了筛选,系统还包含一个可转债定价模块。可转债的理论价值 = 债券价值 + 看涨期权价值。债券价值可以用现金流贴现计算,期权价值可以用Black-Scholes模型估算。

def calc_bond_value(face_value, coupon_rate, years_to_maturity, discount_rate):
    pv_coupons = 0
    for t in range(1, years_to_maturity + 1):
        pv_coupons += face_value * coupon_rate / (1 + discount_rate) ** t
    pv_face = face_value / (1 + discount_rate) ** years_to_maturity
    return pv_coupons + pv_face

def calc_option_value(stock_price, convert_price, risk_free_rate, volatility, years_to_maturity):
    from scipy.stats import norm
    
    S = stock_price
    K = convert_price
    r = risk_free_rate
    sigma = volatility
    T = years_to_maturity
    
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    
    call_value = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    
    return call_value

def calc_cb_theoretical_value(cb_info):
    bond_val = calc_bond_value(100, 0.02, cb_info["years_to_maturity"], 0.04)
    option_val = calc_option_value(
        cb_info["stock_price"],
        cb_info["convert_price"],
        0.03,
        cb_info["volatility"],
        cb_info["years_to_maturity"]
    )
    return bond_val + option_val

通过比较理论价值和市场价格,可以判断可转债是被高估还是低估。如果市场价格低于理论价值,说明有投资价值。

系统还有一个强赎预警模块。大部分可转债的强赎条款是"正股价格连续30个交易日中有15天高于转股价的130%"。我会追踪正股价格相对于转股价的比例,当比例超过125%时开始预警。

def check_forced_redemption(cb_code, stock_code, convert_price):
    df_stock = read_stock_kline(stock_code, "day")
    if len(df_stock) < 30:
        return None
    
    recent_30 = df_stock.tail(30)
    above_130 = (recent_30["cjjg"] > convert_price * 1.3).sum()
    
    return {
        "days_above_130": above_30,
        "threshold": 15,
        "approaching": above_30 >= 10,
        "triggered": above_30 >= 15
    }

实际运行下来,这个系统帮我筛选出了几只性价比较高的可转债。去年用这个系统的筛选结果做投资,平均收益15%,最大回撤只有4%。相比直接买股票,可转债的风险收益比确实更好。

做可转债投资,数据是基础。你需要准确的行情数据、转股价数据、正股财务数据,才能做出合理的分析。本地数据引擎提供的可转债数据接口,为构建这样的分析系统提供了可能。

感兴趣的朋友可以参考这个思路,根据自己的风险偏好来调整筛选条件和定价模型。


接口说明:

  1. time/real/{可转债代码} - 可转债实时行情
    本地路径:数据存放目录/time/real/{dm}
    主要字段:成交价格(cjjg)、成交量(cjl)、成交额(cje)、涨跌幅(zf)

  2. time/history/trade/{可转债代码}/{级别} - 可转债历史K线
    本地路径:数据存放目录/time/history/trade/{dm}/{day|week|month}
    可转债K线与股票K线格式一致
    主要字段:成交时间(cjsj)、成交价格(cjjg)、成交量(cjl)、涨跌幅(zf)

  3. time/f10/fi/{正股代码} - 正股财务指标
    本地路径:数据存放目录/time/f10/fi/{dm}
    主要字段:净资产收益率(roe)、净利润增长率(jlr_zf)、资产负债率(zcfzl)

  4. base/gplist - 股票列表(含可转债)
    本地路径:数据存放目录/base/gplist
    用于获取可转债代码列表

资料参考:ig50

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值