🚀 AI 一键生成 qmt 策略代码

使用 get_enable_short_contract 查询信用账户可融券数量

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

问题描述

如何在融券卖出前检查有没有券?

解决方案

在 QMT 中,要在融券卖出前检查是否有券(即查询融券卖出的最大可下单量),需要使用 query_credit_opvolume 函数配合回调函数 credit_opvolume_callback 来实现。

这是一个异步操作:你发送查询请求,服务器处理后,通过回调函数将结果推送回来。

核心步骤

  1. 发起查询:在 handlebar 或其他逻辑中调用 query_credit_opvolume
    • opType 参数需设置为 28(代表融券卖出)。
  2. 接收结果:在策略中定义 credit_opvolume_callback 函数,系统会自动调用该函数并传入查询结果。
    • 如果返回的 result 大于 0,说明有券且账户资金充足,可以下单。

策略代码示例

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

def init(ContextInfo):
    # 1. 设置您的信用资金账号
    # 请将 '您的信用账号ID' 替换为实际的账号
    ContextInfo.accid = '6000000248' 
    ContextInfo.set_account(ContextInfo.accid)
    
    # 定义一个全局变量用于控制查询频率,避免每个tick都查
    ContextInfo.last_query_time = 0

def handlebar(ContextInfo):
    # 仅在最后一根K线(实时行情)运行
    if not ContextInfo.is_last_bar():
        return

    # 示例:每隔10秒查询一次 600000.SH 的融券可用量
    if time.time() - ContextInfo.last_query_time > 10:
        stock_code = '600000.SH'
        
        # 获取当前最新价作为参考价格
        # 注意:get_market_data_ex 返回的是字典,需解析
        last_data = ContextInfo.get_market_data_ex(['close'], [stock_code], period='1d', count=1)
        if stock_code in last_data and not last_data[stock_code].empty:
            current_price = last_data[stock_code].iloc[-1]['close']
        else:
            current_price = 10.0 # 获取失败时的默认值,实际使用请做好容错
            
        # --- 核心查询逻辑 ---
        # opType = 28 : 融券卖出
        # prType = 11 : 限价 (也可以用 5 最新价等,需与下单类型一致)
        # seq : 序列号,建议使用时间戳或唯一ID,以便在回调中区分是哪次查询
        seq = int(time.time())
        
        print(f"[{time.strftime('%H:%M:%S')}] 发起查询: {stock_code} 价格:{current_price} 融券可卖量...")
        
        # 调用异步查询接口
        query_credit_opvolume(ContextInfo.accid, stock_code, 28, 11, current_price, seq, ContextInfo)
        
        ContextInfo.last_query_time = time.time()

def credit_opvolume_callback(ContextInfo, accid, seq, ret, result):
    """
    查询两融最大可下单量的回调函数
    系统会自动调用此函数返回 query_credit_opvolume 的结果
    """
    # ret: 查询结果状态。1:正常返回, -1:正在查询中, <0: 报错
    if ret == 1:
        print(f"==> 回调收到 (seq={seq}): 账号 {accid} 融券卖出最大可下单量为: {result}")
        
        if result > 0:
            print("    -> 状态:有券可融。")
            # 在此处可以添加下单逻辑,例如:
            # passorder(28, 1101, accid, '600000.SH', 11, price, 100, ContextInfo)
        else:
            print("    -> 状态:无券 或 保证金不足 或 价格超出涨跌停限制。")
            
    elif ret == -1:
        print(f"==> 回调收到 (seq={seq}): 查询正在进行中...")
    else:
        print(f"==> 回调收到 (seq={seq}): 查询出错,错误代码: {ret}")

关键参数说明

  1. query_credit_opvolume 参数详解:

    • accountId: 信用资金账号。
    • stockCode: 股票代码(如 '600000.SH')。
    • opType: 28。这是融券卖出的操作代码。
    • prType: 报价类型。通常填 11 (限价) 或 5 (最新价)。这会影响系统计算最大可买量时的资金预估。
    • price: 委托价格。如果是限价单,填具体的数值;如果是市价单,此值可能被忽略,但建议填入当前价以获得准确估算。
    • seq: 查询序列号(整数)。用于在回调函数中对应是哪一次查询。
  2. 注意事项:

    • 频率限制: 该函数是从服务器/柜台查询数据,建议平均查询时间间隔 30秒 一次,不可在每个 tick 中频繁调用,否则可能导致查询阻塞或被柜台限制。
    • 结果含义: 返回的 result 是综合了券池余量账户可用保证金后的最大可下单数量。如果返回 0,可能是券池没券,也可能是账户没钱(保证金),或者价格不在涨跌停范围内。
    • 异步特性: 代码执行完 query_credit_opvolume 后不会立即得到结果,必须在 credit_opvolume_callback 中处理后续逻辑(如下单)。

Q&A

Q: get_enable_short_contract 这个函数有什么用?
A: get_enable_short_contract(accId) 用于获取信用账户当前可融券的标的明细列表。它返回的是一个列表,告诉你哪些股票允许融券(即在标的池内),但它通常不包含具体的“当前可用数量”。如果你只是想筛选出哪些股票是融券标的,可以用这个函数;如果你需要知道具体能卖多少股(有没有券源),必须用 query_credit_opvolume

Q: 为什么我查询到的结果是 0,但我看软件上显示有券?
A: query_credit_opvolume 返回的是最大可下单量

  1. 检查您的信用账户是否有足够的可用保证金。如果没钱,即使有券,可下单量也是 0。
  2. 检查传入的 price 是否在当日涨跌停范围内。
  3. 检查 opType 是否填对(28 为融券卖出)。

Q: 回测模式下这个函数有效吗?
A: 在回测模式下,QMT 通常不连接真实的柜台券池,因此该函数可能无法返回真实的券源数据,或者返回模拟的无限量/固定量。该功能主要用于实盘交易中规避废单。