问题描述
解决方案
这是一个关于在 QMT 平台进行可视化绘图和技术指标计算的需求。
实现思路
在 QMT 的 Python API 中,我们无法直接修改主图原生 K 线(蜡烛图)的颜色属性(例如将某一根原本是红色的阳线强制改成黄色实体)。但是,我们可以通过以下方式达到视觉上的效果:
- 上涨/下跌颜色:QMT 主图默认就是“红涨绿跌”(国内习惯),这部分无需额外代码,平台自带。
- MACD 金叉变黄:由于无法直接变色 K 线实体,我们可以采用以下两种替代方案之一来“高亮”显示金叉当天的 K 线:
- 方案 A(推荐):在金叉当天的 K 线位置绘制一个黄色图标(如箭头或圆点)或者写上文字。
- 方案 B:在金叉当天,沿着该 K 线的最高价和最低价画一条黄色的垂直线,覆盖在原 K 线上。
下面的代码将实现:
- 自动计算 MACD 指标(DIF, DEA)。
- 判断金叉条件(DIF 上穿 DEA)。
- 视觉实现:
- 在金叉位置绘制黄色垂直线(覆盖原 K 线高低点)。
- 在金叉位置下方绘制黄色图标(增强提示)。
- 在副图绘制 MACD 指标线供参考。
策略代码
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
# 设置默认测试标的(如果未在界面选择)
ContextInfo.set_universe(['600000.SH'])
# 定义MACD参数
ContextInfo.short_len = 12
ContextInfo.long_len = 26
ContextInfo.mid_len = 9
def get_macd(close_series, short_len, long_len, mid_len):
"""
计算MACD指标的辅助函数
"""
# 计算短周期EMA
ema_short = close_series.ewm(span=short_len, adjust=False).mean()
# 计算长周期EMA
ema_long = close_series.ewm(span=long_len, adjust=False).mean()
# 计算DIF
dif = ema_short - ema_long
# 计算DEA
dea = dif.ewm(span=mid_len, adjust=False).mean()
# 计算MACD柱
macd = (dif - dea) * 2
return dif, dea, macd
def handlebar(ContextInfo):
# 获取当前主图的品种代码
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# 获取足够的历史数据用于计算MACD (取最近100根即可,保证计算稳定)
# 注意:get_market_data_ex 返回的数据格式需要处理
data_df = ContextInfo.get_market_data_ex(
['high', 'low', 'close'],
[stock_code],
period=ContextInfo.period,
count=100,
dividend_type=ContextInfo.dividend_type
)
# 数据校验,防止数据不足报错
if stock_code not in data_df or data_df[stock_code].empty:
return
df = data_df[stock_code]
# 计算 MACD
dif, dea, macd = get_macd(df['close'], ContextInfo.short_len, ContextInfo.long_len, ContextInfo.mid_len)
# 获取当前K线和上一根K线的索引位置
# 在handlebar中,iloc[-1]是当前正在运行的K线,iloc[-2]是前一根
if len(dif) < 2:
return
current_dif = dif.iloc[-1]
current_dea = dea.iloc[-1]
last_dif = dif.iloc[-2]
last_dea = dea.iloc[-2]
# --- 逻辑判断 ---
# 1. 判断金叉:DIF 上穿 DEA (当前DIF>DEA 且 上一根DIF<=DEA)
golden_cross = (current_dif > current_dea) and (last_dif <= last_dea)
# 2. 获取当前K线的高低价,用于画线
current_high = df['high'].iloc[-1]
current_low = df['low'].iloc[-1]
# --- 绘图部分 ---
# 1. 在副图画出 MACD 指标 (方便对比)
# limit='noaxis' 表示在主图画,不填或填其他值通常在副图
# 这里我们不加 'noaxis',让它显示在副图区域
ContextInfo.paint('DIF', current_dif, -1, 0, 'white')
ContextInfo.paint('DEA', current_dea, -1, 0, 'yellow')
# 画MACD柱状图,style=42为柱状线
color_macd = 'red' if macd.iloc[-1] > 0 else 'green'
ContextInfo.paint('MACD', macd.iloc[-1], -1, 42, color_macd)
# 2. 实现 "金叉时画成黄色" 的视觉效果
# 由于无法直接改变K线实体颜色,我们在主图(noaxis)绘制黄色标记
if golden_cross:
# 方法A: 在主图 K 线位置画一条黄色的垂直线,覆盖高低点,模拟黄色K线芯
# draw_vertline(条件, 价格1, 价格2, 颜色)
ContextInfo.draw_vertline(True, current_high, current_low, 'yellow')
# 方法B: 在最低价下方画一个黄色图标 (图标类型1通常为圆点或箭头,视版本而定)
# draw_icon(条件, 位置, 图标类型)
ContextInfo.draw_icon(True, current_low * 0.99, 1)
# 方法C: 在主图写字提示
ContextInfo.draw_text(True, current_high * 1.01, '金叉')
# 3. 上涨画红、下跌画绿
# 说明:QMT主图默认就是红涨绿跌,无需额外代码。
# 如果需要强制画线强调,可以使用 draw_vertline 配合 close > open 判断,
# 但通常不需要这样做,因为会覆盖原生K线导致显示混乱。
代码说明
-
数据获取 (
get_market_data_ex):- 我们获取了
high,low,close数据。 count=100确保有足够的数据来计算 EMA 和 MACD,使其数值准确。
- 我们获取了
-
MACD 计算 (
get_macd):- 使用了
pandas的ewm函数计算指数移动平均线,这是计算 MACD 的标准方法。
- 使用了
-
金叉判断:
- 逻辑是:
当前DIF > 当前DEA且前一根DIF <= 前一根DEA。
- 逻辑是:
-
绘图 (
paint,draw_vertline,draw_icon):- 副图:代码默认使用
paint输出 DIF、DEA 和 MACD 柱子,方便您核对金叉位置。 - 主图金叉高亮:
ContextInfo.draw_vertline(..., 'yellow'):在金叉当天的最高价和最低价之间画一条黄色直线。这在视觉上会把该 K 线的中间部分染黄。ContextInfo.draw_icon:在 K 线下方打一个标记,确保您不会错过信号。
- 副图:代码默认使用
如何使用
- 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码完整复制进去。
- 点击【运行】或将策略加载到行情图上。
- 您会看到主图上发生金叉的位置出现了黄色标记和线条,副图显示了 MACD 指标。
Q&A
Q: 为什么不能直接把 K 线实体变成黄色?
A: QMT 的 Python API 主要用于量化计算和画辅助线(指标)。它没有提供类似 plot_candle(color=...) 这样直接重绘原生 K 线实体的函数。使用 draw_vertline(画垂直线)是实现“变色”效果最接近的替代方案。
Q: 代码中的 limit='noaxis' 是什么意思?
A: 在 paint 函数中,如果加上 limit='noaxis',指标线会画在主图(和 K 线在一起)。如果不加,指标线会画在副图(K 线图下方的区域)。本策略中,MACD 数据画在副图,而金叉的黄色标记画在主图。
Q: 如何调整 MACD 的参数?
A: 修改 init 函数中的 ContextInfo.short_len (默认12), ContextInfo.long_len (默认26), ContextInfo.mid_len (默认9) 即可。