问题描述
解决方案
在 QMT 中,要在图表上绘制买卖信号的图标,主要使用 ContextInfo.draw_icon() 函数。为了使信号更加直观,通常还会配合 ContextInfo.draw_text() 函数来标记文字(如“买”、“卖”)。
核心函数说明
-
ContextInfo.draw_icon(cond, height, type)- cond: 布尔值 (True/False)。当条件为 True 时绘制图标。
- height: 图标绘制在图表上的 Y 轴位置(通常是价格,如最高价、最低价或收盘价)。
- type: 图标的类型索引。根据文档,
0代表矩形,1代表椭圆。
-
ContextInfo.draw_text(condition, position, text)- condition: 布尔值。当条件为 True 时绘制文字。
- position: 文字绘制的 Y 轴位置。
- text: 要显示的字符串内容(如 "Buy", "Sell")。
完整代码示例
以下是一个完整的策略代码示例。该策略基于 双均线交叉(金叉买入,死叉卖出) 的逻辑,在产生信号的 K 线位置画出图标和文字。
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
# 设置均线周期
ContextInfo.short_len = 5
ContextInfo.long_len = 10
# 设置图表上显示的指标线(可选,方便肉眼观察交叉)
# 注意:paint函数在handlebar中调用,这里仅做逻辑说明
def handlebar(ContextInfo):
# 获取当前主图的股票代码
stock_code = ContextInfo.stockcode
# 获取足够的历史数据来计算均线
# 我们需要获取收盘价、最高价(High)和最低价(Low)
# High和Low用于决定图标画在K线的上方还是下方,避免遮挡K线
count = ContextInfo.long_len + 5
data_map = ContextInfo.get_market_data_ex(
['close', 'high', 'low'],
[stock_code],
period=ContextInfo.period,
count=count,
subscribe=True
)
if stock_code not in data_map:
return
df = data_map[stock_code]
# 数据长度不足时不计算
if len(df) < ContextInfo.long_len + 1:
return
# 提取价格序列
close_prices = df['close']
high_prices = df['high']
low_prices = df['low']
# 计算短期和长期均线
ma_short = close_prices.rolling(window=ContextInfo.short_len).mean()
ma_long = close_prices.rolling(window=ContextInfo.long_len).mean()
# 获取当前K线和上一根K线的均线值(用于判断交叉)
# iloc[-1] 代表当前最新的一根K线
curr_short = ma_short.iloc[-1]
curr_long = ma_long.iloc[-1]
prev_short = ma_short.iloc[-2]
prev_long = ma_long.iloc[-2]
# 获取当前K线的最高价和最低价,用于定位图标
curr_high = high_prices.iloc[-1]
curr_low = low_prices.iloc[-1]
# --- 定义信号逻辑 ---
# 金叉(买入信号):短期均线上穿长期均线
buy_condition = (prev_short < prev_long) and (curr_short > curr_long)
# 死叉(卖出信号):短期均线下穿长期均线
sell_condition = (prev_short > prev_long) and (curr_short < curr_long)
# --- 绘图部分 ---
# 1. 绘制买入信号
# 位置:画在最低价下方一点,避免重叠
buy_pos = curr_low * 0.99
# draw_icon: 参数分别为 条件, 高度, 图标类型(1为椭圆)
ContextInfo.draw_icon(buy_condition, buy_pos, 1)
# draw_text: 配合文字更清晰
if buy_condition:
ContextInfo.draw_text(True, buy_pos, '买入')
# 2. 绘制卖出信号
# 位置:画在最高价上方一点
sell_pos = curr_high * 1.01
# draw_icon: 参数分别为 条件, 高度, 图标类型(0为矩形)
ContextInfo.draw_icon(sell_condition, sell_pos, 0)
if sell_condition:
ContextInfo.draw_text(True, sell_pos, '卖出')
# 3. (可选) 在图表上画出均线,方便核对
ContextInfo.paint('MA_Short', curr_short, -1, 0, 'yellow')
ContextInfo.paint('MA_Long', curr_long, -1, 0, 'blue')
代码详解
- 数据获取:使用
get_market_data_ex获取close,high,low数据。high和low用于计算图标绘制的最佳位置(买入画在 K 线下方,卖出画在 K 线 上方),这样视觉效果更好。 - 信号判断:通过比较当前 K 线和上一根 K 线的均线位置关系,判断是否发生“金叉”或“死叉”。
draw_icon:- 当
buy_condition为 True 时,在buy_pos位置画一个椭圆(类型 1)。 - 当
sell_condition为 True 时,在sell_pos位置画一个矩形(类型 0)。
- 当
draw_text:仅画图标可能不够直观,因此在相同位置添加了“买入”或“卖出”的文字标记。
如何运行
- 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码复制粘贴进去。
- 点击【运行】或将策略加载到图表上,你将在均线交叉的位置看到对应的图标和文字。
Q&A
Q: draw_icon 的 type 参数除了 0 和 1 还有其他选择吗?
A: 根据官方文档,目前明确列出的只有 0(矩形)和 1(椭圆)。如果需要更丰富的视觉效果(如箭头),建议主要依赖 draw_text 使用文字符号(如 "↑", "↓")或者直接写明 "Buy"/"Sell"。
Q: 为什么图标有时候会遮挡 K 线?
A: 如果将 height 参数直接设置为 close(收盘价),图标就会画在 K 线中间。为了避免遮挡,建议买入信号画在 low * 0.99(最低价下方),卖出信号画在 high * 1.01(最高价上方)。
Q: 这个绘图函数在回测中能看到吗?
A: 可以。在回测模式下,QMT 会在回测结束后生成的图表上展示这些图标。在实盘/模拟盘的主图叠加模式下,也会实时刷新显示。