🚀 AI 一键生成 ptrade 策略代码

如何使用股指期货对冲股票投资组合的系统性风险?(附 PTrade 策略源码)

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

问题描述

请帮我写一个用股指期货对冲股票风险的策略。

解决方案

这是一个基于PTrade平台的股指期货对冲策略(通常称为Alpha策略或市场中性策略)。

策略原理

该策略的核心思想是:做多股票组合,同时做空同等价值的股指期货

  1. 多头部分:买入一篮子股票(例如沪深300成分股或优质蓝筹股),期望获得股票的超额收益(Alpha)。
  2. 空头部分:卖出股指期货(例如IF沪深300期指),以对冲掉市场的系统性风险(Beta)。
  3. 收益来源:如果股票组合的表现优于大盘指数,无论大盘涨跌,策略理论上都能获得正收益。

策略代码实现

import numpy as np

def initialize(context):
    """
    初始化函数,设置策略参数
    """
    # 设定基准为沪深300指数
    set_benchmark('000300.SS')
    
    # 设置股票池:这里为了演示,将在 before_trading_start 中获取沪深300成分股
    # 实际运行时建议筛选基本面较好的股票,这里简化为持有部分权重股
    g.stock_index = '000300.SS'
    
    # 设定期货合约代码
    # 注意:实盘或长周期回测中需要处理主力合约换月逻辑
    # 这里为了演示方便,固定使用某一个合约,实际使用请注意修改日期对应的合约
    g.future_code = 'IF2212.CCFX' 
    
    # 设定期货合约乘数 (IF沪深300为300点)
    g.contract_multiplier = 300
    
    # 设定保证金比例 (假设为15%,用于资金管理计算)
    g.margin_rate = 0.15
    
    # 设定股票仓位比例 (预留现金做期货保证金)
    # 假设满仓对冲,股票市值占80%,保留20%现金用于期货保证金和波动
    g.stock_ratio = 0.8
    
    # 设置手续费 (股票万3,期货万0.5)
    set_commission(commission_ratio=0.0003, min_commission=5.0, type='STOCK')
    set_future_commission("IF", 0.00005)
    
    # 每天上午10:00执行交易逻辑
    run_daily(context, trade_logic, time='10:00')

def before_trading_start(context, data):
    """
    盘前处理
    """
    # 获取沪深300成分股
    index_stocks = get_index_stocks(g.stock_index)
    
    # 为了加快回测速度和演示,我们只取前20只股票作为多头组合
    # 实际策略中应根据因子选股模型选择股票
    g.buy_list = index_stocks[:20]
    
    # 设置股票池
    set_universe(g.buy_list + [g.future_code])

def trade_logic(context):
    """
    交易主逻辑
    """
    # 1. 股票端交易:调整多头仓位
    rebalance_stocks(context)
    
    # 2. 期货端交易:根据股票市值进行对冲
    hedge_futures(context)

def rebalance_stocks(context):
    """
    股票调仓逻辑
    """
    # 获取账户总资产
    total_value = context.portfolio.portfolio_value
    
    # 计算目标股票持仓总市值
    target_stock_value = total_value * g.stock_ratio
    
    # 计算每只股票的目标市值 (等权重分配)
    if len(g.buy_list) > 0:
        target_value_per_stock = target_stock_value / len(g.buy_list)
        
        for stock in g.buy_list:
            # 下单调整股票仓位到目标价值
            order_target_value(stock, target_value_per_stock)
    
    # 卖出不在购买列表中的持仓股票
    for stock in context.portfolio.positions.keys():
        # 排除期货代码
        if stock == g.future_code:
            continue
        if stock not in g.buy_list:
            order_target(stock, 0)

