期货多品种R-breaker策略
R-Breaker是一种高频的日内交易策略,在2010年之前被Future Truth杂志评为最赚钱的策略之一。R-Breaker策略在日内交易,由于中国股市实行“T+1”,而期货市场为”T+0”,因此该策略只适用期货市场,而在中国股票市场无法实现。
R-Breaker包括了趋势和反转两种交易方式,通过分钟级指标判断买入卖出条件,交易机会相对较多。本策略利用R-breaker作为开仓平仓逻辑,交易多个期货品种的主力合约,主要通过价格的短期变化获利。
1.原理
R-breaker策略主要包含以下部分:
- 利用昨日K线计算6个目标价位
- 趋势策略设计与反转策略设计
- 根据当前bar的价格信息(1分钟或者5分钟)判断交易
- 每日收盘前平仓
1.1 计算目标价位
根据昨日的期货价格计算出今日的6个目标价位,价格从高到低依次为:
- 突破买入价(Bbreak)
- 观察卖出价(Ssetup)
- 反转卖出价(Senter)
- 反转买入价(Benter)
- 观察买入价(Bsetup)
- 突破卖出价(Sbreak)
一种计算方法如下:(该方法便于调整参数,也可以使用”中心价位“的方式计算6个目标价位,参见:https://www.myquant.cn/docs/python_strategyies/425)
- 观察卖出价(Ssetup)= High + a * (Close – Low)
- 观察买入(Bsetup)= Low – a * (High – Close)
- 反转卖出价(Senter)= b / 2 * (High + Low) – c * Low
- 反转买入价(Benter)= b / 2 * (High + Low) – c * High
- 突破卖出价(Sbreak)= Bsetup - d * (Ssetup – Bsetup)
- 突破买入价(Bbreak)= Ssetup + d * (Ssetup – Bsetup)
其中a、b、c、d为参数,满足 b - c =1,并且b越大,Senter越大,Benter越小;d越大,Bbreak越大,Sbreak越小。可以通过调整参数改变价位,从而调整交易频率,但注意不能改变6个价格的相对大小。
1.2 设计策略逻辑
- 趋势策略
该策略主要在没有持仓情况下,判断是否有上涨(下跌)的趋势,从而实现多头(空头)开仓。
- 当前价格>突破买入价(Bbreak),开仓做多;
- 当前价格<突破卖出家(Sbreak),开仓做空。
- 反转策略
反转策略包括在持仓与没有持仓的情况下的交易,根据走势进行反转。
- 若当日最高价>观察卖出价(Ssetup),然后下跌导致当前价格<反转卖出价(Senter),没有持仓时则开仓做空,有多头持仓时则先平仓再反向开仓做空;
- 若当日最低价<观察买入价(Bsetup),然后上涨导致当前价格>反转买入价(Senter),没有持仓时则开仓做多,有空头持仓时则先平仓再反向开仓做多。
注意:
- 如果通过突破价格开仓,触发反转会导致止损
- 在持仓下的设置止损
- 设置止盈止损
- 在持多头时,收益达到2%则触发止盈,价格下跌到观察买入价(Bsetup)触发止损(一般设置为Sbreak,这里为了更加稳健)
- 在持空头时,收益达到2%则触发止盈,价格上涨到观察卖出价(Ssetup)触发止损(一般设置为Bbreak,这里为了更加稳健)
- 收盘前平仓
- 本策略日盘设置14:59:59平仓,夜盘设置22:59:59平仓,不交易深夜盘
2. 策略代码
本策略基于聚宽(JoinQuant)平台编写,参考代码逻辑可以移植。
代码整体框架
依赖库
from jqdata import *
import pandas as pd
initialize(context):
策略的主要函数,它在回测过程开始时调用一次。该函数设置交易策略的初始参数,例如基准、起始现金和佣金费率。它还将交易模式设置为使用实际价格,并过滤掉低级别的日志消息。此外,它还设置了期货相关的参数,例如保证金率、订单成本和滑点。
# 初始化函数,设定基准等等
def initialize(context):
set_parameter(context)
# 设定基准银华日利,在多品种的回测当中基准没有参考意义
set_benchmark('511880.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
### 期货相关设定 ###
# 设定账户为金融账户
set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='futures')])
# 期货类每笔交易时的手续费是:买入时万分之0.23,卖出时万分之0.23,平今仓为万分之23
set_order_cost(OrderCost(open_commission=0.00005, close_commission=0.00005, close_today_commission=0.00005),
type='index_futures')
# 设定保证金比例,如果不设置,使用默认保证金比例
set_option('futures_margin_rate', 0.15)
# 设置滑点(单边万5,双边千1)
set_slippage(PriceRelatedSlippage(0.001), type='future')
# 开盘前运行
run_daily(before_market_open, time='08:30', reference_security=get_future_code('JD'))
# 开盘时运行,使用天然橡胶RU作为参考,即不交易深夜夜盘
run_daily(market_open, time='every_bar', reference_security=get_future_code('RU'))
# 收盘前运行
run_daily(close_amount, time='14:59:59', reference_security=get_future_code('RU'))
run_daily(close_amount, time='22:59:59', reference_security=get_future_code('RU')) # 如果不运行夜盘,可以直接注释掉这行
# 收盘后运行
run_daily(after_market_close, time='03:00', reference_security=get_future_code('RU'))
确定每日函数运行时间,在每日8:30运行开盘前函数,初始化参数;分别在14:59:59与22:59:59运行收盘前函数,平仓;在03:00运行收盘后函数,还原部分参数。可以通过修改参考代码和运行时间允许交易深夜盘或放弃夜盘。
set_parameter(context)
该函数用于初始化在 R-breaker 交易策略中使用的各种变量和字典。该函数在交易过程开始时被调用,设置策略所需的必要参数。使用全局变量简化函数传参。
def set_parameter(context):
# 变量设置
g.future_list = [] # 设置期货品种列表
g.MappingReal = {
} # 真实合约映射(key为symbol,value为主力合约)
g.MappingIndex = {
} # 指数合约映射 (key为 symbol,value为指数合约
g.break_price = {
} # 突破价格映射
g.maxmin_price = {
} # 存储各个期货品种的当日最高价和最低价
g.tradeAmount = {
} # 设置交易次数的映射,每交易一次则增加次数,改变开仓阈值,防止过度交易
g.tradePrice = {
} # 保存每次交易价格
g.amount = 10 # 设置默认交易的手数
# 交易的期货品种信息
g.instruments = []
# 以下为夜盘交易品种
g.instruments_eve = ['A', 'AG', 'AL', 'AU', 'B', 'BU', 'C', 'CF', 'CS', 'CU', 'FG', 'FU', 'HC', 'I', 'J', 'JM', 'M', 'MA', 'NI', 'OI',
'P', 'PB', 'PP', 'RB', 'RM', 'RO', 'RU', 'SN', 'SR', 'TA', 'TC', 'Y', 'ZN']
# 价格列表初始化,获取价格
set_future_list(context)
set_future_list(context):
用于设置期货合约列表的函数。在函数中,首先使用 get_future_code
函数获取每个资产的期货代码,然后使用 get_dominant_future
函数获取其对应的主力合约代码。接着,将这些代码存储在 MappingIndex
和 MappingReal
字典中,以便后续使用。如果主力合约代码为空,则跳过该资产。否则,将主力合约代码添加到 future_list
列表中,以便后续使用。
# 合约信息
def set_future_list(context):
for ins in g.instruments:
idx = get_future_code(ins)
dom = get_dominant_future(ins)
# 填充映射字典
g.MappingIndex[ins] = idx
g.MappingReal[ins] = dom
# 设置主力合约已上市的品种基本参数
if dom == '':
pass
else:
if dom not in g.future_list:
g.future_list.append(dom)
judge(bar_data, context, RealFuture):
R-breaker策略的核心函数,判断开仓平仓条件。
每次交易固定手数amount=10,并且开仓时要求可用保证金大于500,000元,以防范风险。
-
没有持仓,分为四种可能情况开仓:
在未持仓的情况下,如果盘中价格超过突破买入价Bbreak,则采取趋势策略,即在该点位开仓做多;
在未持仓的情况下,如果盘中价格跌破突破卖出价Sbreak,则采取趋势策略,即在该点位开仓做空;
未持仓下,如果日最低价格跌破Bsetup,且当前价格上穿Benter,则开多仓,反转策略;
未持仓下,如果日最低价格突破Ssetup,且当前价格下穿Senter,则开空仓,反转策略。
-
持仓情况下,判断止盈止损与另外一组反转策略:
- 持有多头条件
当前价格低于Bsetup,平仓止损;
当前价格高于购买价的102%,平仓止盈;
日最低价格突破Ssetup,且当前价格下穿Senter,则平多头开空头。
- 持有空头条件
当前价格高于Ssetup,平仓止损;
当前价格低于购买价的98%,平仓止盈;
日最低价格跌破Bsetup,且当前价格上穿Benter,则平空仓开多仓。
注意:每一次开仓记录交易价格,用于判断百分比止盈;每次开仓记录当前开仓次数,用于加强开仓条件,即下一次开仓判断会比上一次更苛刻,防止反复开平仓。
# 交易函数
def judge(bar_data, context, RealFuture):
# 输出当前可用保证金
# log.info('当前可用保证金:' , context.portfolio.available_cash)
# 设置合约乘数
# symbol = RealFuture[:2]
# multiple = get_lots(symbol)
break_price = g.break_price
amount = g.amount
# 设置一个系数,随着交易次数增加而变化,防止过度交易
beta = 1 + 0.005 * g.tradeAmount[RealFuture]
# 持仓情况
# print('多仓:'+str(context.portfolio.long_positions))
# print('空仓:'+str(context.portfolio.short_positions))
# 突破策略,该策略用于在价格高于(低于)突破买入价(突破卖出价)时,采取趋势策略,即在该点位开仓做多(做空)
# 首先判断是否有持仓,若持仓,则判断止损,若不持仓,则判断是否满足开仓条件
if (RealFuture not in context.portfolio.long_positions.keys()) and (RealFuture not in context.portfolio.short_positions.keys()):
if bar_data['close'][