🚀 AI 一键生成 qmt 策略代码

如何用 QMT 策略实现每日自动打新股和新债?

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

问题描述

如何编写一个能自动申购当天所有新股和新债的脚本?

解决方案

这是一个基于 QMT Python API 编写的自动申购新股和新债的策略脚本。

策略设计思路

  1. 获取数据:使用 get_ipo_data() 函数分别获取当天的新股(STOCK)和新债(BOND)信息。
  2. 获取额度:使用 get_new_purchase_limit() 获取当前账户的新股申购额度(市值配售额度)。
  3. 计算数量
    • 新股:取“单账户申购上限”与“账户持有市值对应的可申购额度”两者的较小值。
    • 新债:通常顶格申购(一般为 10,000 张或 1,000 手,具体视券商风控而定,脚本中默认按最大允许数量申购)。
  4. 执行下单:使用 passorder 函数进行委托。
  5. 运行控制:通过全局变量控制每天只运行一次,避免重复下单。

QMT 自动申购脚本

请将以下代码复制到 QMT 的策略编辑器中。

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

def init(ContextInfo):
    # ================= 配置区域 =================
    # 请在此处填写您的资金账号
    ContextInfo.acc_id = 'YOUR_ACCOUNT_ID' 
    # 账号类型:'STOCK' (股票), 'CREDIT' (信用)
    ContextInfo.acc_type = 'STOCK'
    # ===========================================

    # 设置账号
    ContextInfo.set_account(ContextInfo.acc_id)
    
    # 定义全局变量,用于控制当天是否已经申购过
    ContextInfo.has_ordered = False
    
    print("策略初始化完成,等待行情驱动...")

def handlebar(ContextInfo):
    # 1. 仅在最后一根K线(实时行情)运行,跳过历史回测阶段
    if not ContextInfo.is_last_bar():
        return

    # 2. 控制每天只运行一次
    # 如果需要盘中多次尝试(防止早上未开盘失败),可以结合时间判断,例如每隔1小时尝试一次
    if ContextInfo.has_ordered:
        return

    # 3. 检查交易时间 (通常申购时间为 9:30 - 15:00)
    current_time = time.strftime("%H%M%S", time.localtime())
    if not ("093000" <= current_time <= "150000"):
        # 非交易时间不执行,但也不置为True,以便交易时间到了再执行
        return

    print(f"开始执行自动申购任务,当前时间: {current_time}")
    
    # 执行申购逻辑
    subscribe_ipo_stocks(ContextInfo)
    subscribe_convertible_bonds(ContextInfo)

    # 标记为已执行
    ContextInfo.has_ordered = True
    print("当日申购任务执行完毕。")

def subscribe_ipo_stocks(ContextInfo):
    """
    申购新股逻辑
    """
    try:
        # 获取当日新股信息
        ipo_stocks = get_ipo_data("STOCK")
        if not ipo_stocks:
            print("今日无新股可申购。")
            return

        # 获取账户申购额度
        # 返回格式示例: {'上海主板': 10000, '深圳市场': 5000, ...}
        limits = get_new_purchase_limit(ContextInfo.acc_id)
        print(f"当前账户新股额度: {limits}")

        for code, info in ipo_stocks.items():
            name = info.get('name', code)
            price = info.get('price', 0.0)
            # 证券最大申购数量
            max_purchase_num = info.get('maxPurchaseNum', 0)
            
            # 简单的额度匹配逻辑 (注意:实际市场分类可能需要更复杂的映射)
            # 这里采用尝试顶格申购策略,如果额度不足,柜台通常会自动废单或按最大额度成交
            # 但为了严谨,建议取 min(额度, 上限)
            
            # 确定申购数量:这里默认尝试按新股允许的上限申购
            # 实际交易中,如果超过账户额度,passorder 可能会报错或由柜台拒单
            volume = max_purchase_num
            
            print(f"正在申购新股: {code} ({name}), 价格: {price}, 数量: {volume}")
            
            # 下单
            # opType=23 (买入/申购), orderType=1101 (单股单账号普通股数下单)
            # prType=11 (指定价/模型价), price=发行价
            passorder(23, 1101, ContextInfo.acc_id, code, 11, price, volume, ContextInfo)
            
    except Exception as e:
        print(f"申购新股时发生错误: {e}")

