问题描述
his_price = ContextInfo.get_market_data_ex(fields=[], stock_code=['c2409.DF'], period='1m', count=10,fill_data=True)
print(his_price['c2409.DF'])
为什么这样始终获取不到期货的数据,返回的Dataframe是空,在模拟交易、回测都是空,回测的历史数据已经下载好了。
解决方案
在 QMT 平台中使用 ContextInfo.get_market_data_ex 获取期货数据时返回空的 DataFrame,通常是由以下几个原因导致的。请按照以下步骤逐一排查:
1. 合约已过期(最常见原因)
你请求的合约是 c2409.DF(大商所玉米24年9月合约)。
- 在模拟交易/实盘中:如果当前时间已经超过了 2024 年 9 月,该合约已经退市。QMT 的实时行情接口无法获取已退市合约的最新数据,因此会返回空。
- 在回测中:如果你的回测时间区间(在策略编辑器的“回测参数”中设置的开始时间和结束时间)不在该合约的存续期内(例如你设置的回测时间是 2024年10月),同样会获取不到数据。
解决办法:
- 如果是模拟交易,请更换为当前的主力合约(例如
c2501.DF或c2505.DF)。 - 你可以使用
ContextInfo.get_main_contract('c.DF')动态获取当前的主力合约代码。
2. 数据周期未正确补充
你提到“历史数据已经下载好了”,但请确认你下载的是否是 1分钟线(1m) 数据。
- QMT 的数据管理中,日线(1d)和分钟线(1m, 5m等)是分开下载的。
- 如果你只下载了日线数据,但代码中请求的是
period='1m',本地数据库中没有分钟线数据,就会返回空。
解决办法:
进入 QMT 终端的 数据管理 -> 补充数据,选择大商所(DF),勾选“1分钟线”,并确保时间范围覆盖了你的回测区间。
3. 回测时间与 count 参数的配合
在回测模式下,get_market_data_ex 默认会以当前 K 线(ContextInfo.barpos 对应的时间)为基准往前取 count 根 K 线。
- 如果你的主图品种是股票,而你在代码里取期货数据,且主图的时间轴与期货的交易时间不完全重合,可能会导致取数异常。
- 确保你的策略运行的主图品种也是期货,或者主图的时间轴包含了期货的交易时间。
4. 调试排查代码
你可以将以下代码放入你的策略中运行,通过日志输出来定位问题:
#coding:gbk
def init(ContextInfo):
# 动态获取当前玉米的主力合约
main_contract = ContextInfo.get_main_contract('c.DF')
print(f"当前玉米主力合约为: {main_contract}")
# 将主力合约存入全局变量
ContextInfo.my_contract = main_contract
def handlebar(ContextInfo):
# 确保只在最后一根K线或特定条件下打印,避免日志过多
if not ContextInfo.is_last_bar():
return
contract = ContextInfo.my_contract
# 尝试获取数据
his_price = ContextInfo.get_market_data_ex(
fields=['open', 'high', 'low', 'close', 'volume'],
stock_code=[contract],
period='1m',
count=10,
subscribe=True # 确保订阅开关打开
)
if contract in his_price and not his_price[contract].empty:
print(f"成功获取到 {contract} 的数据:")
print(his_price[contract])
else:
print(f"警告:获取 {contract} 数据为空!请检查合约是否退市或数据是否下载。")
总结
对于 c2409.DF 这种特定交割月的合约,99% 的概率是因为在当前时间点它已经退市。在编写期货策略时,强烈建议使用 ContextInfo.get_main_contract() 动态获取主力合约进行交易和数据获取,而不是将合约代码写死。