QMT / PTrade 新股申购:两套接口怎么接
这是工程记录。只谈客户端怎么取当日标的、怎么下申购单。能不能申、额度多少、中不中签,以券商规则和合同为准。不构成投资建议,也不代操盘。
两套平台不是同一套函数。PTrade 有一键申购;QMT 要自己拉列表再 passorder。拷代码先换后缀:PTrade 上交所用 .SS,QMT 用 .SH。
PTrade:先看当日有没有
get_ipo_stocks() 只在股票交易模块、PTrade 客户端里有。对接部分通道会空。返回按市场分类:
def handle_data(context, data):
bags = get_ipo_stocks() or {}
log.info('上证普通 %s', bags.get('上证普通代码'))
log.info('上证科创 %s', bags.get('上证科创板代码'))
log.info('深证普通 %s', bags.get('深证普通代码'))
log.info('深证创业 %s', bags.get('深证创业板代码'))
log.info('可转债 %s', bags.get('可转债代码'))没有权限、非交易模块、或当天没有标的,就是空 dict。先 log 再决定要不要下单。
PTrade:一键申购
ipo_stocks_order() 按当日额度申购。submarket_type 不传就全市场;黑名单必须是申购代码(6 位或带后缀都可以)。
def initialize(context):
run_daily(context, ipo_job, time='10:30')
def ipo_job(context):
if not is_trade():
return
# 0上证普通 1科创 2深证普通 3创业板 4可转债
ret = ipo_stocks_order(submarket_type=None, black_stocks=None)
log.info('申购回报 %s', ret)回报一般是 {代码: {entrust_no, entrust_status, redemption_amount}}。entrust_status 为 1 只表示委托提交成功,不是中签。
分市场写、中间 sleep,是为了避免一次打太多单被柜台拒。是否拆开、黑名单填什么,按你自己的账户权限改,不要当成必须全买。
QMT:列表和额度
QMT 没有 PTrade 那种一键函数。常见是:
get_ipo_data('STOCK')当日新股get_ipo_data('BOND')当日新债get_new_purchase_limit(账号)沪深/科创额度
字段名不同版本可能叫 issuePrice / maxPurchaseNum,先把 dict 打出来再取。
#coding:gbk
import time
def init(C):
C.account = '你的资金账号' # 股票户或信用户
C.acct_type = 'STOCK' # CREDIT 用信用
C.done = False
def handlebar(C):
if not C.is_last_bar() or C.done:
return
hm = time.strftime('%H%M')
if hm < '1030':
return
C.done = True
try:
rows = get_ipo_data('STOCK') or {}
except NameError:
print('get_ipo_data 不可用,客户端版本过旧')
return
print('当日新股条数', len(rows))
try:
print('额度', get_new_purchase_limit(C.account))
except Exception as e:
print('额度接口', e)仿真、未开通申购、非交易日,经常是空表。先对接口,再谈定时。
QMT:passorder 怎么下申购
普通股票户常见 opType=23,信用户担保品常见 33。价格类型用限价(文档里 11),数量取接口给的上限和账户额度里较小的那个。quickTrade=2 表示调用到就发,不跟下一根 K 线走。
def submit_one(C, code, price, volume):
op = 33 if C.acct_type == 'CREDIT' else 23
if '.' not in code:
code = code + ('.SH' if code.startswith('7') else '.SZ')
remark = 'ipo_%s' % code.replace('.', '')
passorder(
op, 1101, C.account, code,
11, round(float(price), 2), int(volume),
'ipo_demo', 2, remark, C,
)
print('已提交', code, price, volume)从列表里取价和量时,不要写死数字:
def pick_price_vol(info):
if isinstance(info, dict):
price = info.get('issuePrice') or info.get('IssuePrice') or 0
vmax = info.get('maxPurchaseNum') or info.get('MaxPurchaseNum') or 0
vmin = info.get('minPurchaseNum') or info.get('MinPurchaseNum') or 0
else:
price = getattr(info, 'issuePrice', 0)
vmax = getattr(info, 'maxPurchaseNum', 0)
vmin = getattr(info, 'minPurchaseNum', 0)
return float(price or 0), int(vmax or 0), int(vmin or 0)北证、未开通创业板/科创权限、额度不够最小申购单位,提交会被拒。这些要打日志,不要假设每只都能过。
两边最容易踩的坑
- 后缀。PTrade
.SS,QMT.SH。申购代码本身也常是 7 开头的认购码,不是上市后的交易码。 - 账号类型。普通户和信用户 opType 不同。账号填错,列表有、单过不去。
- 只跑一次。用日期或
C.done卡住,避免每根 K 线重复申购。 - 回测几乎验证不了柜台。申购是交易通道能力,研究环境空表很常见。先仿真或实盘权限页看「新股申购」是否开通。
- PTrade 的
ipo_stocks_order在部分通道(文档写 jz_ufx)不可用。QMT 则取决于客户端版本是否带get_ipo_data。
最小对照
| 步骤 | PTrade | QMT |
|---|---|---|
| 看当日标的 | get_ipo_stocks() | get_ipo_data('STOCK'/'BOND') |
| 看额度 | 一键函数内部处理 | get_new_purchase_limit(账号) |
| 下单 | ipo_stocks_order(...) | passorder(23或33, 1101, ...) |
| 定时 | run_daily(..., time=...) | handlebar 里看时钟 + 只跑一次 |
| 托管 | 券商机房,本机关了还能跑 | 本机/自己的服务器,关机就停 |
需要开通接口或把这段嵌进现有策略,走 关注页 说明是开发落地。不代操盘。
完整讨论和附件在 知识星球 Kimi量化研究所。
