3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于聚宽(JoinQuant)平台的期货主力合约自动移仓换月及交易策略。
核心功能:
注意事项:
initialize 中设置账户类型为 futures。get_dominant_future。# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
"""
初始化函数,设定基准、账户类型、全局变量等
"""
# 1. 设定基准(这里用沪深300,也可以设为0)
set_benchmark('000300.XSHG')
# 2. 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 3. 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 4. 设定期货账户
# 必须将账户类型设定为 futures,否则无法交易期货
set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='futures')])
# 5. 设定期货保证金比例(可选,这里设为15%)
set_option('futures_margin_rate', 0.15)
# --- 策略参数设置 ---
# 设定要操作的期货品种代码(例如:RB 表示螺纹钢,IF 表示沪深300股指期货)
g.underlying_symbol = 'RB'
# 均线参数
g.short_window = 5 # 短期均线窗口
g.long_window = 20 # 长期均线窗口
# 记录当前操作的主力合约
g.current_contract = None
# 6. 设定定时运行
# 开盘前运行:确认主力合约
run_daily(before_market_open, time='before_open', reference_security='RB9999.XSGE')
# 开盘时运行:交易逻辑
run_daily(market_open, time='open', reference_security='RB9999.XSGE')
def before_market_open(context):
"""
开盘前运行函数:每日更新主力合约
"""
# 获取当前日期的主力合约代码
# get_dominant_future 返回如 'RB2310.XSGE'
dom_contract = get_dominant_future(g.underlying_symbol)
# 如果主力合约发生了变化(换月)
if g.current_contract and g.current_contract != dom_contract:
log.info("主力合约切换: %s -> %s" % (g.current_contract, dom_contract))
# 具体的移仓操作在 market_open 中通过检查持仓来执行
g.current_contract = dom_contract
log.info("当前主力合约: %s" % g.current_contract)
def market_open(context):
"""
开盘交易函数
"""
if g.current_contract is None:
return
# --- 1. 移仓换月逻辑 ---
# 检查当前持仓,如果持有的合约不是当前主力合约,则强制平仓
# 注意:这里是简单的平旧仓,新仓位由下面的策略逻辑决定是否开仓
# 获取多单持仓
long_positions = context.portfolio.long_positions
for security in list(long_positions.keys()):
if security != g.current_contract:
log.info("平掉旧合约多单: %s" % security)
order_target(security, 0, side='long')
# 获取空单持仓
short_positions = context.portfolio.short_positions
for security in list(short_positions.keys()):
if security != g.current_contract:
log.info("平掉旧合约空单: %s" % security)
order_target(security, 0, side='short')
# --- 2. 获取行情数据 ---
# 获取过去 g.long_window + 1 天的收盘价
# 注意:使用主力合约代码获取数据
hist = attribute_history(g.current_contract, g.long_window + 1, '1d', ['close'])
# 如果数据长度不够,不进行计算
if len(hist) < g.long_window:
return
close_prices = hist['close']
# --- 3. 计算指标 ---
# 计算短期均线
ma_short = close_prices[-g.short_window:].mean()
# 计算长期均线
ma_long = close_prices[-g.long_window:].mean()
# 获取当前价格
current_price = close_prices[-1]
# --- 4. 获取当前主力合约的持仓情况 ---
# 多单数量
long_amount = context.portfolio.long_positions[g.current_contract].total_amount
# 空单数量
short_amount = context.portfolio.short_positions[g.current_contract].total_amount
# --- 5. 交易信号判断与执行 ---
# 信号:金叉 (短均线 > 长均线) -> 做多
if ma_short > ma_long:
# 如果有空单,先平空
if short_amount > 0:
log.info("金叉:平空单")
order_target(g.current_contract, 0, side='short')
# 如果没有多单,开多单
if long_amount == 0:
log.info("金叉:开多单")
# 按价值下单,例如使用当前可用资金的 50%
# 注意:期货order_value计算的是保证金,这里简化处理,实际建议按手数下单
# 这里演示开 2 手
order(g.current_contract, 2, side='long')
# 信号:死叉 (短均线 < 长均线) -> 做空
elif ma_short < ma_long:
# 如果有多单,先平多
if long_amount > 0:
log.info("死叉:平多单")
order_target(g.current_contract, 0, side='long')
# 如果没有空单,开空单
if short_amount == 0:
log.info("死叉:开空单")
# 演示开 2 手
order(g.current_contract, 2, side='short')
get_dominant_future(symbol):
移仓换月逻辑:
market_open 的开头,我们遍历 context.portfolio.long_positions 和 short_positions。g.current_contract,就说明主力合约已经切换,或者我们持有的是非主力合约。order_target(security, 0, ...) 平掉旧合约。期货交易函数:
side 参数。side='long':操作多单(买入开多,卖出平多)。side='short':操作空单(卖出开空,买入平空)。order_target(security, 0, side='long'):表示将多单持仓调整为0,即平掉所有多单。账户设置:
set_subportfolios([SubPortfolioConfig(..., type='futures')]) 是必须的,否则回测引擎会默认这是股票账户,导致无法买入期货合约。Q: 如何将策略改为交易股指期货(如沪深300)?
A: 只需将 initialize 函数中的 g.underlying_symbol = 'RB' 改为 g.underlying_symbol = 'IF' 即可。同时建议调整保证金比例(股指期货保证金通常较高)。
Q: 为什么移仓时是先平旧仓再开新仓,而不是直接平仓开仓同时进行?
A: 在代码逻辑中,先检查并平掉非主力合约,释放保证金。随后代码向下执行到信号判断部分,如果均线形态依然符合持仓条件,会在新合约上开仓。这样可以避免保证金不足的问题。
Q: 这个策略可以直接实盘吗?
A: 不可以。这是一个回测策略示例。实盘需要考虑更多细节,如滑点控制、网络延迟、撤单逻辑、资金管理以及交易所的平今仓手续费优化等。