问题描述
解决方案
在 QMT 量化平台中,针对期货交易,平台封装了专门的便捷函数来处理开仓和平仓操作,特别是针对期货特有的“平今”(平掉今日新开仓位)和“平昨”(平掉历史持仓)的区别,提供了明确的接口。
以下是基于 QMT Python API 的代码示例,展示了如何进行买入开仓(做多)以及卖出平仓(区分平今优先和平昨优先)。
QMT 期货交易代码示例
# -*- coding: gbk -*-
def init(ContextInfo):
"""
初始化函数
"""
# 1. 设置资金账号
# 请将 'YOUR_FUTURE_ACCOUNT' 替换为您真实的期货资金账号
ContextInfo.accID = 'YOUR_FUTURE_ACCOUNT'
# 2. 绑定账号,用于接收交易回报
ContextInfo.set_account(ContextInfo.accID)
print("策略初始化完成,账号已绑定: " + ContextInfo.accID)
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 获取当前主图的合约代码,也可以直接指定如 'IF2306.IF'
symbol = ContextInfo.stockcode
# 获取当前K线索引
index = ContextInfo.barpos
# 仅在最后一根K线(实时行情)执行交易逻辑,避免回测时重复发单或历史K线发单
if not ContextInfo.is_last_bar():
return
# ==============================================================================
# 场景 1: 买入开仓 (Open Long)
# ==============================================================================
# 假设条件:这里仅为示例,实际策略请替换为您的信号逻辑
buy_condition = False
if buy_condition:
# buy_open(stockcode, amount, style, price, ContextInfo, accId)
# 参数说明:
# stockcode: 合约代码
# amount: 手数
# style: 报价类型,'LATEST'为最新价,'FIX'为指定价,'COMPETE'为对手价
# price: 价格,最新价模式下填0即可
# accId: 资金账号
buy_open(symbol, 1, 'LATEST', 0, ContextInfo, ContextInfo.accID)
print(f"【买入开仓】{symbol} 1手,最新价下单")
# ==============================================================================
# 场景 2: 卖出平仓 - 平今优先 (Close Long - Close Today First)
# ==============================================================================
# 含义:优先平掉今日新开的仓位。如果今日仓位不足,剩余部分会自动平掉昨日(历史)仓位。
# 适用场景:上期所等交易所平今手续费较贵或较便宜时,需要精确控制平仓顺序。
close_today_condition = False
if close_today_condition:
# sell_close_tdayfirst(stockcode, amount, style, price, ContextInfo, accId)
sell_close_tdayfirst(symbol, 1, 'LATEST', 0, ContextInfo, ContextInfo.accID)
print(f"【卖出平仓-平今优先】{symbol} 1手")
# ==============================================================================
# 场景 3: 卖出平仓 - 平昨优先 (Close Long - Close Yesterday First)
# ==============================================================================
# 含义:优先平掉昨日(历史)持仓。如果历史仓位不足,剩余部分会自动平掉今日仓位。
# 适用场景:持有隔夜单,想要优先了结老单子。
close_yesterday_condition = False
if close_yesterday_condition:
# sell_close_ydayfirst(stockcode, amount, style, price, ContextInfo, accId)
sell_close_ydayfirst(symbol, 1, 'LATEST', 0, ContextInfo, ContextInfo.accID)
print(f"【卖出平仓-平昨优先】{symbol} 1手")
代码详解
1. 函数说明
QMT 提供了以下专用函数来简化期货交易,这些函数底层调用的是 passorder,但使用起来更直观:
buy_open(...): 买入开仓。建立多头头寸。sell_close_tdayfirst(...): 卖出平仓(平今优先)。用于平掉多头头寸。系统会检查持仓,优先平掉当天的开仓单。sell_close_ydayfirst(...): 卖出平仓(平昨优先)。用于平掉多头头寸。系统会优先平掉历史持仓(昨仓)。
2. 参数说明
这些函数通常接受以下参数:
stockcode: 合约代码(如'IF2306.IF')。amount: 交易数量(手数)。style: 报价方式。'LATEST': 最新价。'COMPETE': 对手价。'FIX': 指定限价(需配合price参数)。
price: 价格。如果是'LATEST'或'COMPETE',此参数填0或-1均可;如果是'FIX',则填具体价格。ContextInfo: 必须传入全局上下文对象。accId: 资金账号字符串。
3. 补充:做空方向
如果您需要做空(卖出开仓)和买入平仓,对应的函数如下:
- 卖出开仓:
sell_open(...) - 买入平仓(平今优先):
buy_close_tdayfirst(...) - 买入平仓(平昨优先):
buy_close_ydayfirst(...)
Q&A
Q: 为什么要区分平今和平昨?
A: 在中国期货市场(特别是上期所 SHFE),某些品种的“平今仓”手续费可能非常高(或者是免费),而“平昨仓”的手续费标准不同。策略需要根据交易所的费率规则选择优先平哪一部分仓位,以降低交易成本。
Q: 如果我使用 passorder 函数能实现吗?
A: 可以。passorder 是更底层的函数。
opType=0: 开多 (买入开仓)opType=6: 平多, 优先平今opType=7: 平多, 优先平昨
使用封装好的buy_open等函数通常代码可读性更好。
Q: 回测模式下这些函数有效吗?
A: 有效。在回测模式下,QMT 会根据历史行情模拟撮合。但在回测中,“平今”和“平昨”的区别主要体现在手续费计算上(如果设置了详细费率),逻辑上都是减少持仓。