🚀 AI 一键生成 joinquant 策略代码

JoinQuant 平台如何编写 Pivot Points 支撑阻力策略?

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

问题描述

如何编写基于枢轴点(Pivot Points)的日内交易策略?

解决方案

编写基于枢轴点(Pivot Points)的日内交易策略,核心在于利用前一个交易日的最高价(High)、最低价(Low)和收盘价(Close)来计算当天的关键支撑位和阻力位。

由于A股市场实行T+1制度,纯粹的日内回转交易(当天买当天卖)通常需要通过股指期货(如IF、IC)或持有底仓的股票来实现。为了演示最标准的日内策略逻辑,以下代码将基于股指期货(IF - 沪深300主力合约)编写,因为期货支持T+0交易,适合日内策略。

策略逻辑

  1. 计算枢轴点(盘前计算):
    • Pivot (P) = (昨日最高价 + 昨日最低价 + 昨日收盘价) / 3
    • 阻力位 1 (R1) = 2 $\times$ P - 昨日最低价
    • 支撑位 1 (S1) = 2 $\times$ P - 昨日最高价
  2. 交易信号(盘中运行):
    • 做多信号:当价格突破 R1 时,视为多头强势,开多单。
    • 做空信号:当价格跌破 S1 时,视为空头强势,开空单。
  3. 风控与平仓:
    • 日内平仓:每日收盘前(如14:55)强制平掉所有仓位,不持仓过夜。
    • 反转平仓:如果持有空单但价格突破R1,则平空开多;反之亦然。

JoinQuant 策略代码实现

# -*- coding: utf-8 -*-
from jqdata import *

