🚀 AI 一键生成 qmt 策略代码

如何在 QMT 中用代码深度分析回测结果?get_result_records 函数使用详解

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

问题描述

我该如何用代码获取详细的回测数据,比如每一笔买卖记录和每日持仓?

解决方案

在 QMT 平台中,获取回测详细数据(如每一笔成交明细和每日持仓)主要通过 get_result_records 函数来实现。

核心函数说明

get_result_records(recordtype, index, ContextInfo)

  • recordtype (字符串): 指定获取的数据类型。
    • 'dealdetails': 获取交易明细(每一笔买卖记录)。
    • 'holdings': 获取当前持仓(指定 K 线位置的持仓)。
    • 'buys': 获取买入持仓历史。
    • 'sells': 获取卖出持仓历史。
    • 'historysums': 获取历史汇总信息。
  • index (整数): K 线索引号,通常使用 ContextInfo.barpos
  • ContextInfo: 全局上下文对象。

代码实现

以下是一个完整的 Python 策略示例。该策略会在回测结束时(最后一根 K 线),自动打印出回测期间所有的交易明细最终持仓情况。

# -*- coding: gbk -*-
import pandas as pd

def init(ContextInfo):
    # 设置股票池,这里以平安银行为例
    ContextInfo.set_universe(['000001.SZ'])
    # 设置基准
    ContextInfo.benchmark = '000300.SH'
    # 设置账号(回测模式下为虚拟账号)
    ContextInfo.set_account('account_name')
    
    # 简单的策略逻辑变量:记录是否买过
    ContextInfo.has_bought = False

def handlebar(ContextInfo):
    # 获取当前K线索引
    index = ContextInfo.barpos
    # 获取当前时间
    timetag = ContextInfo.get_bar_timetag(index)
    
    # --- 简单的交易逻辑用于生成数据 ---
    # 如果是第一根K线,买入
    if index == 0 and not ContextInfo.has_bought:
        # 按最新价买入 1000 股
        order_shares('000001.SZ', 1000, 'fix', 10.0, ContextInfo, 'account_name')
        ContextInfo.has_bought = True
        print(f"触发买入: 000001.SZ, 时间: {timetag}")
        
    # 如果是第 10 根K线,卖出 500 股
    if index == 10:
        order_shares('000001.SZ', -500, 'fix', 11.0, ContextInfo, 'account_name')
        print(f"触发卖出: 000001.SZ, 时间: {timetag}")

    # --- 获取回测数据的核心逻辑 ---
    # 通常我们在回测结束时(最后一根K线)一次性获取所有记录
    if ContextInfo.is_last_bar():
        print("=" * 30)
        print("回测结束,开始获取详细数据...")
        
        # 1. 获取交易明细 (每一笔买卖)
        # recordtype = 'dealdetails'
        trade_records = get_result_records('dealdetails', index, ContextInfo)
        
        print(f"\n--- 交易明细 (共 {len(trade_records)} 笔) ---")
        for record in trade_records:
            # record 是一个对象,包含多个属性
            # 将毫秒时间戳转换为可读时间
            trade_time = timetag_to_datetime(record.trade_date, '%Y-%m-%d %H:%M:%S')
            
            # 解析买卖方向
            direction_str = "买入" if record.open_close == 1 else "卖出" # 股票: 1买 0卖
            
            print(f"时间: {trade_time}, 代码: {record.stockcode}, "
                  f"方向: {direction_str}, 价格: {record.trade_price:.2f}, "
                  f"成交额: {record.trade_balance:.2f}, 手续费: {record.commission:.2f}")

        # 2. 获取当前持仓 (最终持仓)
        # recordtype = 'holdings'
        holding_records = get_result_records('holdings', index, ContextInfo)
        
        print(f"\n--- 最终持仓 (共 {len(holding_records)} 只) ---")
        for hold in holding_records:
            print(f"代码: {hold.stockcode}, 持仓数量: {hold.position}, "
                  f"持仓成本: {hold.trade_price:.2f}, 最新价: {hold.current_price:.2f}, "
                  f"持仓盈亏: {hold.profit:.2f}")
                  
        print("=" * 30)

返回对象属性详解

get_result_records 返回的是一个列表,列表中的每个对象包含以下常用属性(可以通过 dir(obj) 查看所有属性):

  1. 交易明细 (dealdetails) 对象属性:

    • stockcode: 股票代码
    • trade_date: 交易时间(毫秒级时间戳)
    • open_close: 开平标志(股票:1 买,0 卖;期货:1 开,0 平)
    • trade_price: 成交价格
    • trade_balance: 成交金额
    • commission: 手续费
    • operate_type: 操作类型
  2. 持仓 (holdings) 对象属性:

    • stockcode: 股票代码
    • position: 持仓数量
    • trade_price: 持仓成本价
    • current_price: 当前最新价
    • profit: 持仓盈亏
    • market: 市场代码

常见问题 Q&A

Q: 如何获取每日的持仓变化,而不仅仅是最终持仓?
A: get_result_records('holdings', index, ContextInfo) 获取的是 index 对应的那个时刻的持仓。如果你需要每日持仓,可以在 handlebar 函数中判断每日收盘时间(例如判断时间戳或 ContextInfo.period 为日线),然后在每一根 K 线结束时调用该函数并将结果保存到全局列表或写入文件。

Q: 为什么我在实盘模式下调用这个函数没有数据?
A: get_result_records 函数仅支持回测模式。在实盘或模拟交易模式下,你需要使用 get_trade_detail_data 函数来获取账号的实际委托、成交和持仓信息。

Q: 返回的交易时间是时间戳,如何转换成日期?
A: 使用 QMT 内置函数 timetag_to_datetime(timetag, format),例如 timetag_to_datetime(record.trade_date, '%Y%m%d')