🚀 AI 一键生成 qmt 策略代码

综合涨跌停家数与成交量构建市场情绪指标

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

问题描述

如何编写代码监控全市场的涨跌停家数和情绪?

解决方案

这是一个非常实用的市场监控需求。在 QMT 中,我们可以通过结合 get_full_tick(获取全市场实时快照)和 get_instrumentdetail(获取涨跌停价格)来实现这一功能。

策略设计思路

  1. 获取标的池:在 init 中获取“沪深A股”板块的所有股票代码。
  2. 获取实时行情:使用 get_full_tick 批量获取所有股票的最新价(lastPrice)。
  3. 获取涨跌停价:使用 get_instrumentdetail 获取每只股票当天的涨停价(UpStopPrice)和跌停价(DownStopPrice)。
    • 优化点:涨跌停价全天不变,为了避免每几秒钟循环调用几千次 get_instrumentdetail 导致卡顿,我们应该将这些数据缓存起来,只在初始化或第一次运行时获取。
  4. 统计逻辑
    • 如果 最新价 >= 涨停价,涨停家数 +1。
    • 如果 最新价 <= 跌停价,跌停家数 +1。
    • 情绪指标:这里我们可以定义一个简单的情绪指标,例如 (涨停家数 - 跌停家数) 或者 涨停占比
  5. 输出与绘图:使用 print 在日志输出数值,并使用 ContextInfo.paint 在副图上画出曲线,方便观察日内趋势。

QMT 策略代码

# -*- coding: gbk -*-
import time

def init(ContextInfo):
    # 1. 设置股票池为全市场A股
    # 注意:全市场股票数量较多,建议在性能较好的机器上运行
    ContextInfo.stock_list = ContextInfo.get_stock_list_in_sector('沪深A股')
    ContextInfo.set_universe(ContextInfo.stock_list)
    
    # 2. 初始化全局变量
    ContextInfo.limit_price_cache = {}  # 用于缓存涨跌停价格,避免重复查询
    ContextInfo.last_update_time = 0    # 上次更新时间
    ContextInfo.update_interval = 3     # 设置更新间隔(秒),避免过于频繁刷新导致卡顿
    
    # 设置副图显示的指标名称(可选)
    ContextInfo.paint_names = ["涨停家数", "跌停家数", "市场情绪(净涨停)"]

def handlebar(ContextInfo):
    # 仅在实时行情的最后一根K线(或Tick)运行,跳过历史回测阶段的逐根K线计算以节省时间
    if not ContextInfo.is_last_bar():
        return

    # 控制运行频率,每隔 update_interval 秒运行一次
    current_time = time.time()
    if current_time - ContextInfo.last_update_time < ContextInfo.update_interval:
        return
    ContextInfo.last_update_time = current_time

    # 1. 批量获取全市场实时Tick数据
    # get_full_tick 返回字典: {code: {lastPrice: ..., ...}}
    ticks = ContextInfo.get_full_tick(ContextInfo.stock_list)
    
    up_limit_count = 0   # 涨停计数
    down_limit_count = 0 # 跌停计数
    valid_stock_count = 0 # 有效统计的股票数

    # 2. 遍历所有股票进行统计
    for code in ContextInfo.stock_list:
        tick_data = ticks.get(code)
        
        # 如果没有Tick数据或最新价为0(停牌或未开盘),跳过
        if not tick_data or tick_data.get('lastPrice', 0) <= 0:
            continue
            
        last_price = tick_data['lastPrice']
        
        # 3. 获取涨跌停价格(带缓存机制)
        if code not in ContextInfo.limit_price_cache:
            detail = ContextInfo.get_instrumentdetail(code)
            # 如果获取不到详情或涨跌停价格异常,跳过
            if not detail or detail['UpStopPrice'] <= 0:
                continue
            
            # 缓存该股票的涨跌停价格
            ContextInfo.limit_price_cache[code] = {
                'up': detail['UpStopPrice'],
                'down': detail['DownStopPrice']
            }
        
        limits = ContextInfo.limit_price_cache[code]
        
        # 4. 判断涨跌停
        # 考虑到浮点数精度,虽然金融API通常处理过,但严格来说可以用极小误差范围,这里直接比较通常也没问题
        if last_price >= limits['up']:
            up_limit_count += 1
        elif last_price <= limits['down']:
            down_limit_count += 1
            
        valid_stock_count += 1

    # 5. 计算市场情绪
    # 简单定义:净涨停数 = 涨停 - 跌停
    market_sentiment = up_limit_count - down_limit_count
    
    # 6. 打印日志信息
    # 获取当前时间字符串
    timetag = ContextInfo.get_tick_timetag()
    time_str = timetag_to_datetime(timetag, '%H:%M:%S')
    
    log_msg = f"【市场监控】{time_str} | 涨停: {up_limit_count} 家 | 跌停: {down_limit_count} 家 | 情绪(净涨停): {market_sentiment}"
    print(log_msg)
    
    # 7. 在界面画图 (需要在副图运行策略才能看到)
    # 红色线画涨停
    ContextInfo.paint("涨停家数", up_limit_count, -1, 0, "red", "noaxis")
    # 绿色线画跌停
    ContextInfo.paint("跌停家数", down_limit_count, -1, 0, "green", "noaxis")
    # 黄色线画情绪
    ContextInfo.paint("情绪指标", market_sentiment, -1, 0, "yellow", "noaxis")

