🚀 AI 一键生成 ptrade 策略代码

PTrade 可转债折价套利策略如何实现?(get_cb_info 应用)

ptrade | 发布时间: 2025/12/12
以下内容由 EasyQuant 生成。

问题描述

请帮我编写一个可转债套利策略,当可转债价格低于其转股价值时进行套利。

解决方案

这是一个基于PTrade平台的可转债折价套利策略(即当可转债价格低于转股价值时买入)。

策略逻辑说明

  1. 核心原理
    • 转股价值 = (可转债面值 / 转股价) * 正股价格
    • 溢价率 = (可转债价格 - 转股价值) / 转股价值
    • 套利机会:当溢价率为负数(即折价)时,理论上存在套利空间。
  2. 交易逻辑
    • 买入:当可转债出现折价(溢价率 < 0,或设置一个更低的阈值如 -1%),且处于交易状态时,买入该可转债。
    • 卖出:当持仓的可转债不再折价(溢价率 > 0),或者溢价率回归到一定水平时,卖出平仓。
  3. 风控与资金管理
    • 限制最大持仓数量(例如最多持仓10只),防止过度分散或资金不足。
    • 等权重分配资金。

PTrade 策略代码

import numpy as np
import pandas as pd

def initialize(context):
    """
    策略初始化函数
    """
    # 设置最大持仓数量
    g.max_holdings = 10
    
    # 设置买入阈值:溢价率小于此值时买入 (例如 -0.005 代表折价0.5%)
    g.buy_threshold = -0.001 
    
    # 设置卖出阈值:溢价率大于此值时卖出 (例如 0.01 代表溢价1%)
    g.sell_threshold = 0.01
    
    # 设定交易费率 (可转债费率通常较低,这里设为万分之一)
    set_commission(commission_ratio=0.0001, min_commission=1.0, type='bond')
    
    # 每天10:00运行一次策略逻辑 (避开开盘集合竞价波动)
    run_daily(context, trade_logic, time='10:00')
    
    # 打印日志
    log.info("可转债折价套利策略已启动")

def trade_logic(context):
    """
    每日交易主逻辑
    """
    # 1. 获取所有可转债的基础信息
    # get_cb_info 返回 DataFrame,包含 bond_code, stock_code, convert_price 等字段
    cb_info_df = get_cb_info()
    
    if cb_info_df is None or cb_info_df.empty:
        log.warning("未获取到可转债基础信息")
        return

    # 2. 获取可转债和正股的实时行情快照
    # 提取所有可转债代码
    bond_list = cb_info_df['bond_code'].tolist()
    # 提取所有正股代码
    stock_list = cb_info_df['stock_code'].tolist()
    
    # 获取快照数据 (包含最新价 last_px)
    # 注意:一次获取大量快照可能会比较慢,实盘中建议分批或使用订阅
    bond_snapshots = get_snapshot(bond_list)
    stock_snapshots = get_snapshot(stock_list)
    
    potential_buys = []
    
    # 3. 遍历计算溢价率
    for index, row in cb_info_df.iterrows():
        bond_code = row['bond_code']
        stock_code = row['stock_code']
        convert_price = row['convert_price'] # 转股价
        
        # 过滤掉数据不全的标的
        if bond_code not in bond_snapshots or stock_code not in stock_snapshots:
            continue
            
        bond_data = bond_snapshots[bond_code]
        stock_data = stock_snapshots[stock_code]
        
        # 获取最新价格
        bond_price = bond_data.get('last_px', 0)
        stock_price = stock_data.get('last_px', 0)
        
        # 过滤停牌或无成交的标的
        if bond_price <= 0 or stock_price <= 0 or convert_price <= 0:
            continue
        
        # 过滤交易状态异常的 (HALT: 暂停, SUSP: 停盘)
        if bond_data.get('trade_status') in ['HALT', 'SUSP', 'STOPT']:
            continue
            
        # 计算转股价值 = (100 / 转股价) * 正股价格
        convert_value = (100.0 / convert_price) * stock_price
        
        # 计算溢价率 = (债价 - 转股价值) / 转股价值
        premium_rate = (bond_price - convert_value) / convert_value
        
        # 记录数据
        potential_buys.append({
            'bond_code': bond_code,
            'premium_rate': premium_rate,
            'bond_price': bond_price
        })
    
    # 转换为DataFrame方便排序
    if not potential_buys:
        log.info("今日无有效可转债数据")
        return
        
    df_candidates = pd.DataFrame(potential_buys)
    
    # 4. 卖出逻辑:检查持仓,如果溢价率回归(变高),则卖出
    current_positions = context.portfolio.positions
    for bond_code in list(current_positions.keys()):
        # 获取该持仓的最新溢价率
        record = df_candidates[df_candidates['bond_code'] == bond_code]
        
        if not record.empty:
            current_premium = record.iloc[0]['premium_rate']
            # 如果溢价率高于卖出阈值,止盈/止损卖出
            if current_premium > g.sell_threshold:
                order_target(bond_code, 0)
                log.info("卖出 %s, 当前溢价率: %.2f%%, 触发卖出阈值" % (bond_code, current_premium * 100))
        else:
            # 如果取不到数据(可能停牌或退市),视情况处理,这里暂不操作
            pass

    # 5. 买入逻辑
    # 筛选出满足买入阈值(折价)的标的
    buy_candidates = df_candidates[df_candidates['premium_rate'] < g.buy_threshold]
    
    # 按溢价率从小到大排序(折价越深越优先)
    buy_candidates = buy_candidates.sort_values(by='premium_rate', ascending=True)
    
    # 获取当前持仓数量
    current_hold_count = len(context.portfolio.positions)
    available_slots = g.max_holdings - current_hold_count
    
    if available_slots > 0 and not buy_candidates.empty:
        # 计算单只标的可用资金
        cash = context.portfolio.cash
        if cash < 1000: # 资金太少不交易
            return
            
        # 简单的资金分配:剩余资金 / 剩余仓位
        # 注意:实际交易中可能需要更复杂的资金管理
        per_stock_cash = cash / available_slots
        
        for index, row in buy_candidates.iterrows():
            if available_slots <= 0:
                break
                
            target_bond = row['bond_code']
            
            # 如果已经持仓,跳过
            if target_bond in current_positions and current_positions[target_bond].amount > 0:
                continue
            
            # 下单买入
            # order_value 会自动向下取整到手(10张/1000元面值)
            order_id = order_value(target_bond, per_stock_cash)
            
            if order_id:
                log.info("买入 %s, 价格: %.3f, 溢价率: %.2f%%" % (
                    target_bond, row['bond_price'], row['premium_rate'] * 100))
                available_slots -= 1

