🚀 AI 一键生成 ptrade 策略代码

PTrade 策略教程:利用 AR 与 BR 指标构建市场情绪模型

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

问题描述

请提供一个基于 ARBR 人气意愿指标的量化策略代码

解决方案

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

策略说明

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

  1. AR (人气指标):以当天开盘价为基础,比较最高价、最低价与开盘价的关系,反映市场的人气。
  2. BR (意愿指标):以昨日收盘价为基础,比较最高价、最低价与昨日收盘价的关系,反映市场的买卖意愿。

交易逻辑(本策略示例):

  • 买入信号(金叉):当 AR 向上突破 BR(即 AR > BR 且 昨日AR < 昨日BR),且 AR < 100(处于非过热区间),视为人气回升,执行买入。
  • 卖出信号(死叉或过热):当 AR 向下跌破 BR(即 AR < BR 且 昨日AR > 昨日BR),或者 AR > 150(市场过热),执行卖出止盈/止损。

策略代码

import numpy as np
import pandas as pd

def initialize(context):
    """
    初始化函数,设置策略参数和股票池
    """
    # 设定基准(这里以沪深300为例)
    set_benchmark('000300.SS')
    
    # 设置要操作的股票池(示例:平安银行)
    # 实际使用时建议在 before_trading_start 中通过 get_index_stocks 获取指数成分股
    g.security = ['000001.SZ', '600519.SS']
    set_universe(g.security)
    
    # ARBR 计算周期,通常为 26
    g.N = 26
    
    # 设置手续费(股票:万分之三,最低5元)
    set_commission(commission_ratio=0.0003, min_commission=5.0, type='STOCK')
    # 设置滑点
    set_slippage(slippage=0.002)
    
    log.info("ARBR 策略初始化完成")

def before_trading_start(context, data):
    """
    盘前处理,每天开盘前运行一次
    """
    # 可以在这里动态更新股票池,例如获取沪深300成分股
    # g.security = get_index_stocks('000300.SS')
    # set_universe(g.security)
    pass

def calculate_arbr(security, n, current_dt):
    """
    计算 AR 和 BR 指标
    :param security: 股票代码
    :param n: 计算周期
    :param current_dt: 当前时间
    :return: (ar, br, prev_ar, prev_br) 或者 None
    """
    # 获取历史数据,需要 N+1 天的数据来计算前一天的 ARBR 用于判断交叉
    # 字段需要:high, low, open, close, preclose
    # 注意:BR计算需要昨收价,PTrade日线数据包含 preclose 字段
    count = n + 2 # 多取2天,保证能计算出当天的ARBR和昨天的ARBR
    
    df = get_history(count, frequency='1d', field=['high', 'low', 'open', 'preclose'], security_list=security, include=True)
    
    if df is None or len(df) < count:
        return None
    
    # 提取数据列
    high = df['high'].values
    low = df['low'].values
    open_p = df['open'].values
    pre_close = df['preclose'].values
    
    # --- 计算 AR ---
    # AR = Sum(High - Open) / Sum(Open - Low) * 100
    ho = high - open_p
    ol = open_p - low
    
    # --- 计算 BR ---
    # BR = Sum(High - PreClose) / Sum(PreClose - Low) * 100
    hc = high - pre_close
    cl = pre_close - low
    
    # 计算当天的 AR, BR (使用最近 N 天的数据)
    # 切片范围 [-n:] 表示最后 N 天
    ar_sum_ho = np.sum(ho[-n:])
    ar_sum_ol = np.sum(ol[-n:])
    
    br_sum_hc = np.sum(hc[-n:])
    br_sum_cl = np.sum(cl[-n:])
    
    # 避免除以零
    if ar_sum_ol == 0: ar_sum_ol = 0.0001
    if br_sum_cl == 0: br_sum_cl = 0.0001
    
    ar = (ar_sum_ho / ar_sum_ol) * 100
    br = (br_sum_hc / br_sum_cl) * 100
    
    # 计算昨天的 AR, BR (使用倒数第2天到倒数第 N+1 天的数据)
    # 切片范围 [-(n+1):-1]
    prev_ar_sum_ho = np.sum(ho[-(n+1):-1])
    prev_ar_sum_ol = np.sum(ol[-(n+1):-1])
    
    prev_br_sum_hc = np.sum(hc[-(n+1):-1])
    prev_br_sum_cl = np.sum(cl[-(n+1):-1])
    
    if prev_ar_sum_ol == 0: prev_ar_sum_ol = 0.0001
    if prev_br_sum_cl == 0: prev_br_sum_cl = 0.0001
    
    prev_ar = (prev_ar_sum_ho / prev_ar_sum_ol) * 100
    prev_br = (prev_br_sum_hc / prev_br_sum_cl) * 100
    
    return ar, br, prev_ar, prev_br

