问题描述
解决方案
在 QMT (Quantitative Trading Platform) 中,引用界面上已经制作好的扩展数据(通常是用户自定义的指标或外部导入的数据),主要使用 API 提供的引用函数。
最常用的函数是 ext_data(获取单点数据)和 ext_data_range(获取区间数据)。
以下是详细的操作步骤和代码示例。
核心函数说明
1. 获取特定时刻的扩展数据:ext_data
该函数通常用于 handlebar 中,获取当前 K 线对应的扩展数据值。
- 语法:
ext_data(extdataname, stockcode, deviation, ContextInfo) - 参数:
extdataname: 字符串,界面上定义的扩展数据名称(必须完全一致)。stockcode: 字符串,股票代码(如 '600000.SH')。deviation: 数字,K 线偏移量。0表示当前 K 线,-1表示前一根 K 线。ContextInfo: 策略上下文对象。
- 返回: 数字(指标值)。
2. 获取一段时间的扩展数据:ext_data_range
该函数用于获取指定时间段内的扩展数据序列。
- 语法:
ext_data_range(extdataname, stockcode, begintime, endtime, ContextInfo) - 参数:
begintime/endtime: 字符串,格式如 '20230101' 或 '20230101093000'。
- 返回: 字典 (Dict),时间戳为 Key,数值为 Value。
3. 获取全量扩展数据(高效):ContextInfo.get_ext_all_data
建议在 init 中调用,一次性加载数据,效率最高。
- 语法:
ContextInfo.get_ext_all_data(extdataname, start_time, end_time) - 返回: Pandas Panel 对象(包含值和排名)。
完整代码示例
假设你在 QMT 界面上已经创建了一个名为 "MyIndicator" 的扩展数据。
# -*- coding: gbk -*-
def init(ContextInfo):
# 设置股票池
ContextInfo.set_universe(['600000.SH', '000001.SZ'])
# 方法3:在初始化时一次性获取所有扩展数据(推荐用于回测或需要大量数据时)
# 注意:extdataname 必须与界面上建立的扩展数据名称完全一致
try:
# 获取从 20220101 到 20230101 的数据
ContextInfo.all_ext_data = ContextInfo.get_ext_all_data(
'MyIndicator',
'20220101',
'20230101'
)
print("批量加载扩展数据成功")
except Exception as e:
print("批量加载扩展数据失败:", e)
def handlebar(ContextInfo):
# 获取当前处理的股票代码
stock_code = ContextInfo.stockcode
# --- 方法1:获取当前 K 线的扩展数据值 ---
# 0 表示当前 K 线,如果需要前一根 K 线的数据,可以使用 -1
current_val = ext_data('MyIndicator', stock_code, 0, ContextInfo)
# 获取前一根 K 线的值
prev_val = ext_data('MyIndicator', stock_code, -1, ContextInfo)
print(f"代码: {stock_code}, 当前扩展数据值: {current_val}, 前一根值: {prev_val}")
# --- 方法2:获取指定时间段的扩展数据 ---
# 仅在最后一根 K 线时打印,避免日志过多
if ContextInfo.is_last_bar():
start_t = '20230101'
end_t = '20230201'
range_data = ext_data_range('MyIndicator', stock_code, start_t, end_t, ContextInfo)
print(f"区间数据示例 ({stock_code}):", range_data)
# 简单的交易逻辑示例:如果当前扩展数据值大于 10 则买入
if current_val > 10:
print(f"{stock_code} 触发买入信号,指标值: {current_val}")
# order_shares(stock_code, 100, ContextInfo, 'account_id')
注意事项
- 名称匹配:代码中的
extdataname必须与 QMT 客户端【数据管理】->【扩展数据】列表中显示的名称完全一致(区分大小写)。 - 数据计算:在引用之前,请确保在界面上已经对该扩展数据进行了刷新或计算,否则可能获取不到数据或获取到空值。
- 周期一致性:扩展数据在生成时有固定的周期(如日线、分钟线)。在策略中引用时,最好确保策略运行周期与扩展数据周期逻辑上是匹配的,或者理解偏移量
deviation在不同周期下的含义。 - 性能优化:如果在
handlebar中频繁调用ext_data可能会影响回测速度。对于大规模计算,建议使用ContextInfo.get_ext_all_data在init中预加载。
Q&A
Q: 为什么调用 ext_data 返回的值是 NaN 或 0?
A: 这通常有几个原因:
- 扩展数据名称写错了。
- 界面上没有对该扩展数据进行“刷新计算”,导致本地没有数据文件。
- 策略运行的时间段内,该扩展数据本身就没有值(例如停牌或数据源缺失)。
Q: ext_data 中的 deviation 参数 -1 代表什么?
A: deviation 代表 K 线的偏移量。0 代表当前正在计算的这根 K 线,-1 代表当前 K 线左边的一根(即上一周期),1 代表向右偏移(通常用于未来函数,实盘中不可用)。
Q: 扩展数据可以引用 Python 计算的结果吗?
A: QMT 的扩展数据主要是基于界面上的公式(类似通达信公式)生成的。如果你需要引用 Python 计算的复杂数据,建议直接在 Python 策略代码中计算,或者将 Python 计算结果保存为本地文件(如 CSV),然后在策略中读取 CSV,而不是通过“扩展数据”接口。
Q: get_ext_all_data 返回的数据结构是什么?
A: 它返回一个 pandas.Panel 对象(在旧版 pandas 中)或类似的多维结构。Items 轴通常是时间戳,Major_axis 是股票代码,Minor_axis 是数据域(通常包含 'value' 和 'rank')。具体使用时建议先 print 出来查看结构。