问题描述
解决方案
在聚宽(JoinQuant)平台中,获取实时买卖五档挂单数据主要通过 Tick 级频率的回测或模拟交易来实现。
核心步骤说明
- 获取方式:
- 在 Tick 策略中,使用
handle_tick(context, tick)函数,tick对象包含了当前的五档盘口数据。 - 在 分钟/日频策略中,可以使用
get_current_tick(security)获取当前的快照数据。
- 在 Tick 策略中,使用
- 数据字段:
- 买盘量:
b1_v~b5_v,买盘价:b1_p~b5_p - 卖盘量:
a1_v~a5_v,卖盘价:a1_p~a5_p
- 买盘量:
- 订单不平衡指标 (OII) 计算:
- OII (Order Imbalance Indicator) 是衡量买卖压力的常用指标。
- 公式:$OII = \frac{\sum \text{BidVolume} - \sum \text{AskVolume}}{\sum \text{BidVolume} + \sum \text{AskVolume}}$
- 取值范围为 [-1, 1],越接近 1 代表买压越强,越接近 -1 代表卖压越强。
策略代码实现
以下是一个完整的 Tick 级策略示例,展示了如何提取五档数据、计算 OII 指标,并根据指标进行简单的交易判断。
# -*- coding: utf-8 -*-
import jqdata
def initialize(context):
# 设定基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设置要操作的标的(以平安银行为例)
g.security = '000001.XSHE'
# 设定OII阈值,用于触发交易
g.buy_threshold = 0.6 # 买压显著
g.sell_threshold = -0.6 # 卖压显著
# 必须在初始化或开盘前订阅 Tick 数据
# 注意:Tick 回测需要在回测界面选择“Tick”频率
run_daily(before_market_open, time='09:00')
def before_market_open(context):
# 订阅标的的 tick 事件
subscribe(g.security, 'tick')
# Tick 数据更新时调用(仅在 Tick 回测/模拟中生效)
def handle_tick(context, tick):
security = tick.code
# 1. 获取五档买卖量
# 买一到买五的量
bid_volumes = [tick.b1_v, tick.b2_v, tick.b3_v, tick.b4_v, tick.b5_v]
# 卖一到卖五的量
ask_volumes = [tick.a1_v, tick.a2_v, tick.a3_v, tick.a4_v, tick.a5_v]
# 2. 计算总买量和总卖量
total_bid_vol = sum(bid_volumes)
total_ask_vol = sum(ask_volumes)
# 3. 计算订单不平衡指标 (OII)
# 防止分母为0
if total_bid_vol + total_ask_vol > 0:
oii = (total_bid_vol - total_ask_vol) / (total_bid_vol + total_ask_vol)
else:
oii = 0
# 打印日志方便观察
# log.info("时间: %s, OII: %.4f, 总买量: %d, 总卖量: %d" % (tick.datetime, oii, total_bid_vol, total_ask_vol))
# 4. 简单的交易逻辑示例
position = context.portfolio.positions[security]
# 如果 OII > 0.6,说明买盘强劲,尝试买入
if oii > g.buy_threshold and position.total_amount == 0:
log.info("买压显著 (OII=%.2f),执行买入" % oii)
order_value(security, context.portfolio.available_cash)
# 如果 OII < -0.6,说明卖盘强劲,尝试卖出
elif oii < g.sell_threshold and position.closeable_amount > 0:
log.info("卖压显著 (OII=%.2f),执行卖出" % oii)
order_target(security, 0)
def after_trading_end(context):
# 收盘后取消订阅
unsubscribe_all()
代码解析
subscribe(g.security, 'tick'):
这是 Tick 策略的关键。必须显式订阅标的,handle_tick函数才会被触发。tick对象属性:tick.b1_v至tick.b5_v: 代表买一到买五的手数(注意单位是股还是手,聚宽股票 Tick 数据通常单位为股)。tick.a1_v至tick.a5_v: 代表卖一到卖五的手数。tick.current: 当前最新价。
- OII 计算逻辑:
代码中将五档的买量求和与卖量求和,然后计算差值比例。这是一个最基础的微观结构指标,常用于短线高频策略。 - 注意事项:
- 此代码需要在回测配置中选择 “Tick” 频率。
- 如果是在分钟策略中使用,不能使用
handle_tick,而应该在handle_data中调用get_current_tick(security)来获取快照对象,属性访问方式相同。
Q&A
Q: 为什么我在 handle_data 中无法获取 tick 参数?
A: handle_data 是按分钟或按天运行的,不接收 tick 参数。如果在分钟策略中需要 Tick 数据,请使用 jqdata.get_current_tick(security) 函数获取当前的 Tick 快照对象。
Q: OII 指标除了计算五档总量,还有其他计算方式吗?
A: 有的。进阶的 OII 计算可以引入距离权重。例如,给买一/卖一更高的权重,给买五/卖五较低的权重(如 $W_i = 1/i$),因为一档的价格最容易成交,对短期价格影响最大。
Q: 聚宽的 Tick 数据包含期货吗?
A: 包含。聚宽支持股票、期货、场内基金和指数的 Tick 数据。对于期货,Tick 对象通常只提供买一和卖一(b1_v, a1_v),而不像股票那样提供完整的五档数据(取决于交易所披露的深度)。