问题描述
解决方案
在 QMT 平台中,查询两融(信用)账号的最大可买数量不能简单地通过资金除以价格计算,因为涉及到保证金比例、授信额度等复杂因素。
QMT 提供了专门的异步查询函数 query_credit_opvolume 配合回调函数 credit_opvolume_callback 来实现这一功能。
核心步骤
- 发起查询:在
handlebar或其他逻辑中调用query_credit_opvolume发送查询请求。 - 接收结果:必须在策略代码中定义
credit_opvolume_callback函数,服务器返回数据后会自动触发该函数,结果包含在result参数中。
代码实现
以下是一个完整的策略示例,展示如何查询“融资买入”的最大可买数量。
# -*- coding: gbk -*-
import time
def init(ContextInfo):
# 1. 设置两融账号
# 请将此处替换为您实际的信用资金账号
ContextInfo.accid = '8800000000'
ContextInfo.set_account(ContextInfo.accid)
# 定义一个全局变量用于控制查询频率,避免频繁请求
ContextInfo.last_query_time = 0
print("策略初始化完成,账号已设置")
def handlebar(ContextInfo):
# 只在实时行情的最后一根K线运行,避免回测历史数据时重复触发
if not ContextInfo.is_last_bar():
return
# 限制查询频率,建议间隔30秒以上,避免被服务器拒绝
current_time = time.time()
if current_time - ContextInfo.last_query_time < 30:
return
ContextInfo.last_query_time = current_time
# 2. 准备查询参数
stock_code = '600000.SH' # 查询标的:浦发银行
# opType 操作类型:
# 27: 融资买入
# 33: 担保品买入 (使用自有资金买入)
# 28: 融券卖出
op_type = 27
# prType 报价类型 (同 passorder):
# 11: 限价 (通常计算最大可买需指定价格)
# 5: 最新价
pr_type = 11
# 委托价格 (如果是限价单,此价格影响最大可买数量)
# 这里简单取当前最新价
last_price = ContextInfo.get_market_data(['close'], stock_code=[stock_code], count=1, period='1d')
if last_price is None or len(last_price) == 0:
return
price = last_price['close'][0]
# 生成唯一序列号,用于在回调中区分是哪次查询
seq = int(current_time)
print(f"发起查询: 股票={stock_code}, 价格={price}, 操作类型={op_type}, 序列号={seq}")
# 3. 调用异步查询函数
# query_credit_opvolume(accountId, stockCode, opType, prType, price, seq, ContextInfo)
query_credit_opvolume(ContextInfo.accid, stock_code, op_type, pr_type, price, seq, ContextInfo)
# 4. 定义回调函数接收结果
def credit_opvolume_callback(ContextInfo, accid, seq, ret, result):
"""
查询两融最大可下单量的回调函数
:param accid: 查询的账号
:param seq: 发起查询时传入的序列号
:param ret: 查询状态 (1: 正常返回, -1: 查询中, -2: 账号非法, -3: 参数非法, -4: 服务器报错)
:param result: 查询到的最大可买数量 (如果ret!=1,这里可能是错误信息)
"""
if ret == 1:
print("=" * 30)
print(f"【查询成功】")
print(f"账号: {accid}")
print(f"序列号: {seq}")
print(f"最大可买数量: {result}")
print("=" * 30)
else:
print(f"【查询异常】序列号: {seq}, 状态码: {ret}, 信息: {result}")
关键参数说明
1. query_credit_opvolume (发起查询)
- accountId: 信用资金账号。
- stockCode: 股票代码(支持单个字符串或 List 列表)。
- opType: 交易类型,常用值如下:
27: 融资买入(借钱买股)33: 担保品买入(用自有资金买股)28: 融券卖出
- prType: 报价类型,通常填
11(限价) 或5(最新价)。 - price: 委托价格。对于限价单,价格越低,理论可买数量越多。
- seq: 序列号(整数)。建议使用时间戳或自增ID,以便在回调函数中对应请求。
2. credit_opvolume_callback (接收结果)
- ret: 状态码。只有当
ret == 1时,result才是有效的数量。 - result: 返回的最大可下单数量(股数)。
注意事项
- 异步机制:该函数不是立即返回结果的。代码执行完
query_credit_opvolume后会继续往下执行,直到服务器返回数据,才会跳转到credit_opvolume_callback中执行。 - 调用频率:文档建议平均查询时间间隔 30秒 一次,不可频繁调用,否则可能导致查询失败或被服务器限流。
- 并发限制:同时只能有一个查询在进行中。如果前一个查询未返回,新的查询可能会提前返回或覆盖。
- 批量查询:
stockCode参数支持传入列表(List),例如['600000.SH', '000001.SZ'],此时price也必须是对应长度的价格列表。
Q&A
Q: 为什么我调用了函数但是没有打印结果?
A: 请检查两点:1. 是否在策略中正确定义了 credit_opvolume_callback 函数(拼写必须完全一致)。2. 策略是否处于“实盘”或“模拟交易”模式,回测模式下该函数通常无效或无意义。
Q: opType 填 23 (普通买入) 可以吗?
A: 不可以。query_credit_opvolume 是专门针对信用账户(两融)的接口。信用账户的买入分为“担保品买入”(33)和“融资买入”(27)。普通股票账户的买入才用 23,且普通账户通常直接用可用资金除以价格计算即可,不需要调用此接口。
Q: 返回的数量是“手”还是“股”?
A: 返回的 result 通常是 股数。下单时请注意是否需要取整为 100 的倍数。