问题描述
解决方案
这是一个基于 QMT Python API 编写的自动申购新股和新债的策略脚本。
策略设计思路
- 获取数据:使用
get_ipo_data()函数分别获取当天的新股(STOCK)和新债(BOND)信息。 - 获取额度:使用
get_new_purchase_limit()获取当前账户的新股申购额度(市值配售额度)。 - 计算数量:
- 新股:取“单账户申购上限”与“账户持有市值对应的可申购额度”两者的较小值。
- 新债:通常顶格申购(一般为 10,000 张或 1,000 手,具体视券商风控而定,脚本中默认按最大允许数量申购)。
- 执行下单:使用
passorder函数进行委托。 - 运行控制:通过全局变量控制每天只运行一次,避免重复下单。
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}")
代码关键点解析
-
# -*- coding: gbk -*-:- 必须放在第一行。QMT 的 Python 环境默认编码通常是 GBK,加上这行可以防止中文注释乱码。
-
get_ipo_data(type):- 这是 QMT 专用的获取新股新债数据的接口。
type="STOCK"返回新股数据。type="BOND"返回新债(可转债)数据。- 返回的数据是一个字典,包含代码、名称、发行价 (
price)、最大申购数量 (maxPurchaseNum) 等信息。
-
get_new_purchase_limit(accid):- 获取账户的市值配售额度。虽然代码中调用了它用于打印日志,但在实际下单逻辑中,为了简化代码并确保尽可能多买,脚本逻辑倾向于使用
maxPurchaseNum(新股本身的申购上限)进行委托。 - 注意:如果您的委托数量超过了账户的市值额度,柜台系统通常会自动拒绝该笔委托或按实际可用额度确认,这取决于券商柜台的实现。
- 获取账户的市值配售额度。虽然代码中调用了它用于打印日志,但在实际下单逻辑中,为了简化代码并确保尽可能多买,脚本逻辑倾向于使用
-
passorder函数:opType=23:代表股票买入(申购新股/债在 QMT 中通常视为买入操作)。orderType=1101:代表单账号、按股数/张数下单。prType=11:代表指定价格(即发行价)。
-
防重复机制:
- 使用
ContextInfo.has_ordered变量。脚本在handlebar中每根 K 线(或 Tick)都会被触发,因此必须加锁,确保每天只执行一次申购操作。
- 使用
使用步骤
- 打开 QMT 软件,进入【模型研究】或【策略编辑器】。
- 新建一个 Python 策略。
- 将上述代码粘贴进去。
- 修改账号:将
ContextInfo.acc_id = 'YOUR_ACCOUNT_ID'修改为您实际的资金账号。 - 运行设置:
- 将策略加载到任意一个主图上(建议选择指数,如 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 的实盘或模拟交易模式下运行,并且账号已正确登录。回测模式下部分交易函数可能表现不同或无效。