def hedge_futures(context):
    """
    期货对冲逻辑
    """
    # 获取当前所有股票持仓的市值
    stock_market_value = 0.0
    positions = context.portfolio.positions
    for code, pos in positions.items():
        # 累加股票市值 (排除期货)
        if pos.business_type == 'stock': 
            stock_market_value += pos.last_sale_price * pos.amount
            
    # 获取期货最新价格
    future_price = get_price(g.future_code, count=1, frequency='1m', fields=['close'])['close'][0]
    
    if future_price <= 0:
        log.error("期货价格获取失败")
        return

    # 计算一张期货合约的价值
    contract_value = future_price * g.contract_multiplier
    
    # 计算需要做空的合约数量
    # 理论手数 = 股票总市值 / 单张合约价值
    # 使用 round 四舍五入取整
    required_short_amount = int(round(stock_market_value / contract_value))
    
    # 获取当前期货持仓
    future_position = get_position(g.future_code)
    current_short_amount = future_position.short_amount # 当前空头持仓量
    
    log.info("股票市值: %.2f, 期货价格: %.2f, 需做空手数: %d, 当前空单: %d" % (
        stock_market_value, future_price, required_short_amount, current_short_amount))
    
    # 调整期货仓位
    if required_short_amount > current_short_amount:
        # 需要增加空单 (卖出开仓)
        amount_to_open = required_short_amount - current_short_amount
        sell_open(g.future_code, amount_to_open)
        log.info("卖出开仓期货: %s, 数量: %d" % (g.future_code, amount_to_open))
        
    elif required_short_amount < current_short_amount:
        # 需要减少空单 (买入平仓)
        amount_to_close = current_short_amount - required_short_amount
        buy_close(g.future_code, amount_to_close)
        log.info("买入平仓期货: %s, 数量: %d" % (g.future_code, amount_to_close))

def handle_data(context, data):
    """
    盘中运行函数 (本策略主要逻辑在 run_daily 定时任务中,此处留空)
    """
    pass

代码关键点解析

  1. 资金分配 (g.stock_ratio)

    • 我们不能用100%的资金买股票,因为期货开仓需要缴纳保证金(通常10%-15%),且需要预留资金应对期货价格上涨带来的追加保证金风险。
    • 代码中设置 g.stock_ratio = 0.8,即80%资金买股票,20%资金留作现金和保证金。
  2. 对冲数量计算

    • 公式:需做空手数 = 股票总市值 / (期货价格 * 合约乘数)
    • IF(沪深300)的合约乘数是300。
    • 这里采用了完全市值对冲(Beta=1),即力求期货空头价值等于股票多头价值。
  3. 期货交易指令

    • sell_open(contract, amount): 卖出开仓(做空)。当股票市值增加,需要增加对冲保护时使用。
    • buy_close(contract, amount): 买入平仓(平空)。当股票市值减少,或者期货空头过多时使用。
  4. 合约选择

    • 代码中硬编码了 IF2212.CCFX。在实际长周期回测或实盘中,期货合约会到期交割。你需要编写逻辑来判断当前的主力合约(通常是当月或下月合约),并在临近交割日时进行移仓换月(平掉旧合约,开新合约)。

风险提示

  • 基差风险:期货价格和现货指数价格之间存在差价(升水或贴水)。如果贴水(期货低于现货)过深,对冲成本会很高,导致策略亏损。
  • 保证金风险:如果市场大幅上涨,期货空头会产生浮亏,如果预留现金不足,可能会被强制平仓。
  • 选股能力:该策略赚钱的前提是你的股票组合跑赢沪深300指数。如果股票组合跑输指数,该策略会亏损。

Q&A

Q: 如何处理期货合约的换月问题?
A: 在实盘中,通常会监控当前日期距离合约交割日的天数。当距离交割日(通常是每月第三个周五)仅剩几天时,执行移仓逻辑:buy_close 当前合约,同时 sell_open 下个月份的合约。

Q: 为什么不使用 order_target 来交易期货?
A: 在PTrade中,期货交易通常区分“开仓”和“平仓”操作,使用 buy_open(多开)、sell_close(多平)、sell_open(空开)、buy_close(空平)能更精确地控制持仓性质,避免锁仓或操作错误。

Q: 什么是Beta调整?
A: 上述代码假设Beta=1。如果你的股票组合波动率远大于大盘(例如全是高科技股),你可能需要做空更多的期货来覆盖风险。此时计算公式变为:需做空手数 = (股票市值 * 组合Beta) / 期货合约价值