def handle_data(context, data):
    """
    盘中运行函数,本策略主要逻辑在 run_daily 中执行,此处留空或用于风控
    """
    pass

代码关键点解析

  1. 数据获取 (get_cb_info)
    • 这是PTrade特有的API,用于获取可转债的静态数据(如转股价 convert_price 和对应的正股代码 stock_code)。这是计算转股价值的基础。
  2. 行情快照 (get_snapshot)
    • 策略使用 get_snapshot 获取最新的 last_px(最新价)。相比 get_priceget_history,快照数据在盘中交易时延更低,更适合监控实时折价机会。
  3. 溢价率计算
    • 代码中严格按照公式计算:premium_rate = (bond_price - convert_value) / convert_value
    • premium_rate 为负数时,表示折价(可转债价格便宜,理论上买入转债转股有利可图,或者等待价格回归)。
  4. 交易执行
    • 使用 order_value 按金额下单,系统会自动处理最小交易单位(可转债通常为10张,即面值1000元)。
    • 加入了 trade_status 检查,避免买入停牌的债券。

注意事项

  • 回测与实盘:此代码可直接用于回测。如果在实盘中使用,建议增加更严格的异常处理(如网络超时重试)。
  • 转股操作:本策略是基于价格回归的逻辑(低买高卖)。如果你想进行真正的“转股套利”(即买入债 -> 申请转股 -> 卖出股票),需要调用 debt_to_stock_order 接口。但请注意,转股通常是 T+1 可卖(当日买入转债,当日申请转股,次日股票到账才能卖),因此面临隔夜持仓风险,并非无风险套利。
  • 强赎风险:折价的可转债往往价格较高或临近到期,需注意是否触发“强赎”条款。可以通过 get_cb_info 中的其他字段或外部数据来过滤即将强赎的标的。

Q&A

Q: 为什么不在 handle_data 里每分钟运行?
A: get_cb_info 和全市场 get_snapshot 数据量较大,每分钟运行可能会导致回测速度极慢或触发API流控限制。对于折价套利,通常日内机会持续时间较长,或者在特定时间点(如上午10点或下午2点)检查即可。如果需要更高频,可以缩小股票池范围。

Q: 如何实现真正的 T+0 转股套利?
A: 目前A股市场可转债转股是 T+1 的。所谓的 T+0 套利通常是指拥有底仓(融券卖出正股,买入转债转股还券)或者利用转债本身的 T+0 交易属性做日内波段。本策略实现的是基于折价率的趋势回归策略。

Q: set_commission 中的 type='bond' 是什么意思?
A: 这是设置交易费率的类型。可转债的交易费用通常远低于股票,且没有印花税。在回测中设置准确的费率对套利策略(通常利润微薄)非常重要。