3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个非常经典的**套期保值(Hedging)**策略需求。
在PTrade中实现这一策略,核心逻辑是:持有股票多头(买入)的同时,在期货市场建立空头(卖出)头寸。当市场下跌时,股票端的亏损可以通过期货端的盈利来抵消,从而锁定组合价值。
以下是具体的实现思路和完整的策略代码。
要实现自动化对冲,我们需要解决三个问题:
期货空单总价值 ≈ 股票持仓总价值。需做空的手数 = 股票总市值 / (期货当前价格 * 合约乘数)。请将以下代码复制到 PTrade 的策略编辑区域。
import numpy as np
def initialize(context):
"""
初始化函数
"""
# 1. 设定我们要持有的股票篮子(这里仅作示例,实盘请换成你实际持有的股票)
g.stock_list = ['600519.SS', '600036.SS', '601318.SS']
set_universe(g.stock_list)
# 2. 设定对冲使用的股指期货合约
# 注意:期货合约代码会随时间变化(如 IF2309, IF2312),实盘需定期更换或写逻辑自动获取主力合约
# 这里以 IF2312.CCFX 为例
g.future_code = 'IF2312.CCFX'
# 3. 设定基准指数用于判断趋势(这里用沪深300指数)
g.benchmark_index = '000300.SS'
# 4. 设定均线参数
g.short_window = 5
g.long_window = 20
# 5. 标记是否处于对冲状态
g.is_hedging = False
# 6. 开启交易(每天运行一次,也可以改为分钟级)
# 这里的 '09:31' 是为了避开集合竞价,确保有开盘价
run_daily(context, trade_logic, time='09:31')
def trade_logic(context):
"""
交易主逻辑
"""
# --- 第一步:管理股票持仓 (模拟持有股票) ---
# 如果没有股票持仓,先买入股票(模拟用户已有的持仓)
# 实盘中如果已有持仓,这一步可以忽略或根据实际情况调整
for stock in g.stock_list:
if get_position(stock).amount == 0:
# 简单的等权重买入
cash_per_stock = context.portfolio.cash / len(g.stock_list)
order_value(stock, cash_per_stock)
# --- 第二步:判断市场趋势 ---
# 获取基准指数的历史收盘价
hist = get_history(g.long_window + 2, '1d', 'close', g.benchmark_index)
if len(hist) < g.long_window:
return
close_prices = hist['close'].values
# 计算均线
ma_short = close_prices[-g.short_window:].mean()
ma_long = close_prices[-g.long_window:].mean()
# 获取当前股票持仓的总市值
stock_market_value = get_stock_market_value(context)
# --- 第三步:执行对冲逻辑 ---
# 情况A:死叉(短期 < 长期)且尚未对冲 -> 开启对冲(卖空期货)
if ma_short < ma_long and not g.is_hedging:
log.info("市场趋势转弱 (死叉),开始执行对冲...")
# 计算需要做空的手数
amount = calculate_hedge_amount(context, stock_market_value)
if amount > 0:
# 卖出开仓 (Sell Open)
buy_open_id = sell_open(g.future_code, amount)
if buy_open_id:
g.is_hedging = True
log.info("已卖空期货合约: %s, 数量: %d 手" % (g.future_code, amount))
# 情况B:金叉(短期 > 长期)且正在对冲 -> 结束对冲(平掉期货)
elif ma_short > ma_long and g.is_hedging:
log.info("市场趋势转强 (金叉),结束对冲,平仓期货...")
# 获取当前期货持仓
future_position = get_position(g.future_code)
# 注意:期货分多头(long)和空头(short),对冲持有的是空头
short_amt = future_position.short_amount
if short_amt > 0:
# 买入平仓 (Buy Close)
# 注意:上期所区分平今平昨,中金所(IF/IC/IM)通常不严格区分,但建议使用 close_today=False 兼容
buy_close(g.future_code, short_amt)
log.info("已平仓期货合约: %s, 数量: %d 手" % (g.future_code, short_amt))
g.is_hedging = False
# 情况C:保持对冲状态,但股票市值变动较大,需要动态调整期货仓位(可选高级功能)
# 此处为了代码简洁,暂不展示动态调仓逻辑
def get_stock_market_value(context):
"""
计算当前账户中所有股票持仓的总市值
"""
total_value = 0.0
positions = context.portfolio.positions
for sid, pos in positions.items():
# 过滤掉期货持仓,只计算股票
# PTrade中股票代码通常以 .SS 或 .SZ 结尾,或者通过 business_type 判断
if pos.business_type == 'stock':
total_value += pos.last_sale_price * pos.amount
return total_value
def calculate_hedge_amount(context, stock_value):
"""
计算需要对冲的期货手数
公式:手数 = 股票总市值 / (期货价格 * 合约乘数)
"""
# 获取期货合约信息(主要是合约乘数)
future_info = get_instruments(g.future_code)
if future_info is None:
log.error("无法获取合约信息: %s" % g.future_code)
return 0
multiplier = future_info.contract_multiplier # 合约乘数,IF通常是300
# 获取期货当前价格
# 注意:回测和交易获取价格方式略有不同,这里使用 get_snapshot 兼容性较好,或者用 get_price
# 在回测中 get_snapshot 可能不可用,改用 get_history 取最新一分钟收盘价
if is_trade():
snap = get_snapshot(g.future_code)
current_price = snap[g.future_code]['last_px']
else:
# 回测环境
h = get_history(1, '1m', 'close', g.future_code)
if len(h) > 0:
current_price = h['close'].values[-1]
else:
return 0
if current_price == 0:
return 0
# 单张合约价值
contract_value = current_price * multiplier
# 计算手数(四舍五入或向下取整)
# 这里使用简单的市值对冲(Beta=1假设)
amount = int(stock_value / contract_value)
return amount
def handle_data(context, data):
"""
盘中运行函数,本策略主要逻辑在 run_daily 中执行,此处留空
"""
pass
合约选择 (g.future_code):
IF2312.CCFX。在实际使用时,你必须将其修改为当前的主力合约(例如 IF2406.CCFX)。保证金(Margin):
合约乘数:
get_instruments 会自动获取这个乘数,无需手动硬编码。移仓换月:
buy_close),开新合约(sell_open)。上述代码未包含自动移仓逻辑,需要人工关注到期日。Q: 如何查看我的股票组合和哪个指数相关性最高?
A: 可以计算你的持仓组合每日收益率与 IF(沪深300)、IC(中证500) 的相关系数。通常大盘蓝筹选 IF,中小盘成长选 IC,微盘股选 IM。
Q: 为什么代码里用 sell_open 而不是 order?
A: 在 PTrade 的期货交易中,sell_open(卖出开仓)是专门用于建立空头头寸的函数,语义更清晰。对应的平仓函数是 buy_close(买入平仓)。