def initialize(context):
    """
    初始化函数,设定基准、手续费、账户类型等
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 重要:因为是日内T+0策略,我们需要配置期货账户
    # 初始资金设为 500,000 元
    set_subportfolios([SubPortfolioConfig(cash=500000, type='index_futures')])
    
    # 设置期货交易手续费(以中金所为例,平今仓较贵,此处仅为示例设置)
    set_order_cost(OrderCost(open_commission=0.000023, 
                             close_commission=0.000023, 
                             close_today_commission=0.0023), type='index_futures')
    
    # 定义全局变量
    g.underlying_symbol = 'IF' # 交易标的:沪深300股指期货
    g.future = None            # 存储当前主力合约代码
    
    # 存储枢轴点数据
    g.P = 0
    g.R1 = 0
    g.S1 = 0
    
    # 定时运行函数
    # 1. 开盘前计算枢轴点
    run_daily(before_market_open, time='09:00')
    # 2. 盘中每分钟检测信号
    run_daily(market_open, time='every_bar')
    # 3. 收盘前强制平仓
    run_daily(close_all_positions, time='14:55')

def before_market_open(context):
    """
    开盘前运行:获取主力合约,计算 Pivot Points
    """
    # 获取当前日期的主力合约代码
    g.future = get_dominant_future(g.underlying_symbol)
    
    # 获取前一个交易日的日线数据(High, Low, Close)
    # count=1, unit='1d' 获取的是昨天的数据
    h_data = attribute_history(g.future, 1, '1d', ['high', 'low', 'close'], skip_paused=True)
    
    if len(h_data) > 0:
        high = h_data['high'][-1]
        low = h_data['low'][-1]
        close = h_data['close'][-1]
        
        # 计算 Pivot Points
        g.P = (high + low + close) / 3
        g.R1 = 2 * g.P - low
        g.S1 = 2 * g.P - high
        
        # 记录日志
        log.info(f"主力合约: {g.future}")
        log.info(f"昨日数据 - H:{high}, L:{low}, C:{close}")
        log.info(f"今日枢轴 - P:{g.P:.2f}, R1:{g.R1:.2f}, S1:{g.S1:.2f}")

def market_open(context):
    """
    盘中运行:根据价格与 R1/S1 的关系进行交易
    """
    if not g.future:
        return
    
    # 获取当前最新价格
    current_data = get_current_data()
    if g.future not in current_data:
        return
    
    current_price = current_data[g.future].last_price
    
    # 获取当前持仓情况
    long_pos = context.portfolio.long_positions[g.future].total_amount
    short_pos = context.portfolio.short_positions[g.future].total_amount
    
    # 资金管理:每次使用约 80% 的可用资金
    available_cash = context.portfolio.available_cash
    
    # --- 交易逻辑 ---
    
    # 1. 突破 R1:看多
    if current_price > g.R1:
        # 如果持有空单,先平空
        if short_pos > 0:
            order_target(g.future, 0, side='short')
            log.info(f"价格突破 R1 ({g.R1}),平空单")
        
        # 如果没有多单,开多单
        if long_pos == 0:
            # 注意:期货开仓需要指定 side='long'
            order_value(g.future, available_cash * 0.8, side='long')
            log.info(f"价格突破 R1 ({g.R1}),开多单,价格: {current_price}")

    # 2. 跌破 S1:看空
    elif current_price < g.S1:
        # 如果持有多单,先平多
        if long_pos > 0:
            order_target(g.future, 0, side='long')
            log.info(f"价格跌破 S1 ({g.S1}),平多单")
        
        # 如果没有空单,开空单
        if short_pos == 0:
            # 注意:期货开仓需要指定 side='short'
            order_value(g.future, available_cash * 0.8, side='short')
            log.info(f"价格跌破 S1 ({g.S1}),开空单,价格: {current_price}")

    # 3. (可选) 止损逻辑:例如价格回到 P 点平仓
    # 这里为了简化,暂不添加复杂的止损,仅依赖反转信号和尾盘平仓

def close_all_positions(context):
    """
    收盘前强制平仓,确保日内交易不持仓过夜
    """
    if g.future:
        long_pos = context.portfolio.long_positions[g.future].total_amount
        short_pos = context.portfolio.short_positions[g.future].total_amount
        
        if long_pos > 0:
            order_target(g.future, 0, side='long')
            log.info("尾盘强制平多")
            
        if short_pos > 0:
            order_target(g.future, 0, side='short')
            log.info("尾盘强制平空")

代码关键点解析

  1. 账户配置 (set_subportfolios)
    • 因为是日内策略,必须使用期货账户(type='index_futures')才能实现T+0交易(当天开仓当天平仓)。如果是股票账户,买入后当天无法卖出。
  2. 数据获取 (attribute_history)
    • before_market_open 中调用 attribute_history(..., 1, '1d', ...)。在开盘前(09:00),获取过去1天的数据实际上就是昨天的收盘数据,这是计算枢轴点的标准方法。
  3. 主力合约 (get_dominant_future)
    • 期货合约会随时间换月,使用 get_dominant_future 可以自动跟踪流动性最好的主力合约。
  4. 交易执行 (order_value / order_target)
    • 期货交易必须指定 side 参数('long' 为做多,'short' 为做空)。
    • 平仓时通常使用 order_target(..., 0, side=...) 将仓位调整为0。
  5. 日内风控
    • 通过 run_daily(close_all_positions, time='14:55') 确保在收盘前5分钟平掉所有仓位,避免隔夜风险。

常见问题 Q&A

Q: 这个策略可以直接用于A股股票吗?
A: 不能直接用于开新仓。 A股是T+1制度,今天买入的股票明天才能卖出。如果你想在股票上应用此策略,需要你有“底仓”(即昨天已经持有的股票),通过“高抛低吸”的方式变相实现T+0。

Q: 为什么使用 attribute_history 而不是 get_price
A: 在 initializebefore_market_open 等回测框架函数中,attribute_history 会自动根据回测的当前时间获取历史数据,能有效避免未来函数,且语法更简洁。

Q: 如何增加 R2, S2, R3, S3 等更多支撑阻力位?
A: 你可以在 before_market_open 中添加公式:

  • $R2 = P + (High - Low)$
  • $S2 = P - (High - Low)$
    然后在 market_open 中增加相应的判断逻辑(例如突破R2加仓,或者在R2处止盈)。