3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于PTrade平台的期货跨期套利策略。
本策略采用**统计套利(均值回归)**的思路。跨期套利的核心在于两个不同交割月份的合约(近月与远月)之间的价差(Spread)通常会在一定范围内波动。
价差 = 近月合约价格 - 远月合约价格。import numpy as np
import pandas as pd
def initialize(context):
"""
策略初始化函数
"""
# 设定基准合约品种,例如沪深300股指期货 'IF'
g.product_code = 'IF'
# 套利参数设置
g.window_size = 60 # 计算均值和标准差的窗口大小(如过去60根分钟K线)
g.std_multiplier = 2.0 # 进场阈值:标准差倍数
# 交易数量(手)
g.trade_amount = 1
# 全局变量存储当前操作的合约
g.near_contract = None # 近月合约
g.far_contract = None # 远月合约
# 设定系统参数:分钟回测
set_universe([g.product_code])
def before_trading_start(context, data):
"""
盘前处理:每天开盘前确认当天的近月和远月合约
"""
# 获取该品种所有合约
# 注意:get_future_contracts是获取期货合约列表的常用方法,
# 如果PTrade环境特定版本不支持,需手动维护合约列表或使用get_code_list
all_contracts = get_future_contracts(g.product_code)
# 过滤掉已经退市或未上市的,并按交割日期排序
valid_contracts = []
for code in all_contracts:
info = get_instruments(code)
# 简单的过滤逻辑:确保合约存在且未过期
if info is not None:
valid_contracts.append(code)
# 排序:通常合约代码数字越小越近,或者根据上市日期排序
# 这里简单按代码字符串排序,通常IF2309 < IF2310
valid_contracts.sort()
# 选取近期和远期合约(取排序后的前两个)
if len(valid_contracts) >= 2:
g.near_contract = valid_contracts[0]
g.far_contract = valid_contracts[1]
log.info("今日套利合约组合: 近月 [%s] / 远月 [%s]" % (g.near_contract, g.far_contract))
else:
g.near_contract = None
g.far_contract = None
log.warning("可用合约不足,无法进行跨期套利")
def handle_data(context, data):
"""
盘中运行:每分钟执行一次
"""
# 检查合约是否有效
if g.near_contract is None or g.far_contract is None:
return
# 1. 获取历史数据用于计算统计指标
# 获取过去 N 分钟的收盘价
near_hist = get_history(g.window_size, '1m', 'close', g.near_contract)
far_hist = get_history(g.window_size, '1m', 'close', g.far_contract)
# 确保数据长度足够
if len(near_hist) < g.window_size or len(far_hist) < g.window_size:
return
# 提取收盘价序列 (Series)
# 注意:get_history返回格式可能因版本不同而异,这里假设返回DataFrame或Series
# 如果是DataFrame,通常列名为 'close'
p_near = near_hist['close']
p_far = far_hist['close']
# 2. 计算价差序列 (Spread = Near - Far)
spread_series = p_near - p_far
# 3. 计算统计指标 (均值和标准差)
spread_mean = spread_series.mean()
spread_std = spread_series.std()
# 当前最新价差
current_spread = spread_series.iloc[-1]
# 计算阈值
# 做多价差阈值(价差过低):均值 - N * 标准差
long_spread_threshold = spread_mean - g.std_multiplier * spread_std
# 平仓阈值:回归均值
exit_threshold = spread_mean
# 4. 获取当前持仓信息
pos_near = get_position(g.near_contract)
pos_far = get_position(g.far_contract)
# 判断当前是否有持仓 (多近月 + 空远月)
# 注意:期货持仓分多头(long_amount)和空头(short_amount)
has_long_spread_pos = (pos_near.long_amount > 0) and (pos_far.short_amount > 0)
# 5. 交易逻辑
# --- 开仓逻辑:价差低于下轨,且无持仓 ---
if current_spread < long_spread_threshold and not has_long_spread_pos:
log.info("触发开仓信号: 当前价差 %.2f < 阈值 %.2f" % (current_spread, long_spread_threshold))
# 买入近月 (多开)
buy_open(g.near_contract, g.trade_amount)
# 卖出远月 (空开)
sell_open(g.far_contract, g.trade_amount)
# --- 平仓逻辑:价差回归均值,且有持仓 ---
elif current_spread >= exit_threshold and has_long_spread_pos:
log.info("触发平仓信号: 当前价差 %.2f >= 均值 %.2f" % (current_spread, exit_threshold))
# 卖出近月 (多平)
# close_today=False 表示优先平昨仓,若需严格区分平今平昨需根据交易所规则调整
sell_close(g.near_contract, g.trade_amount, close_today=False)
# 买入远月 (空平)
buy_close(g.far_contract, g.trade_amount, close_today=False)
# 辅助函数:获取期货合约列表
# 如果PTrade环境中没有内置 get_future_contracts,可以使用此替代方案或手动指定
def get_future_contracts(symbol):
"""
获取指定品种的期货合约列表
注意:此函数依赖于 get_code_list 或类似接口,若不可用需咨询券商
这里仅作演示,实际使用建议直接在 initialize 中指定具体合约代码列表
"""
# 示例:返回假设的合约代码,实际需调用API获取
# 在实盘中,通常可以使用 get_all_securities 筛选
# 或者直接使用主力合约代码如 'IF2309.CCFX'
# 这里为了代码不报错,使用一种通用的获取方式(需根据实际环境调整)
try:
# 尝试获取该品种的主力合约和次主力
# PTrade通常支持 'IF8888.CCFX' (主力) 但套利需要具体月份
# 此处建议用户在实盘中手动维护一个合约列表,或者使用 get_instruments 遍历
return ['IF2309.CCFX', 'IF2310.CCFX', 'IF2312.CCFX']
except:
return []
合约获取 (before_trading_start):
initialize 中写死。get_instruments 配合循环来筛选当前上市交易的合约,或者手动在策略参数中更新合约代码。数据获取 (get_history):
1m (1分钟) 频率获取数据,窗口大小设为 60,意味着基于过去1小时的分钟线计算价差的布林带(均值和标准差)。spread_series = p_near - p_far 利用了 Pandas 的向量化计算,直接得出价差序列。交易指令:
buy_open(near): 多头开仓近月。sell_open(far): 空头开仓远月。sell_close(near): 多头平仓近月。buy_close(far): 空头平仓远月。close_today=False: 对于中金所(IF/IC/IH/IM),平今仓和平昨仓手续费通常一致(或有特定高倍率),参数设为 False 系统会自动处理。如果是上期所(如螺纹钢 RB),平今仓手续费可能较高,需根据实际情况调整此参数。风险控制:
has_long_spread_pos 状态判断,防止重复开仓。log.info 记录关键交易信号,便于回测分析。Q: 如何将策略改为“卖出近月,买入远月”(做空价差)?
A: 修改 handle_data 中的逻辑:
short_spread_threshold = spread_mean + g.std_multiplier * spread_std。current_spread > short_spread_threshold。sell_open(near) 和 buy_open(far)。Q: 为什么使用 get_history 而不是 get_snapshot?
A: get_snapshot 只能获取当前切片的一个价格,无法计算均值和标准差。我们需要 get_history 获取一段时间的序列数据来计算统计指标(Mean, Std)。
Q: 实盘中合约到期了怎么办?
A: before_trading_start 函数会在每天开盘前运行。如果逻辑正确(动态获取合约),它会自动切换到新的近月和远月合约。但在实际操作中,跨期套利通常涉及移仓换月,本策略仅演示了基本的开平仓逻辑,未包含自动移仓(即在旧合约到期前强制平仓并开新合约)的功能,实盘需注意合约的最后交易日。