def handle_data(context, data):
    """
    盘中运行函数,处理交易逻辑
    """
    # 获取当前持仓
    positions = context.portfolio.positions
    # 获取当前可用资金
    cash = context.portfolio.cash
    # 平均分配资金(简单示例)
    if len(g.security) > 0:
        per_stock_cash = cash / len(g.security)
    else:
        per_stock_cash = 0

    for stock in g.security:
        # 过滤停牌或无数据的股票
        if stock not in data or np.isnan(data[stock]['close']):
            continue
            
        # 计算指标
        result = calculate_arbr(stock, g.N, context.blotter.current_dt)
        if result is None:
            continue
            
        ar, br, prev_ar, prev_br = result
        
        # 获取当前持仓数量
        curr_position = positions[stock].amount
        
        # --- 交易逻辑 ---
        
        # 1. 买入信号:
        # AR 向上金叉 BR (今天 AR > BR 且 昨天 AR < BR)
        # 且 AR 处于相对低位 (例如 < 100),防止高位接盘
        buy_signal = (ar > br) and (prev_ar < prev_br) and (ar < 100)
        
        # 2. 卖出信号:
        # AR 向下死叉 BR (今天 AR < BR 且 昨天 AR > BR)
        # 或者 AR 过高 (例如 > 150) 视为超买
        sell_signal = ((ar < br) and (prev_ar > prev_br)) or (ar > 150)
        
        # 执行交易
        if buy_signal and curr_position == 0:
            # 有信号且无持仓,买入
            log.info("股票: %s 触发买入信号, AR: %.2f, BR: %.2f" % (stock, ar, br))
            # 使用 order_value 按金额下单
            order_value(stock, per_stock_cash)
            
        elif sell_signal and curr_position > 0:
            # 有信号且有持仓,卖出
            log.info("股票: %s 触发卖出信号, AR: %.2f, BR: %.2f" % (stock, ar, br))
            # 卖出全部持仓
            order_target(stock, 0)

代码解析

  1. initialize:

    • 设置了基准指数、股票池、手续费和滑点。
    • 定义了全局变量 g.N = 26,这是 ARBR 指标的标准计算周期。
  2. calculate_arbr:

    • 这是核心计算函数。它通过 get_history 获取过去 N+2 天的数据。
    • AR 公式: $\frac{\sum(High - Open)}{\sum(Open - Low)} \times 100$
    • BR 公式: $\frac{\sum(High - PreClose)}{\sum(PreClose - Low)} \times 100$
    • 函数不仅计算了当天的 AR/BR,还计算了前一天的 AR/BR,用于判断“金叉”和“死叉”。
    • 加入了分母为 0 的保护机制,防止程序报错。
  3. handle_data:

    • 遍历股票池中的每一只股票。
    • 买入逻辑: 当 AR 从下向上穿过 BR(金叉),并且 AR 小于 100(说明人气刚开始回暖,尚未过热)时,全仓买入该股分配的资金。
    • 卖出逻辑: 当 AR 从上向下穿过 BR(死叉),或者 AR 绝对值超过 150(视为情绪过热,风险较大)时,清仓卖出。

注意事项

  • 数据频率: 该策略默认使用日线级别 (frequency='1d')。ARBR 指标在日线级别上效果最稳定。
  • 股票池: 示例代码中仅手动设置了两只股票。在实盘或回测中,建议在 before_trading_start 中使用 get_index_stocks 动态获取指数成分股(如沪深300)。
  • Python 版本: 代码兼容 Python 3.5 及以上版本(PTrade 环境通常支持)。

Q&A

Q1: 为什么 ARBR 指标有时候会失效?
A1: ARBR 是情绪类指标,在震荡市中表现较好。在单边暴涨或暴跌的极端行情中,指标可能会出现钝化(长期停留在高位或低位),导致过早卖出或过早抄底。建议结合均线(MA)或 MACD 等趋势指标一起使用。

Q2: 如何调整策略的灵敏度?
A2: 可以调整 g.N 的值。减小 g.N(如改为 14)会使指标更敏感,交易更频繁,但假信号也会增加;增大 g.N(如改为 42)会使指标更平滑,适合捕捉中长期趋势。

Q3: 代码中的 include=True 是什么意思?
A3: 在 get_history 中,include=True 表示获取的数据包含当前回测时间点的数据。在日线回测中,这通常意味着包含当天的收盘价(回测引擎会在收盘后撮合)。如果是盘中实时交易,获取到的可能是截至当前分钟的日线数据快照。