3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于期货期限结构(Term Structure)的量化交易策略设计。
期货期限结构是指同一品种、不同到期月份合约价格之间的关系。
核心逻辑:
价差 = 主力合约价格 - 次主力合约价格。主力 > 远月 (Backwardation):做多主力合约。主力 < 远月 (Contango):做空主力合约。以下代码实现了一个基于期限结构的自动轮动策略。为了保证回测和实盘的兼容性,我们使用成交量(Volume)来动态识别主力合约。
import numpy as np
import pandas as pd
import datetime
def initialize(context):
"""
策略初始化函数
"""
# 1. 设定要交易的品种(以螺纹钢为例)
g.product_code = 'RB'
g.exchange_suffix = '.XSGE' # 上期所后缀
# 2. 设定资金管理参数
g.leverage = 2.0 # 杠杆倍数,用于计算下单数量
# 3. 设定全局变量用于记录当前持仓合约
g.current_contract = None
# 4. 设定交易费率(可选,根据实际情况调整)
set_commission(commission_ratio=0.0001, min_commission=5.0, type='future')
# 5. 设定定时运行:每天收盘前10分钟运行策略
run_daily(context, trade_logic, time='14:50')
def get_contract_list(context, product, suffix):
"""
辅助函数:生成当前时间点可能存在的合约代码列表
PTrade没有直接获取某品种所有合约的API,需要根据日期推算
"""
contract_list = []
current_date = context.blotter.current_dt
year = current_date.year
month = current_date.month
# 生成从当前月开始往后推12个月的合约代码
# 格式通常为:RB2305.XSGE (年份后两位 + 月份两位)
for i in range(12):
y = year
m = month + i
if m > 12:
y += 1
m -= 12
# 构建合约代码,注意年份取后两位
y_str = str(y)[-2:]
m_str = "{:02d}".format(m)
code = "{}{}{}{}".format(product, y_str, m_str, suffix)
contract_list.append(code)
return contract_list
def get_dominant_contracts(contract_list):
"""
辅助函数:根据成交量找出主力合约和次主力合约
"""
# 获取这些合约的行情快照或最新行情
# 注意:回测模式下 get_snapshot 可能受限,这里使用 get_price 获取当日数据
df_list = []
for code in contract_list:
# 获取过去1天的日线数据,包含成交量
data = get_price(code, count=1, frequency='1d', fields=['close', 'volume'])
if data is not None and not data.empty and data['volume'].iloc[-1] > 0:
last_close = data['close'].iloc[-1]
volume = data['volume'].iloc[-1]
df_list.append({'code': code, 'close': last_close, 'volume': volume})
if not df_list:
return None, None
# 转换为DataFrame并按成交量降序排列
df = pd.DataFrame(df_list)
df = df.sort_values(by='volume', ascending=False)
# 取出成交量最大的作为主力,第二大的作为次主力(用于比较价格)
if len(df) >= 2:
main_contract = df.iloc[0]
next_contract = df.iloc[1]
return main_contract, next_contract
elif len(df) == 1:
return df.iloc[0], None
else:
return None, None
def trade_logic(context):
"""
核心交易逻辑
"""
# 1. 获取潜在合约列表
potential_contracts = get_contract_list(context, g.product_code, g.exchange_suffix)
# 2. 识别主力与次主力
main_info, next_info = get_dominant_contracts(potential_contracts)
if main_info is None or next_info is None:
log.info("未找到足够活跃的合约,跳过本次交易")
return
main_code = main_info['code']
main_price = main_info['close']
next_price = next_info['close']
log.info("主力合约: %s (价格: %.2f), 次主力合约: %s (价格: %.2f)" % (
main_code, main_price, next_info['code'], next_price))
# 3. 判断期限结构
# Backwardation (现货/近月溢价): 主力价格 > 次主力价格 -> 做多
# Contango (远月溢价): 主力价格 < 次主力价格 -> 做空
signal = 0 # 1为多,-1为空
if main_price > next_price:
signal = 1
log.info("检测到 Backwardation (贴水) 结构,看多主力合约")
else:
signal = -1
log.info("检测到 Contango (升水) 结构,看空主力合约")
# 4. 移仓换月与开平仓逻辑
# 如果主力合约发生了变化(换月),先平掉旧合约
if g.current_contract is not None and g.current_contract != main_code:
log.info("主力合约切换,平仓旧合约: %s" % g.current_contract)
# 平掉旧合约的所有持仓
position = get_position(g.current_contract)
if position.amount > 0: # 多头持仓
order_target(g.current_contract, 0)
elif position.amount < 0: # 空头持仓
order_target(g.current_contract, 0)
g.current_contract = None
# 计算目标持仓数量
# 获取当前账户总资产
total_value = context.portfolio.portfolio_value
# 简单的资金管理:使用总资金的一定比例开仓
# 假设合约乘数为10 (螺纹钢),保证金比例假设为10% (粗略估算,实际应通过get_instruments获取)
contract_multiplier = 10
margin_ratio = 0.1
# 可买手数 = (总资金 * 杠杆) / (价格 * 合约乘数)
target_amount = int((total_value * 0.3) / (main_price * contract_multiplier * margin_ratio))
if target_amount < 1:
target_amount = 1
# 执行交易
# 如果信号为多
if signal == 1:
# 目标是持有正向数量
order_target(main_code, target_amount)
# 如果信号为空
elif signal == -1:
# 目标是持有负向数量
order_target(main_code, -target_amount)
# 更新当前持有的合约代码
g.current_contract = main_code
def handle_data(context, data):
"""
盘中运行函数,本策略主要逻辑在 run_daily 定时任务中,此处留空
"""
pass
合约生成 (get_contract_list):
RB2305, RB2310)。这是量化回测中处理期货合约的常用技巧。主力识别 (get_dominant_contracts):
get_price 获取合约的成交量(Volume)。get_snapshot 获取持仓量(Open Interest/Amount)来判断主力,但在回测模式下 get_snapshot 可能无法获取历史切片数据,因此使用 get_price 更稳健。信号生成:
移仓换月:
if g.current_contract != main_code。下单接口:
order_target(security, amount)。在 PTrade 中,order_target 会自动计算当前持仓与目标持仓的差额,并执行相应的开仓、平仓、平今或平昨操作,简化了期货交易的复杂性。Q1: 为什么使用成交量而不是持仓量来判断主力?
A: 在 PTrade 的回测环境中,get_price 接口提供的历史数据中 volume(成交量)是最完整和准确的。虽然持仓量(Open Interest)是定义主力的标准,但在某些数据源中可能缺失。使用成交量通常能达到相同的效果,因为成交量最大的合约通常也是持仓量最大的。
Q2: 这个策略适合哪些品种?
A: 此策略最适合具有明显周期性或库存周期的商品期货,例如:
Q3: 如何调整杠杆?
A: 代码中 target_amount 的计算逻辑里,total_value * 0.3 代表使用30%的资金作为保证金。你可以调整这个比例来控制实际杠杆。
Q4: 回测时需要注意什么?
A: 务必设置好手续费 (set_commission) 和保证金比例。期货交易对滑点和手续费非常敏感,尤其是频繁换月的策略。