🚀 AI 一键生成 qmt 策略代码

QMT Python 技巧:将 get_market_data 结果转换为 DataFrame

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

问题描述

get_market_data 返回的数据怎么转成 DataFrame?

解决方案

在 QMT 中,ContextInfo.get_market_data 的返回值类型高度依赖于你传入的参数(主要是股票数量时间范围/count)。

在大多数常用场景下,它已经返回了 pandas.DataFramepandas.Panel(旧版 Pandas 的三维结构)。

以下是针对不同情况将数据转换为标准 DataFrame 的方法:

1. 单只股票,多条数据(直接返回 DataFrame)

如果你只获取一只股票的一段时间序列数据,返回值本身就是 DataFrame,无需转换。

# -*- coding: gbk -*-
def handlebar(ContextInfo):
    # 获取平安银行最近 10 天的开高低收
    # stock_code 列表中只有一个元素
    df = ContextInfo.get_market_data(
        ['open', 'high', 'low', 'close'], 
        stock_code=['000001.SZ'], 
        period='1d', 
        count=10
    )
    
    # 此时 df 已经是 DataFrame 类型
    # index 是时间,columns 是 open, high, low, close
    print(type(df)) 
    print(df)

2. 多只股票,多条数据(返回 Panel,需转换)

如果你获取多只股票的时间序列数据,get_market_data 返回的是 pandas.Panel(三维数组:Items=股票, Major_axis=时间, Minor_axis=字段)。

由于 Panel 在新版 Pandas 中已被移除(虽然 QMT 内置环境支持),且操作不便,通常建议将其转换为 MultiIndex DataFrame

转换方法:使用 .to_frame()

# -*- coding: gbk -*-
def handlebar(ContextInfo):
    # 获取两只股票最近 5 天的数据
    panel_data = ContextInfo.get_market_data(
        ['open', 'close'], 
        stock_code=['000001.SZ', '600000.SH'], 
        period='1d', 
        count=5
    )
    
    print("原始类型:", type(panel_data)) # <class 'pandas.core.panel.Panel'>
    
    # 方法一:转换为 MultiIndex DataFrame (推荐)
    # 转换后 index 变为 (时间, 股票代码) 的双重索引
    df_multi = panel_data.to_frame()
    print("转换后的 DataFrame:")
    print(df_multi.head())
    
    # 方法二:如果你只想要某个字段(例如 close)的 DataFrame
    # 结果:index=时间,columns=股票代码
    df_close = panel_data['close']
    print("收盘价 DataFrame:")
    print(df_close.head())

3. (推荐) 使用 get_market_data_ex

官方文档建议使用 ContextInfo.get_market_data_ex 替代 get_market_data
get_market_data_ex 返回的是一个 字典 (Dict),Key 是股票代码,Value 是该股票的 DataFrame

如果你需要将其合并为一个大的 DataFrame,可以使用 pd.concat

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

def handlebar(ContextInfo):
    stock_list = ['000001.SZ', '600000.SH']
    
    # 获取数据,返回格式为 {code: DataFrame, code: DataFrame}
    data_dict = ContextInfo.get_market_data_ex(
        ['open', 'high', 'low', 'close'], 
        stock_list, 
        period='1d', 
        count=5
    )
    
    # 遍历字典查看单独的 DataFrame
    for code, df in data_dict.items():
        print(f"股票 {code} 的数据类型: {type(df)}")
    
    # 【转换技巧】将字典合并为一个大的 DataFrame
    # 1. 给每个 DataFrame 添加一列 'code'
    for code in data_dict:
        data_dict[code]['code'] = code
        
    # 2. 使用 concat 合并
    full_df = pd.concat(data_dict.values())
    
    # 3. (可选) 设置索引方便查询
    # full_df.index.name = 'time'
    # full_df = full_df.reset_index().set_index(['time', 'code'])
    
    print("合并后的 DataFrame:")
    print(full_df)

总结

  1. 单股get_market_data 直接返回 DataFrame。
  2. 多股get_market_data 返回 Panel,使用 .to_frame() 转为 DataFrame。
  3. 最佳实践:使用 get_market_data_ex,它返回字典包含 DataFrame,逻辑更清晰,然后使用 pd.concat 合并。

Q&A

Q: 为什么 get_market_data 返回多只股票时是 Panel 类型?
A: QMT 内置的 Python 环境版本较老(通常是 Python 3.6.8,Pandas 0.22.0),在那个版本的 Pandas 中,Panel 是用于存储三维数据(股票 x 时间 x 字段)的标准结构。虽然新版 Pandas 已废弃 Panel,但在 QMT 环境中它依然存在。

Q: get_market_data_exget_market_data 有什么主要区别?
A: get_market_data 的返回类型会根据参数变化(值、Series、DataFrame 或 Panel),容易导致代码出错。get_market_data_ex 返回结构统一为字典 {code: DataFrame},且支持订阅逻辑,更稳定且易于处理。

Q: 如何将 DataFrame 中的时间戳索引转换为可读日期?
A: QMT 返回的 DataFrame 索引通常是字符串格式的时间(如 '20231027' 或 '20231027093000')。你可以使用 pd.to_datetime(df.index) 将其转换为 datetime 对象,或者直接解析字符串。如果是毫秒时间戳,可以使用 ContextInfo 中的 timetag_to_datetime 函数处理。