🚀 AI 一键生成 ptrade 策略代码
立即体验

如何在 PTrade 中解析 Level-2 十档行情并计算订单流不平衡(OFI)因子?

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

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: PTrade Level-2 高频因子:买卖盘口订单流不平衡(OFI)因子构建

Question: 在 ptrade 中如何解析 Level-2 十档行情并计算订单流不平衡因子?

解决方案

PTrade Level-2 高频因子:买卖盘口订单流不平衡(OFI)因子构建 ## 1. 订单流不平衡(OFI)因子原理 订单流不平衡(Order Flow Imbalance, OFI)是高频微观结构研究中的经典因子,用于衡量买卖双方在最佳买卖价位上的订单流变化,反映短期价格变动的供求推动力。 ### OFI 计算公式: 对于 $t$ 时刻的最佳买一与卖一档位: 1. 买盘变化量 $e_t^{bid}$: - 若 $P_t^{bid} > P_{t-1}^{bid}$,则 $e_t^{bid} = V_t^{bid}$ - 若 $P_t^{bid} = P_{t-1}^{bid}$,则 $e_t^{bid} = V_t^{bid} - V_{t-1}^{bid}$ - 若 $P_t^{bid} < P_{t-1}^{bid}$,则 $e_t^{bid} = 0$ 2. 卖盘变化量 $e_t^{ask}$: - 若 $P_t^{ask} < P_{t-1}^{ask}$,则 $e_t^{ask} = V_t^{ask}$ - 若 $P_t^{ask} = P_{t-1}^{ask}$,则 $e_t^{ask} = V_t^{ask} - V_{t-1}^{ask}$ - 若 $P_t^{ask} > P_{t-1}^{ask}$,则 $e_t^{ask} = 0$ 3. 单期 OFI 因子: $$OFI_t = e_t^{bid} - e_t^{ask}$$ 通过对一段时间内的 $OFI_t$ 进行累加,可以得到区间微观订单流不平衡度。 --- ## 2. PTrade 中的 Level-2 盘口数据结构 在 PTrade 中,可以通过 get_snapshot(security) 获取盘口快照,其返回的字典格式包含: - bid_grp: 委买档位字典,格式为 {档位: [价格, 委托量, 委托笔数]},如 {1: [42.71, 200, 5]}。 - offer_grp: 委卖档位字典,格式与 bid_grp 相同。 --- ## 3. Python 策略源码实现 以下代码演示如何在 PTrade 的 tick_data 事件或周期函数中动态计算 OFI 因子并进行交易信号判断: python def initialize(context): g.security = '600570.SS' set_universe(g.security) # 记录上一 Tick 的买卖一价与量 g.prev_bid_price = None g.prev_bid_vol = None g.prev_ask_price = None g.prev_ask_vol = None g.ofi_window = [] def calc_ofi(bid_price, bid_vol, ask_price, ask_vol, prev_bid_price, prev_bid_vol, prev_ask_price, prev_ask_vol): # 计算买盘变化量 if prev_bid_price is None: return 0.0 if bid_price > prev_bid_price: e_bid = bid_vol elif bid_price == prev_bid_price: e_bid = bid_vol - prev_bid_vol else: e_bid = 0.0 # 计算卖盘变化量 if ask_price < prev_ask_price: e_ask = ask_vol elif ask_price == prev_ask_price: e_ask = ask_vol - prev_ask_vol else: e_ask = 0.0 return e_bid - e_ask def tick_data(context, data): sec = g.security if sec not in data: return tick_info = data[sec].get('tick', None) if tick_info is None or tick_info.empty: return # 提取买一和卖一数据 bid_grp = tick_info['bid_grp'].iloc[0] offer_grp = tick_info['offer_grp'].iloc[0] if not bid_grp or not offer_grp: return bid_price, bid_vol = bid_grp[1][0], bid_grp[1][1] ask_price, ask_vol = offer_grp[1][0], offer_grp[1][1] # 计算 OFI ofi = calc_ofi(bid_price, bid_vol, ask_price, ask_vol, g.prev_bid_price, g.prev_bid_vol, g.prev_ask_price, g.prev_ask_vol) # 更新历史价格量 g.prev_bid_price, g.prev_bid_vol = bid_price, bid_vol g.prev_ask_price, g.prev_ask_vol = ask_price, ask_vol # 维持最近 20 个 Tick 的滑动窗口 g.ofi_window.append(ofi) if len(g.ofi_window) > 20: g.ofi_window.pop(0) sum_ofi = sum(g.ofi_window) log.info('当前 20-Tick 累积 OFI 因子值为: %s' % sum_ofi) def handle_data(context, data): pass --- ## 4. 注意事项 1. Level-2 行情权限:解析多档盘口委托量和笔数数据需开通交易环境的 Level-2 行情权限。 2. 数据清洗:高频行情快照可能存在丢包或时间戳不连续的情况,在计算差分时建议校验价格与时间戳。 3. 因子扩展:可将一档 OFI 因子扩展至前五档或前十档(多档加权 OFI),以提升因子的稳定性和预测能力。