3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT 平台中,将策略回测的净值数据进行可视化绘图,最直接且推荐的方式是使用平台内置的 ContextInfo.paint() 函数。该函数可以将计算出的数值直接绘制在回测界面的 K 线图或副图上。
以下是具体的实现步骤和代码示例。
handlebar 函数中,使用 ContextInfo.get_net_value(index) 获取当前 K 线位置的策略净值。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')
ContextInfo.get_net_value(index)index,通常传入 ContextInfo.barpos。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):
limit 参数,但在界面上右键点击主图 -> 选择“叠加指标”或“副图指标”来查看。如果你希望在回测结束后弹出一个独立的 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: 为什么我的 paint 画出来的线是一条直线?
A: 可能是因为策略没有进行任何交易,或者交易没有成交,导致账户资金没有变化,净值一直维持在 1.0。请检查 passorder 是否被调用以及是否成交。
Q: paint 函数能画在独立的窗口吗?
A: paint 函数是绑定在 QMT 行情图表上的。如果需要独立窗口,请使用上面提到的 matplotlib 方法。
Q: 回测时 get_net_value 返回的净值包含浮动盈亏吗?
A: 是的,get_net_value 计算的是包含持仓浮动盈亏和现金在内的总资产净值。