代码关键点解析

  1. 缓存机制 (ContextInfo.limit_price_cache)

    • get_instrumentdetail 是一个相对耗时的操作,且一只股票当天的涨跌停价是固定的。
    • 代码中设计了缓存:只有当缓存中没有该股票数据时,才去调用 API。这极大地提高了 handlebar 的循环速度,防止界面卡顿。
  2. 批量获取数据 (get_full_tick)

    • 不要在循环中一只一只地去取行情(如 get_market_data),那样效率极低。
    • 使用 get_full_tick(list) 一次性拿回几千只股票的数据是最高效的方法。
  3. 频率控制 (update_interval)

    • 全市场遍历计算量较大,不需要每个 Tick(毫秒级)都算一次。代码设置了每 3 秒计算一次,既保证了实时性,又降低了 CPU 占用。
  4. 绘图 (paint)

    • ContextInfo.paint 可以将计算结果实时绘制在 K 线图的副图上。
    • 使用方法:在 QMT 界面中,打开一个行情图(如上证指数),右键选择“叠加指标”或“副图指标”,选择这个策略,即可看到涨跌停家数的历史走势曲线。

如何运行

  1. 打开 QMT 的【模型研究/策略编辑器】。
  2. 新建一个 Python 策略,将上述代码粘贴进去。
  3. 点击【编译】确保无误。
  4. 方式一(看日志):直接点击【运行】,在下方的日志窗口观察文字输出。
  5. 方式二(看图表)
    • 在行情界面(例如输入 000001.SH 上证指数)。
    • 将周期切换为【1分钟】或【分笔】。
    • 在副图区域右键 -> 选择指标 -> 找到你刚才保存的策略名称。
    • 你将看到红、绿、黄三条线动态展示全市场的涨跌停变化。

Q&A

Q: 为什么有时候涨停家数比行情软件上看到的少?
A:

  1. ST股规则:代码直接使用了交易所给出的 UpStopPrice。有些行情软件可能包含“触及涨停但未封死”的股票,或者对涨停的定义(如ST股的5%)处理略有不同。本代码逻辑是严格的 最新价 >= 涨停价
  2. 北交所/科创板沪深A股 板块通常包含主板、创业板和科创板。如果需要包含或排除特定板块(如北交所),可以在 init 中调整 get_stock_list_in_sector 的参数。

Q: 如何定义更复杂的情绪指标?
A: 你可以在代码第 5 步修改 market_sentiment 的计算公式。例如:

  • 涨停占比: up_limit_count / (up_limit_count + down_limit_count)
  • 全市场上涨率: 在循环中统计 last_price > pre_close 的家数,计算 上涨家数 / 总家数