🚀 AI 一键生成 qmt 策略代码

利用 get_full_tick 分析盘口买卖价差 (Bid-Ask Spread)

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

问题描述

如何获取实时行情的盘口买卖价差 (Bid-Ask Spread) 数据?

解决方案

在 QMT (Quantitative Trading Platform) 中,获取实时盘口买卖价差 (Bid-Ask Spread) 的最直接方法是使用 ContextInfo.get_full_tick() 接口。

该接口可以获取指定标的的最新分笔数据(Tick Data),其中包含了买一价(Bid1)和卖一价(Ask1)。

核心逻辑

  1. 获取 Tick 数据:调用 ContextInfo.get_full_tick(code_list) 获取最新的盘口快照。
  2. 提取价格:从返回的数据字典中提取 askPrice(卖价列表)和 bidPrice(买价列表)。列表的第 0 位即为卖一价和买一价。
  3. 计算价差
    • 绝对价差 (Spread) = 卖一价 - 买一价
    • 相对价差 (Spread Ratio) = (卖一价 - 买一价) / 中间价 * 100% (可选,用于衡量流动性成本比例)

QMT 策略代码示例

以下是一个完整的 Python 策略示例,展示如何在 handlebar 周期内实时计算并打印当前主图品种的买卖价差。

# -*- coding: gbk -*-

def init(ContextInfo):
    # 设置示例股票池,这里以贵州茅台为例
    # 实际运行时会根据界面选择的品种或此处设置的 universe 运行
    ContextInfo.set_universe(['600519.SH'])
    
    # 设置账号(如果需要交易)
    # ContextInfo.set_account('您的资金账号')

def handlebar(ContextInfo):
    # 获取当前主图的股票代码
    current_stock = ContextInfo.stockcode + '.' + ContextInfo.market
    
    # 1. 获取最新分笔数据 (Tick Data)
    # get_full_tick 返回一个字典,key是股票代码,value是数据字典
    tick_data_map = ContextInfo.get_full_tick([current_stock])
    
    # 检查是否成功获取数据
    if current_stock in tick_data_map:
        tick_data = tick_data_map[current_stock]
        
        # 2. 提取盘口价格
        # askPrice 和 bidPrice 是列表,包含五档或十档行情
        # 索引 0 对应 卖一 和 买一
        ask_prices = tick_data.get('askPrice', [])
        bid_prices = tick_data.get('bidPrice', [])
        
        # 确保数据有效(防止列表为空,例如跌停或涨停时可能一边为空)
        if len(ask_prices) > 0 and len(bid_prices) > 0:
            ask_1 = ask_prices[0] # 卖一价
            bid_1 = bid_prices[0] # 买一价
            
            # 过滤无效价格(如0)
            if ask_1 > 0 and bid_1 > 0:
                # 3. 计算买卖价差
                spread = ask_1 - bid_1
                
                # 计算相对价差 (Spread %)
                mid_price = (ask_1 + bid_1) / 2
                spread_ratio = (spread / mid_price) * 100
                
                # 打印结果
                print(f"代码: {current_stock}")
                print(f"时间: {tick_data.get('timetag')}") # 注意:这里通常不需要转换,仅作展示
                print(f"卖一价: {ask_1}, 买一价: {bid_1}")
                print(f"绝对价差 (Spread): {spread:.2f}")
                print(f"相对价差 (Spread %): {spread_ratio:.4f}%")
                print("-" * 30)
            else:
                print(f"{current_stock} 价格数据异常 (可能为0)")
        else:
            # 处理涨跌停板情况(可能只有买单或只有卖单)
            if len(ask_prices) == 0 and len(bid_prices) > 0:
                print(f"{current_stock} 当前可能涨停 (无卖单)")
            elif len(bid_prices) == 0 and len(ask_prices) > 0:
                print(f"{current_stock} 当前可能跌停 (无买单)")
    else:
        print(f"未获取到 {current_stock} 的 Tick 数据")

代码解析

  1. ContextInfo.get_full_tick([code]):

    • 这是获取实时盘口最关键的函数。它不需要像 get_market_data 那样指定复杂的参数,专门用于获取最新的 Level-1 或 Level-2 快照。
    • 返回的数据结构中,askPricebidPrice 是列表。对于普通 Level-1 行情,列表长度通常为 5;对于 Level-2 行情,长度可能为 10。
  2. 异常处理:

    • 在计算价差前,必须判断 ask_pricesbid_prices 是否为空。
    • 涨停板:此时可能没有卖单(askPrice 为空或价格为 0),无法计算常规价差。
    • 跌停板:此时可能没有买单(bidPrice 为空或价格为 0)。
  3. 运行模式:

    • 此代码需要在实盘模式(“运行”按钮)下才能看到实时的 Tick 变化。
    • 如果在回测模式下,get_full_tick 可能会返回回测时间点对应的快照(取决于数据精度),但通常用于实盘高频监控。

常见问题 (Q&A)

Q: get_full_tickget_market_data 有什么区别?
A: get_full_tick 专门用于获取当前时刻的最新盘口快照(Tick),返回的是字典结构,包含买卖五档/十档,速度快且使用方便。get_market_data 更通用,可以获取历史序列数据(如过去 100 个 tick 或 K 线),返回的是 Pandas DataFrame 或 Series,处理起来相对重一些。计算实时盘口价差推荐使用 get_full_tick

Q: 为什么计算出的 Spread 有时是负数?
A: 在正常的连续竞价交易中,卖一价永远大于买一价,Spread 应为正数。如果出现负数,可能是数据源异常、使用了错误的市场代码(如套利合约),或者在极端的市场交叉盘瞬间(极少见)。最常见的情况是代码逻辑错误,例如将 bid - ask 算反了。

Q: 如何在盘口价差超过特定阈值时触发交易?
A: 您可以在 handlebar 中加入逻辑判断。例如:

if spread_ratio < 0.05: # 如果价差小于 0.05%,认为流动性好,适合交易
    passorder(...) # 执行下单函数

Q: 这个接口支持期货和期权吗?
A: 支持。get_full_tick 适用于股票、期货、期权等所有 QMT 支持的品种。对于期货,Spread 通常是一个最小变动价位(Tick Size);对于期权,Spread 是衡量流动性的重要指标。