🚀 AI 一键生成 qmt 策略代码

QMT 绘图函数高级教程:结合 paint、draw_icon 和 draw_text 打造专业图表

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

问题描述

如何在策略图表上画出布林带通道,并且在价格突破上轨时用一个向上的箭头标记出来?

解决方案

这是一个需要在 QMT 策略图表上进行技术指标计算(布林带)和图形绘制(画线、画文本/图标)的需求。

实现思路

  1. 数据获取:使用 ContextInfo.get_market_data_ex 获取当前主图品种的历史收盘价。
  2. 指标计算:利用 pandas 库计算移动平均线(中轨)和标准差,进而计算出上轨和下轨。
  3. 绘制通道:使用 ContextInfo.paint() 函数在主图上绘制上、中、下三条轨道线。
  4. 信号标记:判断当前收盘价是否大于上轨,如果满足条件,使用 ContextInfo.draw_text() 在图表上绘制向上的箭头符号 "↑"(注:QMT 的 draw_icon 默认图标类型较少,使用文本绘制箭头视觉效果更明确)。

策略代码

# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    # 定义布林带的参数
    ContextInfo.boll_period = 20  # 周期 N=20
    ContextInfo.boll_width = 2    # 宽度 K=2
    
    # 设置图表上显示的指标名称(可选)
    print("布林带策略初始化完成")

def handlebar(ContextInfo):
    # 获取当前主图的品种代码
    # ContextInfo.stockcode 仅返回代码,需拼接市场后缀
    stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
    
    # 获取当前 K 线的位置索引
    index = ContextInfo.barpos
    
    # 如果当前 K 线索引小于计算周期,数据不足,直接返回
    if index < ContextInfo.boll_period:
        return

    # 获取历史行情数据
    # count 取 boll_period + 2 即可,保证有足够数据计算 rolling
    # period 使用 ContextInfo.period 获取当前主图周期(如 '1d', '5m')
    data_dict = ContextInfo.get_market_data_ex(
        ['close', 'low'],  # 获取收盘价和最低价
        [stock_code], 
        period=ContextInfo.period, 
        count=ContextInfo.boll_period + 5,
        dividend_type=ContextInfo.dividend_type, # 跟随主图复权方式
        subscribe=True
    )
    
    if stock_code not in data_dict:
        return
        
    df = data_dict[stock_code]
    
    # 再次校验数据长度
    if len(df) < ContextInfo.boll_period:
        return

    # --- 计算布林带 ---
    # 1. 计算中轨:N日移动平均线 (MA)
    df['mid'] = df['close'].rolling(window=ContextInfo.boll_period).mean()
    
    # 2. 计算标准差 (STD)
    df['std'] = df['close'].rolling(window=ContextInfo.boll_period).std()
    
    # 3. 计算上轨和下轨
    df['upper'] = df['mid'] + ContextInfo.boll_width * df['std']
    df['lower'] = df['mid'] - ContextInfo.boll_width * df['std']
    
    # 获取当前 K 线的数值(DataFrame 的最后一行)
    current_bar = df.iloc[-1]
    close_price = current_bar['close']
    upper_val = current_bar['upper']
    mid_val = current_bar['mid']
    lower_val = current_bar['lower']
    low_price = current_bar['low'] # 当根 K 线最低价,用于定位箭头位置
    
    # --- 绘图部分 ---
    
    # 1. 在主图绘制布林带三条线
    # paint(指标名, 数值, 索引位置(-1代表主图), 线型(0代表曲线), 颜色)
    ContextInfo.paint("Upper", upper_val, -1, 0, "yellow")   # 上轨 黄色
    ContextInfo.paint("Mid", mid_val, -1, 0, "white")        # 中轨 白色
    ContextInfo.paint("Lower", lower_val, -1, 0, "magenta")  # 下轨 品红
    
    # 2. 标记突破信号
    # 逻辑:当前收盘价 > 上轨
    is_breakout = close_price > upper_val
    
    if is_breakout:
        # 在图表上绘制文字箭头
        # draw_text(条件, 位置, 文字)
        # 位置设置在下轨下方一点,或者最低价下方,避免遮挡 K 线
        draw_position = lower_val * 0.99 
        ContextInfo.draw_text(True, draw_position, "↑")
        
        # 如果您希望同时在日志输出提示
        # print(f"时间: {ContextInfo.get_bar_timetag(index)} 发生突破,价格: {close_price}")

代码要点解析

  1. ContextInfo.paint: 这是 QMT 专门用于在图表上画线的函数。
    • 参数 -1 表示在主图(和 K 线在一起)绘制,如果填 01 则会在副图显示。
    • 参数 0 代表画实线(曲线)。
  2. ContextInfo.draw_text: 用于绘制箭头。
    • 虽然 QMT 有 draw_icon 函数,但其内置图标类型较少(主要是矩形和椭圆),为了精确显示“向上的箭头”,直接绘制文本符号 "↑" 是最稳妥的方法。
    • 位置选择:代码中将箭头绘制在 lower_val * 0.99(下轨下方 1% 的位置),这样箭头会出现在 K 线柱的下方指向上方,视觉上比较清晰。
  3. 数据获取:使用了 get_market_data_ex,这是 QMT 推荐的高效数据接口,能够直接返回 DataFrame 格式,方便进行 rolling(滚动)计算。

如何运行

  1. 打开 QMT 的【模型研究/策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码复制进去。
  4. 点击【运行】或在行情图上加载该模型,即可看到布林带轨道和突破时的箭头标记。

Q&A

Q: 为什么使用 draw_text 而不是 draw_icon 来画箭头?
A: QMT 的 draw_icon 函数在文档中主要支持简单的几何图形(如 0:矩形, 1:椭圆)。虽然某些版本可能支持更多整型代码对应的图标,但为了保证代码在不同版本间的兼容性和视觉的准确性,使用 draw_text 绘制 Unicode 字符 "↑" 是实现“向上箭头”最直接且不易出错的方法。

Q: ContextInfo.paint 函数中的颜色参数支持哪些?
A: QMT 支持常见的颜色英文单词,包括 'red' (红), 'green' (绿), 'blue' (蓝), 'yellow' (黄), 'white' (白), 'black' (黑), 'cyan' (青), 'magenta' (品红/紫) 等。

Q: 如何修改布林带的参数(例如改成 26 日均线)?
A: 在代码的 init 函数中,修改 ContextInfo.boll_period = 2026 即可。init 函数专门用于初始化这类全局参数。