3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
利用 QMT 的 Level 2 数据计算 买卖压力失衡(Order Imbalance) 是高频交易和短线策略中常用的因子。买卖压力失衡主要衡量订单簿中买盘和卖盘力量的差异,用于预测短期价格走势。
在 QMT 中,我们可以通过两种主要方式利用 Level 2 数据来计算失衡:
get_full_tick 获取买一到买十(或买五)的挂单量,计算加权或简单的量比。l2quoteaux(Level 2 行情快照指标)获取全市场的委买总量和委卖总量。下面我将为您提供详细的计算逻辑和一个完整的 Python 策略代码示例。
这是最常用的微观结构因子。公式如下:
$$ Imbalance = \frac{\sum(BidVol_i) - \sum(AskVol_i)}{\sum(BidVol_i) + \sum(AskVol_i)} $$
利用 Level 2 特有的“总委买量”和“总委卖量”数据:
$$ TotalImbalance = \frac{TotalBidQty - TotalOffQty}{TotalBidQty + TotalOffQty} $$
以下代码展示了如何在 QMT 中同时计算这两种失衡指标。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
# 1. 设置股票池 (示例使用 浦发银行 和 平安银行)
# 注意:Level 2 数据通常需要开通相应权限
ContextInfo.stock_list = ['600000.SH', '000001.SZ']
ContextInfo.set_universe(ContextInfo.stock_list)
# 2. 设置账号 (实盘需要,回测可忽略或设置虚拟账号)
# ContextInfo.set_account('您的资金账号')
# 3. 订阅行情
# 'tick': 用于获取盘口挂单 (买一到买五/买十)
# 'l2quoteaux': Level 2 特色指标,包含总委买/委卖量、撤单量等
for stock in ContextInfo.stock_list:
ContextInfo.subscribe_quote(stock, period='tick', dividend_type='none')
ContextInfo.subscribe_quote(stock, period='l2quoteaux', dividend_type='none')
print("策略初始化完成,已订阅 Tick 和 Level 2 快照数据")
def handlebar(ContextInfo):
# 获取当前 K 线位置,避免在历史数据回放时重复计算(视需求而定)
if not ContextInfo.is_last_bar():
return
# 遍历股票池计算压力失衡
for stock in ContextInfo.stock_list:
calculate_pressure_imbalance(ContextInfo, stock)
def calculate_pressure_imbalance(ContextInfo, stock_code):
"""
计算买卖压力失衡的核心函数
"""
# ------------------------------------------------------------------
# 方法一:基于盘口挂单 (Order Book) 的失衡计算
# ------------------------------------------------------------------
full_tick = ContextInfo.get_full_tick([stock_code])
if not full_tick:
return
tick_data = full_tick.get(stock_code)
if tick_data:
# 获取买盘和卖盘的挂单量列表 (通常为5档或10档,取决于行情权限)
# bidVol: [买1量, 买2量, ...]
# askVol: [卖1量, 卖2量, ...]
bid_vols = tick_data.get('bidVol', [])
ask_vols = tick_data.get('askVol', [])
# 简单求和计算 (也可以根据档位加权,例如给买1更高的权重)
sum_bid_vol = sum(bid_vols)
sum_ask_vol = sum(ask_vols)
# 防止分母为0
if (sum_bid_vol + sum_ask_vol) > 0:
# 计算盘口失衡度 [-1, 1]
lob_imbalance = (sum_bid_vol - sum_ask_vol) / (sum_bid_vol + sum_ask_vol)
else:
lob_imbalance = 0.0
print(f"[{stock_code}] 盘口失衡度(LOB): {lob_imbalance:.4f} (买量:{sum_bid_vol}, 卖量:{sum_ask_vol})")
# ------------------------------------------------------------------
# 方法二:基于 Level 2 总委托量 (Total Queue) 的失衡计算
# ------------------------------------------------------------------
# 使用 get_market_data_ex 获取 l2quoteaux 数据
# 注意:count=-1 表示取最新一笔
l2_data = ContextInfo.get_market_data_ex(
fields=[], # 空列表代表获取所有字段
stock_code=[stock_code],
period='l2quoteaux',
count=1,
subscribe=True
)
if stock_code in l2_data and not l2_data[stock_code].empty:
df_l2 = l2_data[stock_code]
# 获取最新的一行数据
latest_l2 = df_l2.iloc[-1]
# 字段说明 (参考 QMT 文档):
# totalBidQuantity: 委买总量
# totalOffQuantity: 委卖总量
total_bid_qty = latest_l2.get('totalBidQuantity', 0)
total_off_qty = latest_l2.get('totalOffQuantity', 0)
# 计算总委托失衡度
if (total_bid_qty + total_off_qty) > 0:
total_imbalance = (total_bid_qty - total_off_qty) / (total_bid_qty + total_off_qty)
else:
total_imbalance = 0.0
print(f"[{stock_code}] 总委托失衡度(L2): {total_imbalance:.4f} (总委买:{total_bid_qty}, 总委卖:{total_off_qty})")
# --------------------------------------------------------------
# 简单的交易信号示例
# --------------------------------------------------------------
# 逻辑:如果盘口买压大 且 总委买量也大,视为强买入信号
if lob_imbalance > 0.6 and total_imbalance > 0.3:
print(f"!!! 发现买入信号: {stock_code} 买压显著 !!!")
# order_shares(stock_code, 100, 'fix', tick_data['lastPrice'], ContextInfo, 'account_id')
print("-" * 30)
数据订阅 (subscribe_quote):
period='l2quoteaux' 才能获取 Level 2 的快照指标(如总委买/委卖量)。period='tick' 用于获取高频的盘口挂单数据。获取盘口数据 (get_full_tick):
bidVol 和 askVol 是列表。bid_vols 进行加权。例如,买一的权重设为 1.0,买五的权重设为 0.2,因为越靠近成交价的挂单对价格影响越大。获取 Level 2 统计数据 (get_market_data_ex + l2quoteaux):
totalBidQuantity (委买总量) 和 totalOffQuantity (委卖总量) 反映了市场上所有的意愿,不仅仅是前几档。pandas.DataFrame,方便进行时间序列分析。为什么 l2quoteaux 数据为空?
init 中正确调用了 subscribe_quote。如何利用撤单数据?
l2quoteaux 中还包含 withdrawBidQuantity (买入撤单总量) 和 withdrawOffQuantity (卖出撤单总量)。Q: get_full_tick 返回的是 5 档还是 10 档数据?
A: 这取决于您的券商服务器配置和账号权限。通常普通账号是 5 档,Level 2 账号可能是 10 档。您可以通过 len(tick_data['bidVol']) 来打印查看实际长度。
Q: 这个策略可以直接用于回测吗?
A: l2quoteaux (Level 2 快照) 的历史数据量非常大,并非所有券商的 QMT 服务器都提供完整的 Level 2 历史数据回测支持。通常 Tick 级回测支持较好,但 Level 2 统计字段可能需要您先下载补充数据或仅在实盘中使用。
Q: 如何对盘口进行加权计算?
A: 您可以定义一个权重数组,例如 weights = [1.0, 0.8, 0.6, 0.4, 0.2],然后使用 np.average(bid_vols, weights=weights) 来计算加权买量,这样能更准确地反映即时压力。