def subscribe_convertible_bonds(ContextInfo):
    """
    申购新债逻辑
    """
    try:
        # 获取当日新债信息
        ipo_bonds = get_ipo_data("BOND")
        if not ipo_bonds:
            print("今日无新债可申购。")
            return

        for code, info in ipo_bonds.items():
            name = info.get('name', code)
            price = info.get('price', 100.0) # 可转债一般面值100
            # 可转债通常顶格申购为 10000 张 (1000手) 或者 1000000 元
            # maxPurchaseNum 单位通常是“张”或“手”,需根据券商接口实际返回确认
            # 大部分情况 QMT 返回的是数量,建议直接使用返回的 maxPurchaseNum
            volume = info.get('maxPurchaseNum', 10000) 
            
            print(f"正在申购新债: {code} ({name}), 价格: {price}, 数量: {volume}")
            
            # 下单
            passorder(23, 1101, ContextInfo.acc_id, code, 11, price, volume, ContextInfo)
            
    except Exception as e:
        print(f"申购新债时发生错误: {e}")

代码关键点解析

  1. # -*- coding: gbk -*-

    • 必须放在第一行。QMT 的 Python 环境默认编码通常是 GBK,加上这行可以防止中文注释乱码。
  2. get_ipo_data(type)

    • 这是 QMT 专用的获取新股新债数据的接口。
    • type="STOCK" 返回新股数据。
    • type="BOND" 返回新债(可转债)数据。
    • 返回的数据是一个字典,包含代码、名称、发行价 (price)、最大申购数量 (maxPurchaseNum) 等信息。
  3. get_new_purchase_limit(accid)

    • 获取账户的市值配售额度。虽然代码中调用了它用于打印日志,但在实际下单逻辑中,为了简化代码并确保尽可能多买,脚本逻辑倾向于使用 maxPurchaseNum(新股本身的申购上限)进行委托。
    • 注意:如果您的委托数量超过了账户的市值额度,柜台系统通常会自动拒绝该笔委托或按实际可用额度确认,这取决于券商柜台的实现。
  4. passorder 函数

    • opType=23:代表股票买入(申购新股/债在 QMT 中通常视为买入操作)。
    • orderType=1101:代表单账号、按股数/张数下单。
    • prType=11:代表指定价格(即发行价)。
  5. 防重复机制

    • 使用 ContextInfo.has_ordered 变量。脚本在 handlebar 中每根 K 线(或 Tick)都会被触发,因此必须加锁,确保每天只执行一次申购操作。

使用步骤

  1. 打开 QMT 软件,进入【模型研究】或【策略编辑器】。
  2. 新建一个 Python 策略。
  3. 将上述代码粘贴进去。
  4. 修改账号:将 ContextInfo.acc_id = 'YOUR_ACCOUNT_ID' 修改为您实际的资金账号。
  5. 运行设置
    • 将策略加载到任意一个主图上(建议选择指数,如 000001.SH)。
    • 周期选择“1天”或“1分钟”均可(推荐 1 分钟,以便盘中启动时能尽快触发)。
    • 点击【运行】。

常见问题 Q&A

Q: 这个脚本需要一直开着吗?
A: 是的,需要在交易时间段内保持 QMT 软件和策略运行。策略会在检测到是交易时间且尚未申购时自动下单。

Q: 为什么申购数量直接用了 maxPurchaseNum
A: 新股申购通常建议“顶格申购”。如果您的市值额度不足以支撑顶格申购,交易柜台会根据您的实际额度自动调整或废单。如果希望代码严格计算额度,需要解析 get_new_purchase_limit 返回的中文 Key(如"上海主板")并映射到具体的股票代码后缀(如 .SH),逻辑会相对复杂,上述脚本采用的是最通用的“尝试顶格”策略。

Q: 怎么确认申购成功了?
A: 脚本运行后,请查看 QMT 下方的【交易】->【委托】面板。如果看到新股/新债的委托记录,且状态为“已报”或“已成”(申购通常显示已报,晚上清算后才确认配号),即表示成功。

Q: 报错 name 'passorder' is not defined 怎么办?
A: 请确保您是在 QMT 的实盘模拟交易模式下运行,并且账号已正确登录。回测模式下部分交易函数可能表现不同或无效。