🚀 AI 一键生成 qmt 策略代码

QMT 数据处理:如何将回测成交记录导出为 JSON 文件用于外部分析?

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

问题描述

如何把 QMT 的成交记录导出成 JSON 文件?

解决方案

要将 QMT 的成交记录导出为 JSON 文件,主要涉及以下三个步骤:

  1. 获取数据:使用 get_trade_detail_data 函数获取成交(DEAL)类型的对象列表。
  2. 数据转换:QMT 返回的是 C++ 封装的对象(如 CDealDetail),无法直接被 JSON 序列化。需要遍历对象属性(通常以 m_ 开头)并将其转换为标准的 Python 字典。
  3. 文件写入:使用 Python 标准库 json 将字典列表写入文件。

以下是完整的策略代码实现。

策略代码

# -*- coding: gbk -*-
import json
import os
import datetime

def init(ContextInfo):
    # ================= 配置区域 =================
    # 请在此处替换您的资金账号
    ContextInfo.accID = '6000000000' 
    # 账号类型:'STOCK' (股票), 'FUTURE' (期货), 'CREDIT' (两融)
    ContextInfo.accType = 'STOCK'
    # 导出文件的路径 (请确保文件夹存在)
    ContextInfo.json_path = 'D:/qmt_trade_records.json'
    # ===========================================

    # 绑定账号,必须步骤
    ContextInfo.set_account(ContextInfo.accID)
    print("策略初始化完成,准备导出成交记录...")

def handlebar(ContextInfo):
    # 仅在最后一根K线(实时行情或回测结束时)执行一次导出,避免重复写入
    if not ContextInfo.is_last_bar():
        return

    # 1. 获取成交记录对象列表
    # 参数说明:账号ID, 账号类型, 数据类型('DEAL'代表成交)
    deal_objects = get_trade_detail_data(ContextInfo.accID, ContextInfo.accType, 'DEAL')

    if not deal_objects:
        print("未查询到成交记录,跳过导出。")
        return

    # 2. 将 QMT 对象转换为字典列表
    data_list = []
    for obj in deal_objects:
        deal_dict = convert_obj_to_dict(obj)
        data_list.append(deal_dict)

    # 3. 写入 JSON 文件
    try:
        with open(ContextInfo.json_path, 'w', encoding='utf-8') as f:
            # ensure_ascii=False 保证中文能正常显示,indent=4 用于美化格式
            json.dump(data_list, f, ensure_ascii=False, indent=4)
        
        print(f"成功导出 {len(data_list)} 条成交记录到: {ContextInfo.json_path}")
    except Exception as e:
        print(f"导出 JSON 失败: {e}")

def convert_obj_to_dict(qmt_obj):
    """
    辅助函数:将 QMT 的 C++ 对象属性转换为 Python 字典
    QMT 的属性通常以 'm_' 开头
    """
    result = {}
    # 获取对象的所有属性名
    attributes = dir(qmt_obj)
    
    for attr in attributes:
        # 过滤掉内置方法,只保留 m_ 开头的属性
        if attr.startswith('m_'):
            try:
                value = getattr(qmt_obj, attr)
                # 处理一下可能的特殊类型,确保 JSON 可序列化
                if isinstance(value, (str, int, float, bool, type(None))):
                    result[attr] = value
                else:
                    # 对于复杂类型,转为字符串
                    result[attr] = str(value)
            except Exception:
                continue
                
    # 为了方便阅读,可以手动映射一些关键字段名(可选)
    # 如果不需要重命名,可以直接返回 result
    formatted_result = {
        "stock_code": result.get("m_strInstrumentID", ""),   # 证券代码
        "stock_name": result.get("m_strInstrumentName", ""), # 证券名称
        "direction": result.get("m_nDirection", 0),          # 买卖方向 (48买, 49卖)
        "price": result.get("m_dPrice", 0.0),                # 成交均价
        "volume": result.get("m_nVolume", 0),                # 成交数量
        "amount": result.get("m_dTradeAmount", 0.0),         # 成交金额
        "trade_time": result.get("m_strTradeTime", ""),      # 成交时间
        "trade_date": result.get("m_strTradeDate", ""),      # 成交日期
        "order_id": result.get("m_strOrderSysID", ""),       # 委托编号
        "trade_id": result.get("m_strTradeID", ""),          # 成交编号
        "commission": result.get("m_dComssion", 0.0),        # 手续费
        "remark": result.get("m_strRemark", ""),             # 备注
        "raw_data": result # 保留原始所有字段以备查
    }
    
    return formatted_result

代码说明

  1. get_trade_detail_data: 这是核心 API,用于获取交易明细。第三个参数传入 'DEAL' 即表示获取成交记录。如果需要导出委托记录,可将其改为 'ORDER'
  2. convert_obj_to_dict: QMT 返回的数据是封装好的对象,不能直接用 json.dump。这个函数通过 dir() 遍历对象属性,提取所有以 m_ 开头的字段(这是 QMT 底层 C++ 对象的命名规范),并将其转化为字典。
  3. handlebar 控制: 代码中加入了 if not ContextInfo.is_last_bar(): return 判断,确保只在运行到最新行情或回测结束时执行一次导出操作,防止在每一根历史 K 线上重复写入文件导致 IO 瓶颈。
  4. JSON 格式化: 使用 ensure_ascii=False 可以让输出的 JSON 文件直接显示中文(如股票名称),而不是 Unicode 编码。

常见问题 Q&A

Q: 为什么导出的文件中没有数据?
A: 请检查 ContextInfo.accID 是否填写正确,且该账号在 QMT 交易终端中已登录。此外,get_trade_detail_data 只能获取当日的成交记录(部分券商版本支持获取历史,视具体柜台接口而定)。如果是回测模式,它会导出回测期间产生的所有模拟成交。

Q: 如何导出历史成交记录(非当日)?
A: QMT 的 Python API 主要针对当日交易和策略运行。如果要获取历史已结算的成交记录,通常需要通过券商提供的外部文件导入,或者如果您的 QMT 版本支持,尝试查阅是否有 get_history_trade_data 类接口(标准版 API 通常仅支持当日)。

Q: 导出的买卖方向是数字 48 和 49,是什么意思?
A: 这是 ASCII 码对应的值。

  • 48 对应字符 '0',在 QMT 定义中通常代表 买入 (ENTRUST_BUY)。
  • 49 对应字符 '1',在 QMT 定义中通常代表 卖出 (ENTRUST_SELL)。
  • 建议在处理 JSON 数据时建立一个映射表来翻译这些代码。

Q: 可以自动定时导出吗?
A: 可以。您可以在 init 中使用 ContextInfo.run_time 设置一个定时任务,例如每天收盘后 15:05 执行导出函数。