🚀 AI 一键生成 qmt 策略代码

如何将 QMT 策略回测结果导出并使用 Matplotlib 进行可视化分析?

qmt | 发布时间: 2025/12/5
以下内容由 EasyQuant 生成。

问题描述

如何将策略回测的净值数据进行可视化绘图?

解决方案

在 QMT 平台中,将策略回测的净值数据进行可视化绘图,最直接且推荐的方式是使用平台内置的 ContextInfo.paint() 函数。该函数可以将计算出的数值直接绘制在回测界面的 K 线图或副图上。

以下是具体的实现步骤和代码示例。

核心思路

  1. 获取净值:在 handlebar 函数中,使用 ContextInfo.get_net_value(index) 获取当前 K 线位置的策略净值。
  2. 绘制曲线:使用 ContextInfo.paint() 将获取到的净值画在图表上。

完整策略代码示例

你可以将以下代码复制到 QMT 的策略编辑器中进行回测。为了演示效果,该策略包含了一个简单的买入逻辑,以便净值发生变化。

# -*- coding: gbk -*-

def init(ContextInfo):
    """
    初始化函数
    """
    # 设置相关标的,这里以平安银行为例
    ContextInfo.set_universe(['000001.SZ'])
    
    # 设置回测初始资金
    ContextInfo.capital = 1000000
    
    # 设置手续费(可选,为了回测更真实)
    # 佣金万三
    ContextInfo.set_commission(0, [0.001, 0.001, 0.0003, 0.0003, 0, 5])
    
    # 定义一个全局变量用于控制只买一次
    ContextInfo.has_bought = False

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前K线索引
    index = ContextInfo.barpos
    
    # --- 简单的交易逻辑 (为了让净值产生波动) ---
    # 获取当前主图代码
    stock_code = ContextInfo.stockcode
    
    # 如果没买过,且是第一根K线之后,全仓买入
    if not ContextInfo.has_bought and index > 0:
        # 获取最新价
        last_price = ContextInfo.get_market_data(['close'], stock_code=[stock_code], count=1, period='1d')
        if last_price is not None:
            # 全仓买入
            passorder(23, 1101, ContextInfo.accountid, stock_code, 5, -1, 1, ContextInfo)
            ContextInfo.has_bought = True
            print(f"在索引 {index} 处买入 {stock_code}")

    # --- 核心:净值可视化绘图 ---
    
    # 1. 获取当前回测节点的策略净值
    # 注意:get_net_value 仅在回测模式下有效
    net_value = ContextInfo.get_net_value(index)
    
    # 2. 使用 paint 函数绘图
    # 参数说明:
    # name: 指标名称,显示在左上角
    # value: 要绘制的数值
    # index: 位置索引,-1 表示当前位置
    # line_style: 线型,0 为曲线
    # color: 颜色 (可选)
    # limit: 坐标轴控制 (可选)
    ContextInfo.paint('策略净值', net_value, -1, 0, 'red')
    
    # 3. (可选) 绘制基准净值进行对比
    # 这里的基准通常是 1.0 开始,具体取决于回测设置的基准
    # ContextInfo.paint('基准线', 1.0, -1, 0, 'blue')

关键函数详解

1. ContextInfo.get_net_value(index)

  • 作用:获取策略在指定 K 线索引位置的单位净值(初始值为 1.0)。
  • 参数index,通常传入 ContextInfo.barpos
  • 注意:此函数仅在回测模式下返回有效数据。

2. ContextInfo.paint(name, value, index, line_style, color, limit)

  • 作用:在图表上绘制指标线。
  • 参数
    • name (string): 指标名称,例如 '策略净值'
    • value (number): 当前要画的数值。
    • index (number): 填 -1 即可,表示跟随主图 K 线索引。
    • line_style (number): 0 代表曲线,42 代表柱状线。
    • color (string): 颜色,如 'red', 'blue', 'yellow' 等。
    • limit (string):
      • 如果不填,QMT 会尝试将线条和 K 线画在同一个坐标系中。由于净值通常是 1.0 附近,而股价可能是几十几百,这会导致图形压缩。
      • 建议操作:在运行策略时,在 QMT 界面上选择**“副图”**显示,或者在代码中不加 limit 参数,但在界面上右键点击主图 -> 选择“叠加指标”或“副图指标”来查看。

如何在 QMT 界面查看结果

  1. 编译并运行:点击策略编辑器的“回测”按钮。
  2. 查看位置
    • 如果策略设置中“位置”选的是**“副图”**,净值曲线会直接显示在 K 线图下方的副图区域。
    • 如果选的是**“主图”,由于数值差异巨大(净值约 1.0 vs 股价),建议在图表上右键** -> 叠加指标 -> 选择你的策略,或者将策略属性改为副图显示。

进阶:使用 Matplotlib 绘图(非实时)

如果你希望在回测结束后弹出一个独立的 Python 图表,可以使用 matplotlib 库。

# -*- coding: gbk -*-
import matplotlib.pyplot as plt

def init(ContextInfo):
    ContextInfo.net_values = [] # 用于存储净值序列
    ContextInfo.dates = []      # 用于存储日期序列
    ContextInfo.set_universe(['000001.SZ'])
    ContextInfo.capital = 1000000

def handlebar(ContextInfo):
    index = ContextInfo.barpos
    
    # 记录数据
    nv = ContextInfo.get_net_value(index)
    current_time = ContextInfo.get_bar_timetag(index)
    
    ContextInfo.net_values.append(nv)
    ContextInfo.dates.append(current_time)
    
    # 简单的买入逻辑...
    if index == 0:
        passorder(23, 1101, ContextInfo.accountid, ContextInfo.stockcode, 5, -1, 1, ContextInfo)

    # 判断是否是最后一根K线,如果是,则画图
    if ContextInfo.is_last_bar():
        plt.figure(figsize=(10, 6))
        plt.plot(ContextInfo.net_values, label='Net Value', color='red')
        plt.title('Strategy Backtest Net Value')
        plt.xlabel('Bar Index')
        plt.ylabel('Net Value')
        plt.legend()
        plt.grid(True)
        plt.show()

Q&A

Q: 为什么我的 paint 画出来的线是一条直线?
A: 可能是因为策略没有进行任何交易,或者交易没有成交,导致账户资金没有变化,净值一直维持在 1.0。请检查 passorder 是否被调用以及是否成交。

Q: paint 函数能画在独立的窗口吗?
A: paint 函数是绑定在 QMT 行情图表上的。如果需要独立窗口,请使用上面提到的 matplotlib 方法。

Q: 回测时 get_net_value 返回的净值包含浮动盈亏吗?
A: 是的,get_net_value 计算的是包含持仓浮动盈亏和现金在内的总资产净值。