问题描述
解决方案
在 QMT (Quantitative Trading Platform) 中创建自定义技术指标,本质上是利用 Python 强大的数据处理能力(如 Pandas、Numpy)来编写计算逻辑,并通过 QMT 提供的绘图接口将结果展示在 K 线图上。
以下是创建自定义技术指标的完整步骤和代码示例。
创建自定义指标的核心步骤
- 获取数据:在
handlebar函数中,使用ContextInfo.get_market_data_ex获取历史行情数据(如收盘价、成交量等)。 - 计算逻辑:利用 Python 的数学库(如 Pandas)根据你的想法编写计算公式。
- 绘图输出:使用
ContextInfo.paint()函数将计算出的数值绘制在图表上。
示例:创建一个“动态波动通道”指标
假设你的想法是创建一个简单的自定义指标:以 20 日均线为中轨,上下各加减 2 倍的 20 日标准差作为通道(类似布林带,但我们手动实现以演示过程)。
完整代码实现
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
# 初始化函数,设置一些常量
ContextInfo.period = 20 # 均线周期
ContextInfo.std_dev_mult = 2 # 标准差倍数
def handlebar(ContextInfo):
# 1. 获取当前主图的品种代码
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# 2. 获取历史数据
# 获取足够的历史数据以确保计算均线时有值,这里取过去 50 根 K 线
# 注意:get_market_data_ex 返回的是字典 {code: dataframe}
data_dict = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period=ContextInfo.period,
count=50,
dividend_type=ContextInfo.dividend_type
)
if stock_code not in data_dict:
return
df = data_dict[stock_code]
# 确保数据量足够计算
if len(df) < ContextInfo.period:
return
# 3. 编写自定义计算逻辑 (利用 Pandas)
# 计算 N 日移动平均线 (中轨)
df['MA'] = df['close'].rolling(window=ContextInfo.period).mean()
# 计算 N 日标准差
df['STD'] = df['close'].rolling(window=ContextInfo.period).std()
# 计算上轨和下轨
df['Upper'] = df['MA'] + (df['STD'] * ContextInfo.std_dev_mult)
df['Lower'] = df['MA'] - (df['STD'] * ContextInfo.std_dev_mult)
# 获取当前 K 线对应的计算结果(最新的一行数据)
# iloc[-1] 代表取最后一行,即当前 bar 的值
current_ma = df['MA'].iloc[-1]
current_upper = df['Upper'].iloc[-1]
current_lower = df['Lower'].iloc[-1]
# 4. 绘图输出 (Visualization)
# 参数说明: paint(指标名称, 数值, 位置索引, 线型, 颜色)
# 位置索引 -1 表示在主图绘制
# 绘制中轨 (黄色)
ContextInfo.paint('My_MA', current_ma, -1, 0, 'yellow')
# 绘制上轨 (青色)
ContextInfo.paint('My_Upper', current_upper, -1, 0, 'cyan')
# 绘制下轨 (品红)
ContextInfo.paint('My_Lower', current_lower, -1, 0, 'magenta')
# 5. 进阶:在图表上标记信号
# 例如:当收盘价突破上轨时,在图上写字
current_close = df['close'].iloc[-1]
if current_close > current_upper:
ContextInfo.draw_text(True, current_upper, '突破')
关键函数详解
1. ContextInfo.paint()
这是将你的逻辑可视化的核心函数。
- 用法:
ContextInfo.paint(name, value, index, line_style, color, limit) - 参数:
name: 指标名称(显示在左上角)。value: 当前 K 线需要绘制的数值。index: -1 表示画在主图(和 K 线叠加),0 或其他正数表示画在副图(独立窗口)。line_style: 0 为曲线,42 为柱状线。color: 颜色字符串(如 'red', 'green', 'white', 'yellow')。
2. 数据获取与 Pandas
QMT 的 get_market_data_ex 返回的是 Pandas DataFrame 格式,这使得计算非常方便:
rolling(window=N).mean():计算移动平均。rolling(window=N).std():计算标准差。- 你可以使用任何数学公式,例如
(High + Low + Close) / 3计算典型价。
如何在 QMT 中运行
- 打开 QMT 客户端,进入【模型研究】或【策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码复制粘贴到编辑器中。
- 点击工具栏的【运行】或【编译】。
- 在行情图上,该策略会根据你的逻辑画出三条线。
常见问题 (Q&A)
Q: 我可以使用第三方库来计算指标吗?
A: 可以。QMT 内置了 talib 库,这是金融领域标准的计算库。例如计算 RSI 可以直接调用 talib.RSI(...),无需自己手写公式。
Q: 如何将指标画在副图(K线图下方)而不是主图上?
A: 在 ContextInfo.paint 函数中,将第三个参数 index 设置为 0(或者不填,默认通常是副图,但建议显式指定)。如果填 -1 则是主图叠加。
Q: 为什么我的指标线是直的或者没有显示?
A: 请检查 get_market_data_ex 中的 count 参数。如果获取的历史数据长度不足以计算指标(例如计算 20 日均线但只获取了 10 根 K 线),结果将是 NaN,导致无法绘图。
Q: 如何只在特定条件下画线?
A: paint 函数在每个 handlebar 周期都会被调用。如果你只想在特定条件下显示,可以结合 ContextInfo.draw_icon 或 ContextInfo.draw_text 来标记特定点,而不是画连续的线。对于 paint,如果传入 NaN 值,通常会断开连线。