🚀 AI 一键生成 ptrade 策略代码

PTrade 平台如何编写 OBV 能量潮交易策略?

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

问题描述

请帮我编写一个基于 OBV 能量潮指标的量化策略

解决方案

这是一个基于 OBV (On-Balance Volume,能量潮) 指标的量化交易策略。

策略原理

OBV 指标通过统计成交量的变动趋势来推测股价趋势。

  1. 计算 OBV
    • 如果今日收盘价 > 昨日收盘价,则今日 OBV = 昨日 OBV + 今日成交量。
    • 如果今日收盘价 < 昨日收盘价,则今日 OBV = 昨日 OBV - 今日成交量。
    • 如果今日收盘价 = 昨日收盘价,则今日 OBV = 昨日 OBV。
  2. 交易逻辑 (OBV 均线交叉策略)
    • 为了平滑信号,我们计算 OBV 的移动平均线 (MA_OBV)。
    • 买入信号:当 OBV 线上穿 MA_OBV 线(金叉),视为资金流入,看涨。
    • 卖出信号:当 OBV 线跌破 MA_OBV 线(死叉),视为资金流出,看跌。

策略代码

import talib
import numpy as np

def initialize(context):
    """
    初始化函数,设置股票池、参数和手续费
    """
    # 设置要操作的股票,这里以恒生电子为例
    g.security = '600570.SS'
    # 设置股票池
    set_universe(g.security)
    
    # 策略参数
    # OBV均线周期,通常取30天,可根据回测调整
    g.obv_ma_window = 30
    
    # 设置回测时的手续费,股票买入万三,卖出万三加千一印花税
    set_commission(commission_ratio=0.0003, min_commission=5.0, type='STOCK')
    # 设置滑点
    set_slippage(slippage=0.002)

def handle_data(context, data):
    """
    盘中运行函数,每个单位时间(如每天)运行一次
    """
    security = g.security
    
    # 1. 获取历史数据
    # 我们需要足够的数据来计算OBV和它的均线
    # 获取数量 = 均线周期 + 缓冲期(用于指标初始化)
    count = g.obv_ma_window + 100
    
    # 获取收盘价和成交量,使用前复权(pre)以保证价格连续性
    # get_history 返回的是 DataFrame
    hist = get_history(count, frequency='1d', field=['close', 'volume'], security_list=security, fq='pre')
    
    # 如果数据不足,直接返回
    if len(hist['close']) < count:
        return

    # 提取 close 和 volume 为 numpy 数组,talib 需要 numpy 数组作为输入
    close_prices = hist['close'].values
    volumes = hist['volume'].values
    
    # 2. 计算 OBV 指标
    # 使用 talib 库计算 OBV
    # 注意:talib.OBV 返回的是一个数组
    obv = talib.OBV(close_prices, volumes)
    
    # 3. 计算 OBV 的移动平均线 (MA)
    # 这里使用简单移动平均 SMA
    obv_ma = talib.SMA(obv, timeperiod=g.obv_ma_window)
    
    # 4. 获取当前和前一时刻的指标值用于判断交叉
    # 当前周期的 OBV 和 MA
    current_obv = obv[-1]
    current_obv_ma = obv_ma[-1]
    
    # 前一周期的 OBV 和 MA
    prev_obv = obv[-2]
    prev_obv_ma = obv_ma[-2]
    
    # 检查计算结果是否包含 NaN (数据不足时 talib 会返回 NaN)
    if np.isnan(current_obv_ma) or np.isnan(prev_obv_ma):
        return

    # 5. 获取当前持仓和资金情况
    position = get_position(security)
    current_cash = context.portfolio.cash
    
    # 6. 生成交易信号
    
    # 金叉:上穿均线 -> 买入
    # 条件:前一时刻 OBV <= 前一时刻 MA,且 当前 OBV > 当前 MA
    if prev_obv <= prev_obv_ma and current_obv > current_obv_ma:
        # 如果有可用资金,全仓买入
        if current_cash > 0:
            log.info("OBV金叉,买入股票: %s" % security)
            order_value(security, current_cash)
            
    # 死叉:下穿均线 -> 卖出
    # 条件:前一时刻 OBV >= 前一时刻 MA,且 当前 OBV < 当前 MA
    elif prev_obv >= prev_obv_ma and current_obv < current_obv_ma:
        # 如果有持仓,清仓卖出
        if position.amount > 0:
            log.info("OBV死叉,卖出股票: %s" % security)
            order_target(security, 0)

代码解析

  1. 数据获取 (get_history):

    • 我们获取了 close (收盘价) 和 volume (成交量)。
    • count 设置得比较大 (g.obv_ma_window + 100),这是因为 OBV 是累积指标,且计算移动平均线 (MA) 需要前面的数据作为铺垫,否则初期计算结果会是 NaN
  2. 指标计算 (talib):

    • PTrade 支持 talib 库,这是计算技术指标最高效的方法。
    • talib.OBV(close, volume) 直接计算出 OBV 序列。
    • talib.SMA(obv, timeperiod) 对 OBV 序列再做一次平滑处理,得到均线。
  3. 信号判断:

    • 策略通过比较 current (当前) 和 prev (前一期) 的数值关系来判断“交叉”。
    • 金叉prev_obv <= prev_macurr_obv > curr_ma
    • 死叉prev_obv >= prev_macurr_obv < curr_ma
  4. 交易执行:

    • order_value(security, cash):用当前所有现金买入。
    • order_target(security, 0):将持仓调整为 0,即清仓。

注意事项

  • Python 版本:代码兼容 Python 3.5+,未使用 f-string 等新特性。
  • 复权get_history 中使用了 fq='pre' (前复权)。对于技术指标策略,使用前复权非常重要,否则分红派息导致的价格缺口会扭曲指标计算。
  • 有效性:OBV 策略在趋势明显的市场中效果较好,但在震荡市中可能会频繁发出假信号,建议结合其他指标(如 MACD 或 RSI)进行过滤。

Q&A

Q: 为什么 OBV 指标需要配合均线使用?
A: 原始的 OBV 曲线波动较大且没有固定的取值范围(不像 RSI 在 0-100 之间)。单独看 OBV 的数值没有意义,重要的是它的趋势。通过加上一条移动平均线(MA),可以构建出相对的参照系,从而通过金叉和死叉来捕捉趋势的转折点。

Q: 代码中的 talib 是什么?
A: talib (Technical Analysis Library) 是一个广泛使用的金融技术分析库,PTrade 平台原生支持该库。它计算指标的速度比自己用 Python 写循环要快得多,且计算逻辑标准。

Q: 如何修改策略操作多只股票?
A: 目前代码针对单只股票 (g.security 为字符串)。若要操作多只股票,需将 g.security 设为列表,并在 handle_data 中使用 for security in g.security: 循环遍历每只股票,分别获取数据、计算指标和下单。