🚀 AI 一键生成 joinquant 策略代码

基于 jqlib 库在 JoinQuant 构建 ARBR 情绪指标交易系统

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

问题描述

请帮我编写一个基于ARBR人气意愿指标的量化策略

解决方案

这是一个基于 ARBR(人气意愿指标) 的量化交易策略。

策略原理

ARBR 指标由 AR(人气指标)和 BR(意愿指标)两个指标构成,主要用于分析市场买卖气势的强弱。

  1. AR (人气指标):以当天开盘价为基础,比较最高价、最低价与开盘价的关系,反映市场买卖人气的强弱。
    • 公式:$AR = \frac{\sum (H - O)}{\sum (O - L)} \times 100$
  2. BR (意愿指标):以昨日收盘价为基础,比较当天最高价、最低价与昨日收盘价的关系,反映市场买卖意愿的强弱。
    • 公式:$BR = \frac{\sum \max(0, H - PC)}{\sum \max(0, PC - L)} \times 100$

策略逻辑

本策略采用经典的超买超卖反转逻辑:

  • 买入信号:当市场处于极度低迷(超卖)状态时买入。
    • 条件:BR < 40。这通常意味着空方力量衰竭,股价可能见底反弹。
  • 卖出信号:当市场处于极度亢奋(超买)状态时卖出。
    • 条件:AR > 180。这通常意味着多方力量过度消耗,股价可能见顶回落。
  • 标的:以平安银行(000001.XSHE)为例。
  • 周期:日线级别,参数 N=26。

策略代码

# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd

def initialize(context):
    """
    初始化函数,设定基准、标的、参数等
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 设定要操作的股票,这里以平安银行为例
    g.security = '000001.XSHE'
    
    # ARBR指标的计算周期,通常为26
    g.N = 26
    
    # 设定买入和卖出的阈值
    g.buy_threshold_br = 40   # BR低于此值视为超卖,买入
    g.sell_threshold_ar = 180 # AR高于此值视为超买,卖出
    
    # 每天开盘时运行策略
    run_daily(market_open, time='09:30')

def market_open(context):
    """
    每日开盘运行的逻辑
    """
    security = g.security
    
    # 1. 获取历史数据
    # 计算BR需要用到前一日收盘价,所以获取 N + 1 天的数据
    # fields: high(最高价), low(最低价), open(开盘价), close(收盘价)
    h_data = attribute_history(security, g.N + 1, '1d', ['high', 'low', 'open', 'close'])
    
    # 如果数据长度不足(例如刚上市),则跳过
    if len(h_data) < g.N + 1:
        return

    # 2. 数据预处理
    # 提取最近 N 天的数据用于计算 AR
    high_n = h_data['high'][-g.N:]
    low_n = h_data['low'][-g.N:]
    open_n = h_data['open'][-g.N:]
    
    # 提取用于计算 BR 的数据
    # 当天最高价、最低价(最近 N 天)
    high_curr = h_data['high'][-g.N:].values
    low_curr = h_data['low'][-g.N:].values
    # 前一日收盘价(取前 N+1 天数据中的前 N 个,即对应每一天的"昨日收盘")
    close_prev = h_data['close'][:-1].values

    # 3. 计算 AR 指标
    # AR = Sum(High - Open) / Sum(Open - Low) * 100
    ar_numerator = (high_n - open_n).sum()
    ar_denominator = (open_n - low_n).sum()
    
    # 防止分母为0
    if ar_denominator == 0:
        ar = 100 # 默认值
    else:
        ar = (ar_numerator / ar_denominator) * 100

    # 4. 计算 BR 指标
    # BR = Sum(MAX(0, High - PrevClose)) / Sum(MAX(0, PrevClose - Low)) * 100
    # 计算分子序列:今天最高价 - 昨天收盘价,取大于0的部分
    br_up_part = np.maximum(0, high_curr - close_prev)
    # 计算分母序列:昨天收盘价 - 今天最低价,取大于0的部分
    br_down_part = np.maximum(0, close_prev - low_curr)
    
    br_numerator = br_up_part.sum()
    br_denominator = br_down_part.sum()
    
    # 防止分母为0
    if br_denominator == 0:
        br = 100 # 默认值
    else:
        br = (br_numerator / br_denominator) * 100

    # 记录指标值到日志,方便回测查看
    # log.info("Date: %s, AR: %.2f, BR: %.2f" % (context.current_dt.date(), ar, br))
    
    # 5. 交易逻辑
    curr_position = context.portfolio.positions[security].closeable_amount
    available_cash = context.portfolio.available_cash
    
    # 信号1:买入逻辑 (BR < 40,市场人气极度低迷,意愿指标超卖)
    if br < g.buy_threshold_br:
        if available_cash > 0:
            # 全仓买入
            order_value(security, available_cash)
            log.info("买入信号触发 (BR=%.2f < %.2f): 买入 %s" % (br, g.buy_threshold_br, security))
            
    # 信号2:卖出逻辑 (AR > 180,市场人气过热,人气指标超买)
    elif ar > g.sell_threshold_ar:
        if curr_position > 0:
            # 清仓卖出
            order_target(security, 0)
            log.info("卖出信号触发 (AR=%.2f > %.2f): 卖出 %s" % (ar, g.sell_threshold_ar, security))

Q&A

Q1: 为什么计算 BR 指标时需要获取 N+1 天的数据?
A1: BR 指标的公式中包含 $(H - PC)$ 和 $(PC - L)$,其中 $PC$ 代表昨日收盘价。为了计算最近 N 天的 BR 值,我们需要这 N 天每一天对应的“前一天收盘价”,因此总共需要向前多取一天的数据。

Q2: AR 和 BR 的阈值(40 和 180)是如何确定的?
A2: 这是 ARBR 指标的经典经验值。通常认为 BR < 50 为低价区,AR > 150-180 为高价区。在实际量化中,这些参数可以通过 JoinQuant 的参数优化功能进行回测调整,以适应不同的个股波动特性。

Q3: 这个策略可以用于多只股票吗?
A3: 可以。目前的示例代码为了清晰仅针对单只股票。若要操作多只股票,可以将 g.security 改为一个股票列表,并在 market_open 函数中使用 for 循环遍历列表,对每一只股票分别计算 ARBR 并执行交易逻辑。

Q4: 为什么代码中要判断分母是否为0?
A4: 在极端行情下(例如连续一字涨停或跌停,或者长时间停牌后复牌),开盘价可能等于最低价(导致 AR 分母为0),或者昨日收盘价等于今日最低价(导致 BR 分母为0)。为了防止程序抛出 ZeroDivisionError 导致策略中断,必须进行分母非零检查。