问题描述
解决方案
在 QMT 中获取股指期货和对应指数的实时价格并计算基差,主要涉及以下几个步骤:
- 确定标的:确定你要关注的期货品种(如 IF, IC, IH, IM)及其对应的现货指数代码。
- 获取主力合约:使用
get_main_contract动态获取当前的主力合约代码(因为期货合约会按月交割变化)。 - 获取实时行情:使用
get_full_tick获取最新的 Tick 快照数据(包含最新价lastPrice)。 - 计算基差:通常基差定义为 现货价格 - 期货价格。
以下是完整的策略代码示例。
策略代码实现
# -*- coding: gbk -*-
def init(ContextInfo):
"""
初始化函数
"""
# 定义期货品种与其对应的现货指数代码映射关系
# IF: 沪深300期货 -> 000300.SH
# IC: 中证500期货 -> 000905.SH
# IH: 上证50期货 -> 000016.SH
# IM: 中证1000期货 -> 000852.SH
ContextInfo.pairs = {
'IF.IF': '000300.SH',
'IC.IF': '000905.SH',
'IH.IF': '000016.SH',
'IM.IF': '000852.SH'
}
# 设置定时器,例如每3秒运行一次计算函数(可选,也可以直接写在handlebar里)
# 这里为了演示清晰,我们直接在 handlebar 中由行情驱动执行
def handlebar(ContextInfo):
"""
K线/行情驱动函数
"""
# 仅在实时行情的最后一根K线(或最新Tick)时计算,避免回测历史数据时打印过多日志
if not ContextInfo.is_last_bar():
return
# 遍历定义的品种对
for future_generic_code, index_code in ContextInfo.pairs.items():
# 1. 获取当前主力合约代码
# get_main_contract 会返回如 'IF2406.IF' 这样的具体合约代码
main_contract = ContextInfo.get_main_contract(future_generic_code)
if not main_contract:
print(f"未找到 {future_generic_code} 的主力合约")
continue
# 2. 获取实时 Tick 数据
# get_full_tick 返回一个字典,key是合约代码,value是包含行情的字典
code_list = [main_contract, index_code]
tick_data = ContextInfo.get_full_tick(code_list)
# 检查数据是否获取成功
if main_contract in tick_data and index_code in tick_data:
# 提取最新价
fut_price = tick_data[main_contract].get('lastPrice')
idx_price = tick_data[index_code].get('lastPrice')
# 确保价格有效(非0且非None)
if fut_price and idx_price:
# 3. 计算基差 (Basis = Spot - Future)
basis = idx_price - fut_price
# 计算基差率 (Basis Rate = Basis / Spot Price)
basis_rate = (basis / idx_price) * 100
# 4. 输出结果
print("=" * 30)
print(f"品种: {future_generic_code} | 主力合约: {main_contract}")
print(f"指数代码: {index_code}")
print(f"期货价格: {fut_price:.2f}")
print(f"指数价格: {idx_price:.2f}")
print(f"当前基差: {basis:.2f}")
print(f"基差率: {basis_rate:.2f}%")
print("=" * 30)
else:
print(f"价格数据无效: {main_contract} or {index_code}")
else:
print(f"获取行情失败,请检查是否已下载或订阅: {code_list}")
代码核心逻辑解析
-
ContextInfo.get_main_contract(codemarket):- 这是获取主力合约的关键。传入通用的品种代码(如
'IF.IF'),它会自动返回当前市场上持仓量最大的具体合约代码(如'IF2312.IF')。这保证了策略始终跟踪流动性最好的合约。
- 这是获取主力合约的关键。传入通用的品种代码(如
-
ContextInfo.get_full_tick(stock_code_list):- 这是获取实时快照最高效的接口。
- 它返回一个字典,包含买卖五档、最新价、成交量等信息。
- 我们主要使用其中的
'lastPrice'字段。
-
基差计算公式:
- 代码中采用的是国内常用的定义:
基差 = 现货指数价格 - 期货合约价格。 - 如果基差为正(升水),说明现货价格高于期货价格;
- 如果基差为负(贴水),说明期货价格高于现货价格。
- 代码中采用的是国内常用的定义:
运行说明
- 将上述代码复制到 QMT 的【策略编辑器】中。
- 在【模型设置】中,选择一个默认的运行周期(如 1分钟 或 1天 均可,因为
get_full_tick获取的是切片数据,不受 K 线周期影响,但handlebar的触发频率受行情推送影响)。 - 点击【运行】。
- 观察下方的【日志输出】窗口,即可看到实时的基差数据。
Q&A
Q: 为什么有时候 get_full_tick 获取不到数据?
A: get_full_tick 依赖于本地行情缓存或实时推送。如果这是你第一次查看某个冷门合约,可能需要先在行情界面打开一下该图表,或者在代码中使用 ContextInfo.subscribe_quote(code) 显式订阅一下该合约的行情。
Q: 如何计算次主力合约(下月合约)的基差?
A: QMT 的 get_main_contract 只能获取主力。如果要获取次主力,通常需要获取该品种的所有合约列表(可以使用 get_option_list 变通获取或通过板块成分股逻辑),然后根据持仓量排序,取持仓量第二大的合约。
Q: 这个策略可以用来进行期现套利吗?
A: 可以作为核心逻辑的一部分。你需要设定一个基差阈值(例如基差率 > 2%),当满足条件时,买入期货并融券卖出ETF(反向套利),或者卖出期货并买入ETF/一篮子股票(正向套利)。但实际交易还需要考虑冲击成本、资金占用和滑点。