问题描述
解决方案
这是一个需要在 QMT 策略图表上进行技术指标计算(布林带)和图形绘制(画线、画文本/图标)的需求。
实现思路
- 数据获取:使用
ContextInfo.get_market_data_ex获取当前主图品种的历史收盘价。 - 指标计算:利用
pandas库计算移动平均线(中轨)和标准差,进而计算出上轨和下轨。 - 绘制通道:使用
ContextInfo.paint()函数在主图上绘制上、中、下三条轨道线。 - 信号标记:判断当前收盘价是否大于上轨,如果满足条件,使用
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}")
代码要点解析
ContextInfo.paint: 这是 QMT 专门用于在图表上画线的函数。- 参数
-1表示在主图(和 K 线在一起)绘制,如果填0或1则会在副图显示。 - 参数
0代表画实线(曲线)。
- 参数
ContextInfo.draw_text: 用于绘制箭头。- 虽然 QMT 有
draw_icon函数,但其内置图标类型较少(主要是矩形和椭圆),为了精确显示“向上的箭头”,直接绘制文本符号"↑"是最稳妥的方法。 - 位置选择:代码中将箭头绘制在
lower_val * 0.99(下轨下方 1% 的位置),这样箭头会出现在 K 线柱的下方指向上方,视觉上比较清晰。
- 虽然 QMT 有
- 数据获取:使用了
get_market_data_ex,这是 QMT 推荐的高效数据接口,能够直接返回 DataFrame 格式,方便进行rolling(滚动)计算。
如何运行
- 打开 QMT 的【模型研究/策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码复制进去。
- 点击【运行】或在行情图上加载该模型,即可看到布林带轨道和突破时的箭头标记。
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 = 20 为 26 即可。init 函数专门用于初始化这类全局参数。