问题描述
解决方案
在 QMT 平台中,要在回测图表上绘制自定义技术指标(如快线和慢线),主要使用 ContextInfo.paint() 函数。
该函数可以在每一根 K 线(Bar)上绘制数值,从而连接成曲线。
核心步骤
- 获取数据:在
handlebar函数中,使用ContextInfo.get_market_data_ex()获取当前 K 线及之前的历史收盘价。 - 计算指标:根据获取的数据计算快线(例如 5 日均线)和慢线(例如 10 日均线)的数值。
- 绘制曲线:调用
ContextInfo.paint()将计算出的数值输出到图表上。
代码实现
以下是一个完整的策略示例代码。该策略会在主图上绘制一条 5周期快线(红色) 和一条 10周期慢线(绿色)。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
"""
初始化函数
"""
# 定义快线和慢线的周期
ContextInfo.fast_period = 5
ContextInfo.slow_period = 10
print("策略初始化完成,准备绘制双均线指标")
def handlebar(ContextInfo):
"""
K线逐根运行函数
"""
# 获取当前主图的品种代码
stock_code = ContextInfo.stockcode
# 获取当前 K 线的时间戳(毫秒)
current_timetag = ContextInfo.get_bar_timetag(ContextInfo.barpos)
# 将时间戳转换为字符串格式,用于获取数据
# 注意:get_market_data_ex 的 end_time 需要字符串格式
end_time_str = timetag_to_datetime(current_timetag, '%Y%m%d%H%M%S')
# 获取历史数据
# 我们需要获取足够的数据来计算慢线,这里多取一点作为缓冲
count = ContextInfo.slow_period + 5
# 使用 get_market_data_ex 获取数据
# 注意:period='follow' 跟随主图周期,dividend_type='follow' 跟随主图复权
data_map = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period='follow',
end_time=end_time_str,
count=count,
dividend_type='follow',
fill_data=False,
subscribe=True
)
# 检查数据是否获取成功
if stock_code in data_map:
df = data_map[stock_code]
# 确保数据长度足够计算慢线
if len(df) >= ContextInfo.slow_period:
# 计算快线 (例如 MA5)
# 取最后 fast_period 行的收盘价求平均
fast_value = df['close'].iloc[-ContextInfo.fast_period:].mean()
# 计算慢线 (例如 MA10)
# 取最后 slow_period 行的收盘价求平均
slow_value = df['close'].iloc[-ContextInfo.slow_period:].mean()
# --- 绘图部分 ---
# 绘制快线
# 参数说明:
# 1. 指标名称 (显示在图例中)
# 2. 数值
# 3. 索引位置 (-1 表示当前 Bar)
# 4. 线型 (0 表示曲线)
# 5. 颜色 ('red')
ContextInfo.paint("快线_MA5", fast_value, -1, 0, 'red')
# 绘制慢线
ContextInfo.paint("慢线_MA10", slow_value, -1, 0, 'green')
# 可以在这里添加简单的交易逻辑演示(可选)
# if fast_value > slow_value:
# ContextInfo.paint("多头排列", 1, -1, 0, 'nodraw') # 仅在左上角显示数值不画线
函数详解:ContextInfo.paint
ContextInfo.paint(name, value, index, line_style, color, limit)
- name (string): 指标名称,会显示在图表的左上角数据区。
- value (number): 当前 K 线对应的指标数值。
- index (number): 绘制的位置索引。通常填 -1,表示在当前运行到的 K 线位置(
ContextInfo.barpos)进行绘制。 - line_style (number): 线型。
0: 曲线(最常用,连接各个点)。42: 柱状线(类似成交量柱)。
- color (string): 颜色。支持
'red','blue','green','yellow','white','cyan','magenta','brown'。 - limit (string, 可选): 控制参数。
'noaxis': 画线但不影响坐标轴缩放(例如在主图画一个很小的值,不让K线被压缩)。'nodraw': 不在图上画线,只在左上角显示数值。
注意事项
- 主图与副图:
- 如果你的指标数值是价格相关的(如均线、布林带),直接运行即可,它会默认叠加在主图 K 线上。
- 如果你的指标是震荡指标(如 MACD、RSI,数值范围 0-100 或围绕 0 轴),在策略编辑器中,请将策略的**“显示位置”设置为“副图”**,否则会压缩主图 K 线的显示比例。
- 运行模式:该绘图函数在“回测模式”和“实盘/模拟运行模式”下均有效。
- 性能:
paint函数在每一根 K 线都会被调用。在编写复杂逻辑时,请确保计算过程高效,避免拖慢回测速度。
Q&A
Q: 如何让两条线显示在副图(Sub-chart)而不是主图上?
A: 代码本身不需要修改。在 QMT 的【策略编辑器】界面右侧的【基本信息】栏中,找到【位置】选项,将其从“主图”或“主图叠加”修改为**“副图”**。保存并运行后,指标就会显示在 K 线图下方的独立区域。
Q: 我可以画柱状图吗?比如 MACD 的红绿柱?
A: 可以。将 ContextInfo.paint 的第 4 个参数 line_style 设置为 42 即可绘制柱状线。
Q: 为什么我的线画出来是断断续续的?
A: 确保 handlebar 在每一根 K 线都计算并调用了 paint。如果只在特定条件下(如 if condition: 内部)调用 paint,那么不满足条件时就不会有点,导致线条中断。必须保证每根 Bar 都有返回值。