🚀 AI 一键生成 joinquant 策略代码

JoinQuant 量化实战:R-Breaker 日内反转与趋势策略实现

joinquant | 发布时间: 2025/12/22
以下内容由 EasyQuant 生成。

问题描述

请提供 R-Breaker 日内交易策略的 Python 代码

解决方案

R-Breaker 是一种经典的日内交易策略,结合了趋势跟随(突破)和均值回归(反转)两种逻辑。由于该策略需要进行日内频繁交易(T+0)且通常涉及做空操作,因此它最适合应用于期货市场(如股指期货 IF、商品期货等)。

以下是基于聚宽(JoinQuant)API 实现的 R-Breaker 策略代码。

策略逻辑简述

  1. 计算 6 个关键价位:根据前一日的最高价(High)、最低价(Low)和收盘价(Close)计算:
    • 突破买入价 (B_break)
    • 观察卖出价 (S_setup)
    • 反转卖出价 (S_enter)
    • 反转买入价 (B_enter)
    • 观察买入价 (B_setup)
    • 突破卖出价 (S_break)
  2. 交易信号
    • 趋势策略:价格突破 B_break 做多;价格跌破 S_break 做空。
    • 反转策略:当日最高价超过 S_setup 后,价格回落跌破 S_enter 做空;当日最低价低于 B_setup 后,价格反弹超过 B_enter 做多。
  3. 风控:每日收盘前强制平仓(日内策略不隔夜)。

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}")

代码关键点解析

  1. 标的选择 (g.future_code)
    • 代码中使用了 IF9999.CCFX(股指期货主力连续合约)作为示例。在实际回测或模拟中,建议使用 get_dominant_future('IF') 动态获取当月主力合约,以避免主力换月导致的数据跳空。
  2. 关键价位计算 (before_market_open)
    • 使用 attribute_history 获取前一天的 High, Low, Close。
    • 严格按照 R-Breaker 的公式计算 6 个价位。
  3. 交易信号 (market_open)
    • 趋势信号:优先级最高。如果价格突破最外层的 B_breakS_break,视为强趋势,直接顺势开仓。
    • 反转信号:需要满足两个条件。以做空为例,必须是“当日最高价已经超过了观察卖出价 S_setup”(说明多头尝试进攻过),且“当前价格回落跌破了反转卖出价 S_enter”(说明多头力竭,空头反扑)。
  4. 日内平仓 (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:

  1. 参数优化:R-Breaker 的参数(如距离 Pivot 的倍数,默认为 2 和 1)可以根据不同品种的波动率进行调整。
  2. 过滤震荡:在波动率极低的日子里,R-Breaker 容易产生假突破。可以加入 ATR 或成交量过滤器。
  3. 止损:虽然策略本身带有反转止损逻辑,但增加一个固定的百分比止损(如亏损 1% 强平)可以防止单边极端行情下的巨大回撤。