🚀 AI 一键生成 ptrade 策略代码

PTrade Level-2 数据应用:如何利用订单簿不平衡(OBI)预测短期价格走势?

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

问题描述

请帮我编写一个基于订单簿不平衡(Order Book Imbalance)的 Tick 级交易策略

解决方案

这是一个基于 订单簿不平衡 (Order Book Imbalance, OBI) 的 Tick 级高频交易策略设计。

策略原理

订单簿不平衡 (OBI) 是衡量买卖盘力量对比的一个经典微观结构指标。

  1. 计算公式
    $$ OBI = \frac{V_{bid} - V_{ask}}{V_{bid} + V_{ask}} $$

    • $V_{bid}$:买盘总量(通常取买一到买五的总挂单量)。
    • $V_{ask}$:卖盘总量(通常取卖一到卖五的总挂单量)。
  2. 指标含义

    • OBI 的取值范围在 $[-1, 1]$ 之间。
    • OBI > 0:买盘挂单量大于卖盘,市场存在潜在的上涨压力。
    • OBI < 0:卖盘挂单量大于买盘,市场存在潜在的下跌压力。
  3. 交易逻辑

    • 开仓(买入):当 $OBI > \text{阈值}$(例如 0.4),且当前无持仓时,以对手价(卖一价)买入。
    • 平仓(卖出):当 $OBI < -\text{阈值}$(例如 -0.4),且当前有持仓时,以对手价(买一价)卖出。
    • 止损:如果价格亏损超过一定比例,强制平仓。

PTrade 策略代码实现

注意

  1. tick_data 函数仅在交易模式(实盘或模拟盘)下生效,且需要开通 Level-2 行情权限才能获取完整的逐笔和五档数据。
  2. 普通的回测模式(日线/分钟线)无法运行此代码,因为它们不触发 tick_data
  3. 代码兼容 Python 3.5 语法。
# 策略名称:Tick级订单簿不平衡(OBI)策略
# 运行环境:PTrade 交易/模拟交易模式 (需L2行情权限)

def initialize(context):
    """
    初始化函数,设置股票池和全局变量
    """
    # 设定要交易的股票,建议选择流动性好的标的
    g.security = '600570.SS' 
    set_universe(g.security)
    
    # 策略参数设置
    g.obi_threshold = 0.4      # OBI阈值,超过此值触发信号
    g.trade_qty = 100          # 每次交易数量
    g.stop_loss_pct = 0.01     # 止损百分比 (1%)
    
    # 交易状态控制
    g.last_entry_price = 0.0   # 记录最后一次开仓价格
    
    log.info("OBI策略初始化完成,监控标的: %s" % g.security)

