问题描述
解决方案
R-Breaker 是一种经典的日内交易策略,结合了趋势跟随(突破)和均值回归(反转)两种逻辑。由于该策略需要进行日内频繁交易(T+0)且通常涉及做空操作,因此它最适合应用于期货市场(如股指期货 IF、商品期货等)。
以下是基于聚宽(JoinQuant)API 实现的 R-Breaker 策略代码。
策略逻辑简述
- 计算 6 个关键价位:根据前一日的最高价(High)、最低价(Low)和收盘价(Close)计算:
- 突破买入价 (B_break)
- 观察卖出价 (S_setup)
- 反转卖出价 (S_enter)
- 反转买入价 (B_enter)
- 观察买入价 (B_setup)
- 突破卖出价 (S_break)
- 交易信号:
- 趋势策略:价格突破 B_break 做多;价格跌破 S_break 做空。
- 反转策略:当日最高价超过 S_setup 后,价格回落跌破 S_enter 做空;当日最低价低于 B_setup 后,价格反弹超过 B_enter 做多。
- 风控:每日收盘前强制平仓(日内策略不隔夜)。
R-Breaker 策略代码
# -*- coding: utf-8 -*-
from jqdata import *
def initialize(context):
"""
策略初始化函数
"""
# 1. 设定基准(以沪深300指数为例)
set_benchmark('000300.XSHG')
# 2. 设定交易标的:这里以沪深300股指期货主力合约为例
# 注意:实际回测中建议使用 get_dominant_future 获取主力合约
g.future_code = 'IF9999.CCFX'
# 3. 设定账户类型为期货
set_subportfolios([SubPortfolioConfig(cash=context.portfolio.starting_cash, type='futures')])
# 4. 设定手续费(根据实际情况调整,这里设为万分之0.23)
set_order_cost(OrderCost(open_commission=0.000023, close_commission=0.000023, close_today_commission=0.0023), type='index_futures')
# 5. 设定滑点
set_slippage(PriceRelatedSlippage(0.002), type='index_futures')
# 6. 开启动态复权(真实价格)
set_option('use_real_price', True)
# 全局变量:存储当天的6个关键价位
g.B_break = 0
g.S_setup = 0
g.S_enter = 0
g.B_enter = 0
g.B_setup = 0
g.S_break = 0
# 每日开盘前运行:计算关键价位
run_daily(before_market_open, time='open')
# 交易时间内运行:每分钟检测信号
run_daily(market_open, time='every_bar')
# 收盘前运行:强制平仓
run_daily(close_market, time='14:55')
def before_market_open(context):
"""
每日开盘前计算 R-Breaker 的 6 个价位
"""
# 获取主力合约(如果是实盘或精确回测,建议每天更新主力合约代码)
# g.future_code = get_dominant_future('IF')
# 获取前一日的行情数据 (High, Low, Close)
# count=1, unit='1d' 获取的是前一天的数据
hist_data = attribute_history(g.future_code, 1, '1d', ['high', 'low', 'close'], skip_paused=True)
if len(hist_data) == 0:
return
high = hist_data['high'][0]
low = hist_data['low'][0]
close = hist_data['close'][0]
# 计算枢轴点 (Pivot)
pivot = (high + low + close) / 3.0
# 计算 6 个关键价位
g.B_break = high + 2 * (pivot - low) # 突破买入价
g.S_setup = pivot + (high - low) # 观察卖出价
g.S_enter = 2 * pivot - low # 反转卖出价
g.B_enter = 2 * pivot - high # 反转买入价
g.B_setup = pivot - (high - low) # 观察买入价
g.S_break = low - 2 * (high - pivot) # 突破卖出价
# 打印日志方便调试
log.info(f"今日 {context.current_dt.date()} R-Breaker 关键价位:")
log.info(f"B_break: {g.B_break}, S_setup: {g.S_setup}, S_enter: {g.S_enter}")
log.info(f"B_enter: {g.B_enter}, B_setup: {g.B_setup}, S_break: {g.S_break}")
def market_open(context):
"""
盘中每分钟逻辑:检查信号并交易
"""
# 14:55 之后不进行新开仓,交由 close_market 处理平仓
if context.current_dt.hour == 14 and context.current_dt.minute >= 55:
return
security = g.future_code
# 获取当前分钟的收盘价作为当前价格
current_data = get_current_data()[security]
current_price = current_data.last_price
# 获取当日截止目前的最高价和最低价(用于反转逻辑判断)
# 注意:get_current_data().high 是当日最高价
today_high = current_data.high
today_low = current_data.low
# 获取当前持仓情况
# long_positions 和 short_positions 返回的是 Position 对象
long_pos = context.portfolio.long_positions[security]
short_pos = context.portfolio.short_positions[security]
has_long = long_pos.total_amount > 0
has_short = short_pos.total_amount > 0
# ---------------- 交易逻辑 ----------------
# 1. 趋势突破逻辑 (Trend Following)
# 价格突破 B_break -> 做多 (如果有空单则平空开多)
if current_price > g.B_break:
if has_short:
# 平空单
order_target(security, 0, side='short')
log.info(f"趋势突破:平空单 {security} at {current_price}")
if not has_long:
# 开多单
order_target(security, 1, side='long')
log.info(f"趋势突破:开多单 {security} at {current_price}")
# 价格跌破 S_break -> 做空 (如果有多单则平多开空)
elif current_price < g.S_break:
if has_long:
# 平多单
order_target(security, 0, side='long')
log.info(f"趋势突破:平多单 {security} at {current_price}")
if not has_short:
# 开空单
order_target(security, 1, side='short')
log.info(f"趋势突破:开空单 {security} at {current_price}")
# 2. 均值回归/反转逻辑 (Mean Reversion)
# 价格曾冲高到 S_setup 以上,但回落跌破 S_enter -> 做空
elif (today_high > g.S_setup) and (current_price < g.S_enter):
if has_long:
# 平多单
order_target(security, 0, side='long')
log.info(f"反转策略:平多单 {security} at {current_price}")
if not has_short:
# 开空单
order_target(security, 1, side='short')
log.info(f"反转策略:开空单 {security} at {current_price}")
# 价格曾下探到 B_setup 以下,但反弹突破 B_enter -> 做多
elif (today_low < g.B_setup) and (current_price > g.B_enter):
if has_short:
# 平空单
order_target(security, 0, side='short')
log.info(f"反转策略:平空单 {security} at {current_price}")
if not has_long:
# 开多单
order_target(security, 1, side='long')
log.info(f"反转策略:开多单 {security} at {current_price}")
def close_market(context):
"""
收盘前强制平仓,确保日内交易不隔夜
"""
security = g.future_code
long_pos = context.portfolio.long_positions[security]
short_pos = context.portfolio.short_positions[security]
if long_pos.total_amount > 0:
order_target(security, 0, side='long')
log.info(f"收盘强平:平多单 {security}")
if short_pos.total_amount > 0:
order_target(security, 0, side='short')
log.info(f"收盘强平:平空单 {security}")
代码关键点解析
- 标的选择 (
g.future_code):- 代码中使用了
IF9999.CCFX(股指期货主力连续合约)作为示例。在实际回测或模拟中,建议使用get_dominant_future('IF')动态获取当月主力合约,以避免主力换月导致的数据跳空。
- 代码中使用了
- 关键价位计算 (
before_market_open):- 使用
attribute_history获取前一天的 High, Low, Close。 - 严格按照 R-Breaker 的公式计算 6 个价位。
- 使用
- 交易信号 (
market_open):- 趋势信号:优先级最高。如果价格突破最外层的
B_break或S_break,视为强趋势,直接顺势开仓。 - 反转信号:需要满足两个条件。以做空为例,必须是“当日最高价已经超过了观察卖出价
S_setup”(说明多头尝试进攻过),且“当前价格回落跌破了反转卖出价S_enter”(说明多头力竭,空头反扑)。
- 趋势信号:优先级最高。如果价格突破最外层的
- 日内平仓 (
close_market):- R-Breaker 是典型的日内策略,不留隔夜仓位以规避跳空风险。代码设定在 14:55 强制平掉所有多单和空单。
常见问题 Q&A
Q: 这个策略可以用于股票吗?
A: 原版 R-Breaker 不适合中国 A 股市场。原因有二:1. A 股是 T+1 交易,当天买入无法当天卖出,无法实现日内反转;2. A 股缺乏便捷的做空机制(融券成本高且券源不稳定)。如果强行用于股票,只能保留“突破买入”和“回调买入”的逻辑,且必须持仓过夜,风险特征会完全改变。
Q: 为什么使用 order_target 而不是 order?
A: order_target(security, 1, side='long') 确保最终持仓为 1 手。如果当前已经持有 1 手,它不会重复下单;如果当前持有空单,它会先平空再开多(逻辑需配合代码中的平仓判断)。在示例代码中,我显式地先平反向仓位再开新仓位,逻辑更加清晰。
Q: 如何优化这个策略?
A:
- 参数优化:R-Breaker 的参数(如距离 Pivot 的倍数,默认为 2 和 1)可以根据不同品种的波动率进行调整。
- 过滤震荡:在波动率极低的日子里,R-Breaker 容易产生假突破。可以加入 ATR 或成交量过滤器。
- 止损:虽然策略本身带有反转止损逻辑,但增加一个固定的百分比止损(如亏损 1% 强平)可以防止单边极端行情下的巨大回撤。