🚀 AI 一键生成 qmt 策略代码
立即体验

如何在QMT中开发股指期货双向网格策略?(含动态止损与资金管理源码)

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

问题描述

QMT 期货网格策略开发:双向网格构建与动态资金风控
如何在QMT中针对股指期货开发一个带动态止损和资金管理功能的网格交易策略?

解决方案

QMT期货双向网格策略开发:双向网格构建与动态资金风控\n\n网格交易(Grid Trading)是一种利用价格震荡进行低买高卖的经典量化策略。在期货市场(如股指期货)中,由于自带杠杆且支持双向交易,构建一个双向网格策略并配合动态资金风控,可以有效捕捉震荡行情红利,同时规避单边突破带来的爆仓风险。\n\n本文将详细介绍如何在国信证券QMT平台上,利用Python API开发一个适用于股指期货的双向网格交易策略。\n\n---\n\n## 一、 核心设计思路\n\n1. 双向网格构建:以初始基准价为中心,向上布置多档“卖出开空”网格,向下布置多档“买入开多”网格。\n2. 动态资金管理:根据账户可用资金(m_dAvailable)动态计算每档网格的下单手数,避免盲目满仓。\n3. 动态风控(整体止损):实时监控账户总资产(m_dBalance),当最大回撤超过设定阈值,或总资产低于安全线时,触发一键平仓并暂停策略。\n\n---\n\n## 二、 关键 QMT API 接口\n\n* ContextInfo.set_account(account):设定交易账号,绑定主推。\n* get_trade_detail_data(account, type, datatype):获取账户资金(ACCOUNT)和持仓(POSITION)明细。\n* passorder(opType, orderType, accountid, orderCode, prType, price, volume, ContextInfo):发送期货委托指令。\n\n---\n\n## 三、 策略源码实现 (Python)\n\n请在QMT策略编辑器中新建Python策略,并粘贴以下代码:\n\npython\n#encoding:gbk\nimport numpy as np\n\ndef init(ContextInfo):\n # 1. 基础参数设置\n ContextInfo.account = '您的期货资金账号' # 请替换为真实的模拟或实盘期货账号\n ContextInfo.set_account(ContextInfo.account)\n ContextInfo.symbol = ContextInfo.stockcode + '.' + ContextInfo.market\n \n # 2. 网格参数\n ContextInfo.grid_step = 15.0 # 网格间距(点数)\n ContextInfo.grid_levels = 5 # 单侧网格层数\n ContextInfo.base_price = 0.0 # 基准价格(运行中动态更新)\n \n # 3. 资金与风控参数\n ContextInfo.risk_ratio = 0.1 # 单笔交易所占可用资金比例\n ContextInfo.max_drawdown_limit = 0.05 # 账户最大回撤止损阈值(5%)\n ContextInfo.init_balance = 0.0 # 初始资金\n ContextInfo.max_balance = 0.0 # 历史最高资金\n ContextInfo.is_stopped = False # 策略风控停止标志\n \n print('期货双向网格策略初始化完成!')\n\ndef handlebar(ContextInfo):\n if ContextInfo.is_stopped:\n return\n \n # 1. 获取最新行情\n full_tick = ContextInfo.get_full_tick([ContextInfo.symbol])\n if not full_tick or ContextInfo.symbol not in full_tick:\n return\n current_price = full_tick[ContextInfo.symbol]['lastPrice']\n \n # 2. 获取账户资金与持仓信息\n acct_info = get_trade_detail_data(ContextInfo.account, 'FUTURE', 'ACCOUNT')\n if not acct_info:\n return\n account_obj = acct_info[0]\n \n current_balance = account_obj.m_dBalance\n available_cash = account_obj.m_dAvailable\n \n # 初始化资金记录\n if ContextInfo.init_balance == 0.0:\n ContextInfo.init_balance = current_balance\n ContextInfo.max_balance = current_balance\n ContextInfo.base_price = current_price\n print(f'策略启动,基准价: {ContextInfo.base_price}, 初始资金: {ContextInfo.init_balance}')\n return\n \n # 3. 动态资金风控逻辑\n if current_balance > ContextInfo.max_balance:\n ContextInfo.max_balance = current_balance\n \n # 计算当前回撤\n drawdown = (ContextInfo.max_balance - current_balance) / ContextInfo.max_balance\n if drawdown >= ContextInfo.max_drawdown_limit:\n print(f'【风控触发】当前回撤 {drawdown*100:.2f}% 超过限制,执行一键平仓!')\n liquidate_all(ContextInfo)\n ContextInfo.is_stopped = True\n return\n \n # 4. 动态计算下单手数 (基于可用资金与合约乘数)\n detail = ContextInfo.get_instrumentdetail(ContextInfo.symbol)\n multiplier = detail.get('VolumeMultiple', 1.0)\n # 假设保证金比例为 15%\n margin_rate = 0.15\n single_margin_limit = available_cash * ContextInfo.risk_ratio\n order_volume = int(single_margin_limit / (current_price * multiplier * margin_rate))\n order_volume = max(1, order_volume) # 至少下单1手\n \n # 5. 网格交易逻辑\n pos_info = get_trade_detail_data(ContextInfo.account, 'FUTURE', 'POSITION')\n long_pos = 0\n short_pos = 0\n for pos in pos_info:\n if pos.m_strInstrumentID == ContextInfo.stockcode:\n # 区分多空持仓\n if pos.m_nDirection == 48: # 多头\n long_pos = pos.m_nVolume\n elif pos.m_nDirection == 49: # 空头\n short_pos = pos.m_nVolume\n \n # 计算当前价格偏离基准价的网格层数\n price_deviation = current_price - ContextInfo.base_price\n current_level = int(price_deviation / ContextInfo.grid_step)\n \n # 向上突破:开空或平多\n if current_level >= 1 and short_pos < ContextInfo.grid_levels:\n # 价格上涨,分批开空\n target_short = min(current_level, ContextInfo.grid_levels)\n if short_pos < target_short:\n diff = target_short - short_pos\n print(f'价格上涨至 {current_price},触发开空网格,下单 {diff * order_volume} 手')\n passorder(3, 1101, ContextInfo.account, ContextInfo.symbol, 5, -1, diff * order_volume, ContextInfo)\n ContextInfo.base_price = current_price # 更新基准价\n \n # 向下突破:开多或平空\n elif current_level <= -1 and long_pos < ContextInfo.grid_levels:\n # 价格下跌,分批开多\n target_long = min(abs(current_level), ContextInfo.grid_levels)\n if long_pos < target_long:\n diff = target_long - long_pos\n print(f'价格下跌至 {current_price},触发开多网格,下单 {diff * order_volume} 手')\n passorder(0, 1101, ContextInfo.account, ContextInfo.symbol, 5, -1, diff * order_volume, ContextInfo)\n ContextInfo.base_price = current_price # 更新基准价\n\ndef liquidate_all(ContextInfo):\n # 一键平仓函数\n pos_info = get_trade_detail_data(ContextInfo.account, 'FUTURE', 'POSITION')\n for pos in pos_info:\n if pos.m_strInstrumentID == ContextInfo.stockcode and pos.m_nVolume > 0:\n if pos.m_nDirection == 48: # 平多\n print(f'平多仓: {pos.m_nVolume}手')\n passorder(6, 1101, ContextInfo.account, ContextInfo.symbol, 5, -1, pos.m_nVolume, ContextInfo)\n elif pos.m_nDirection == 49: # 平空\n print(f'平空仓: {pos.m_nVolume}手')\n passorder(8, 1101, ContextInfo.account, ContextInfo.symbol, 5, -1, pos.m_nVolume, ContextInfo)\n\n\n---\n\n## 四、 策略要点解析\n\n1. 动态手数计算:策略通过 ContextInfo.get_instrumentdetail 获取合约乘数,结合当前可用资金和预设的 risk_ratio 动态计算下单手数。当账户资金增长时,下单手数自动放大;资金缩水时,手数自动缩小。\n2. 最大回撤风控:在 handlebar 中,策略会记录历史最高资产净值。一旦当前净值相比最高净值回撤达到 5%(max_drawdown_limit),将立即调用 liquidate_all 函数进行一键平仓,并停止策略运行,防止单边趋势行情导致网格爆仓。\n3. 基准价动态更新:每次网格触发交易后,基准价 ContextInfo.base_price 会更新为当前成交价,从而实现网格的动态平移,适应价格中枢的变化。