def tick_data(context, data):
    """
    Tick数据处理函数,每3秒或有新Tick时触发
    """
    security = g.security
    
    # 1. 获取当前Tick数据
    # data[security] 包含了 'tick', 'order', 'transcation'
    if security not in data:
        return
        
    tick_info = data[security].get('tick')
    if not tick_info:
        return

    # 2. 提取五档买卖盘数据
    # bid_grp 和 offer_grp 是字典,key为档位(1-5),value为列表 [价格, 数量, 笔数]
    bid_grp = tick_info.get('bid_grp')
    offer_grp = tick_info.get('offer_grp')
    
    if not bid_grp or not offer_grp:
        return

    # 3. 计算买卖盘总量 (取前5档)
    total_bid_vol = 0.0
    total_ask_vol = 0.0
    
    # 遍历1到5档
    for i in range(1, 6):
        # 确保档位存在且数据有效
        if i in bid_grp:
            # bid_grp[i][1] 是该档位的委托数量
            total_bid_vol += bid_grp[i][1]
        
        if i in offer_grp:
            # offer_grp[i][1] 是该档位的委托数量
            total_ask_vol += offer_grp[i][1]

    # 防止除以零
    if total_bid_vol + total_ask_vol == 0:
        return

    # 4. 计算 OBI 指标
    obi = (total_bid_vol - total_ask_vol) / (total_bid_vol + total_ask_vol)
    
    # 获取当前最新价和持仓信息
    current_price = tick_info['last_px']
    position = get_position(security)
    curr_amount = position.amount # 当前持仓数量
    enable_amount = position.enable_amount # 可用数量

    # 5. 止损逻辑 (优先级最高)
    if curr_amount > 0 and g.last_entry_price > 0:
        # 计算收益率
        pnl_pct = (current_price - g.last_entry_price) / g.last_entry_price
        if pnl_pct < -g.stop_loss_pct:
            log.info("触发止损: 当前价格 %s, 开仓价格 %s, 亏损 %.2f%%" % (current_price, g.last_entry_price, pnl_pct * 100))
            # 卖出平仓,使用 '1' 代表以买一价(对手价)快速成交
            order_tick(security, -enable_amount, priceGear='1')
            g.last_entry_price = 0.0
            return

    # 6. 信号生成与交易执行
    
    # 场景 A: 买入信号 (OBI > 阈值 且 空仓)
    if obi > g.obi_threshold and curr_amount == 0:
        log.info("买入信号: OBI=%.4f, 买盘量=%d, 卖盘量=%d" % (obi, total_bid_vol, total_ask_vol))
        # 以卖一价(对手价)下单买入,priceGear='-1' 代表卖一档
        order_tick(security, g.trade_qty, priceGear='-1')
        g.last_entry_price = current_price
        
    # 场景 B: 卖出信号 (OBI < -阈值 且 有持仓)
    elif obi < -g.obi_threshold and enable_amount > 0:
        log.info("卖出信号: OBI=%.4f, 买盘量=%d, 卖盘量=%d" % (obi, total_bid_vol, total_ask_vol))
        # 以买一价(对手价)下单卖出,priceGear='1' 代表买一档
        order_tick(security, -enable_amount, priceGear='1')
        g.last_entry_price = 0.0

def handle_data(context, data):
    """
    必须实现的函数,但在Tick策略中主要逻辑写在 tick_data 中
    """
    pass

代码关键点解析

  1. 数据获取 (tick_data)

    • 使用 data[security]['tick']['bid_grp'] 获取买盘档位数据。
    • PTrade 的档位数据结构通常是字典 {1: [价格, 数量, 笔数], 2: [...], ...}
    • 我们循环 range(1, 6) 来累加前五档的挂单量。
  2. OBI 计算

    • 公式简单直接,反映了当前时刻买卖盘的静态压力。
    • total_bid_voltotal_ask_vol 的对比是核心。
  3. 下单方式 (order_tick)

    • 这是专门用于 tick_data 中的下单函数。
    • priceGear='-1':表示以卖一价下单(用于买入,追求立即成交)。
    • priceGear='1':表示以买一价下单(用于卖出,追求立即成交)。
    • 这种方式比指定 limit_price 更适合高频场景,因为它自动跟随盘口。
  4. 风险控制

    • 加入了简单的百分比止损逻辑,防止单边行情造成过大亏损。
    • 检查 enable_amount(可用持仓)以避免在 T+1 制度下卖出当日买入的股票(如果是股票交易)。

常见问题 Q&A

Q: 这个策略可以在回测中运行吗?
A: 标准的 PTrade 回测通常是分钟或日线级别的,不会触发 tick_data。要测试此策略,通常需要在“研究”模块中自行获取历史 Tick 数据进行模拟撮合,或者在提供 Tick 级回测的高级环境中运行。

Q: 为什么使用 order_tick 而不是 order
A:tick_data 这种高频回调函数中,order_tick 是专用的接口,它允许通过 priceGear 参数快速指定盘口档位(如买一、卖一),比手动获取价格再传给 order 函数效率更高,且更符合盘口博弈的逻辑。

Q: 如何调整策略的灵敏度?
A: 修改 g.obi_threshold

  • 调大阈值(如 0.6):信号更少,但理论上信号质量更高(买卖盘差异巨大)。
  • 调小阈值(如 0.2):信号更频繁,但可能遭遇更多假信号(噪音)。