🚀 AI 一键生成 qmt 策略代码

如何在 QMT 中实现自动化卖券还款和买券还券操作?

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

问题描述

如何写一个脚本,在我卖出信用账户的股票后,自动用获得的资金去归还融资负债?

解决方案

这是一个非常实用的需求。在 QMT 中,实现“卖出股票后自动还款”主要有两种思路:

  1. 直接使用“卖券还款”指令(推荐):在卖出时直接使用 opType=31(卖券还款),这样卖出的资金会直接用于归还负债,无需分两步操作,这是最合规且效率最高的方式。
  2. 分步操作(卖出 -> 收到成交回报 -> 发起直接还款):如果你必须使用普通卖出(例如为了配合某些算法交易),然后想用脚本自动把钱还进去,则需要利用 deal_callback(成交回报)函数。

下面我将为你提供 第二种思路(分步操作) 的完整代码实现。这个脚本会监听你的信用账户,一旦检测到“卖出”成交,就会立即发起一笔“直接还款”的委托。

策略逻辑说明

  1. init 初始化:设置信用账户 ID 并绑定回调。
  2. deal_callback 成交回报:这是核心。当有一笔交易成交时,系统会自动调用此函数。
    • 判断成交是否属于当前设置的信用账户。
    • 判断交易方向是否为“卖出”(m_nDirection == 49)。
    • 获取成交金额(m_dTradeAmount)。
    • 执行还款:调用 passorder 函数,使用 opType=32(直接还款),金额为刚才卖出的成交额。

QMT 策略代码

# -*- coding: gbk -*-
import time

def init(ContextInfo):
    # ================= 配置区域 =================
    # 请在此处替换您的信用资金账号
    ContextInfo.credit_account = '88000001' 
    # ===========================================

    # 设置交易账号,必须在init中设置才能接收主推回调
    ContextInfo.set_account(ContextInfo.credit_account)
    
    print(f"策略已启动,正在监听账号 {ContextInfo.credit_account} 的卖出成交...")

def handlebar(ContextInfo):
    # 本策略主要依赖事件驱动(callback),handlebar中无需写逻辑
    pass

def deal_callback(ContextInfo, dealInfo):
    """
    成交回报回调函数
    当有成交发生时,系统自动调用此函数
    """
    # 1. 安全检查:确保成交的账号是我们要操作的信用账号
    if dealInfo.m_strAccountID != ContextInfo.credit_account:
        return

    # 2. 判断交易方向
    # m_nDirection: 48=买入, 49=卖出
    # 我们只关心“卖出”操作产生的资金
    if dealInfo.m_nDirection == 49:
        
        stock_code = dealInfo.m_strInstrumentID
        trade_amount = dealInfo.m_dTradeAmount # 成交金额(元)
        
        print(f"检测到卖出成交: {stock_code}, 成交金额: {trade_amount:.2f}")
        
        # 3. 执行直接还款逻辑
        # opType = 32: 直接还款
        # orderType = 1102: 单股、单账号、普通、金额(元)方式下单
        # 注意:由于卖出包含手续费和印花税,实际到账金额会略少于 trade_amount。
        # 如果账户内没有额外可用资金,全额还款可能会因资金不足失败。
        # 建议保留一点缓冲,或者确保账户有少量留存资金。
        
        # 这里演示尝试归还全部成交金额
        repay_amount = trade_amount
        
        print(f"正在发起直接还款: {stock_code}, 金额: {repay_amount:.2f}")
        
        passorder(
            32,                         # opType: 32 代表直接还款
            1102,                       # orderType: 1102 代表按金额(元)下单
            ContextInfo.credit_account, # 账号
            stock_code,                 # 代码 (通常填对应的标的代码)
            5,                          # prType: 5 代表最新价 (还款时价格参数通常不敏感,但需符合格式)
            -1,                         # price: 价格忽略
            repay_amount,               # volume: 还款金额
            ContextInfo                 # 上下文对象
        )

def order_callback(ContextInfo, orderInfo):
    # 委托回报(可选),用于调试查看还款委托是否发出
    pass

代码关键点解析

  1. passorder 参数详解 (针对还款)

    • opType=32:这是 QMT 中“直接还款”的操作码。它告诉柜台你要用现金归还负债。
    • orderType=1102:这一点非常重要。普通的股票买卖通常按“股数”下单(1101),但还款通常是按“金额”进行的。1102 表示 volume 参数的单位是“元”。
    • volume=repay_amount:传入刚才卖出获得的金额。
  2. 关于手续费的提示

    • dealInfo.m_dTradeAmount 返回的是成交金额(价格 × 数量)。
    • 实际回到你账户的资金 = 成交金额 - 佣金 - 印花税 - 过户费。
    • 风险点:如果你账户里原本余额为 0,直接用 trade_amount 去还款,可能会因为资金不足(差了手续费那部分)而导致还款委托废单。
    • 建议:在实际使用中,建议将 repay_amount 乘以一个系数(如 0.99),或者确保账户里本身留有一部分现金作为缓冲。

如何运行

  1. 打开 QMT 客户端,进入【模型研究】->【策略编辑器】。
  2. 新建一个 Python 策略,将上述代码粘贴进去。
  3. 修改账号:将 ContextInfo.credit_account = '88000001' 中的号码改为你实际的信用资金账号。
  4. 点击【运行】(注意:必须是实盘模式,且需要在交易设置中勾选“模型交易”相关权限)。
  5. 之后你在交易界面手动卖出股票,或者其他策略卖出股票时,该脚本都会自动触发还款。

常见问题 Q&A

Q: 为什么不直接用“卖券还款” (opType 31)?
A: 如果你是手动下单或写下单策略,直接用 opType=31 是最好的。但有些场景下(例如使用条件单、网格交易等第三方工具),它们可能只发出了普通卖出指令。这个脚本就是为了给这些普通卖出指令做“善后”工作的。

Q: 脚本报错“资金不足”怎么办?
A: 如代码解析中所述,这是因为卖出成交额包含了手续费。你可以将代码中的 repay_amount = trade_amount 改为 repay_amount = trade_amount * 0.995 (预留 0.5% 扣除费用),或者在账户里常备几百块钱现金。

Q: 这个脚本会重复还款吗?
A: deal_callback 是由成交推送触发的。如果一笔委托分成了 3 次成交(例如 1000 股分成了 300、300、400 成交),这个函数会被调用 3 次,每次分别归还对应部分的金额。这是正确的逻辑,不会导致重复还款。