委托回报与状态管理

本章介绍 QMT 内置 Python 的委托回报机制和订单状态管理。

委托回报回调

order_callback

当委托状态发生变化时触发:

def order_callback(ContextInfo, order_info):
    """委托状态变化回调"""
    print(f'委托回报: {order_info.m_strStockCode}')
    print(f'  方向: {"买入" if order_info.m_nOrderType == 1 else "卖出"}')
    print(f'  数量: {order_info.m_nVolume}')
    print(f'  价格: {order_info.m_dPrice}')
    print(f'  状态: {order_info.m_nOrderStatus}')
    print(f'  委托号: {order_info.m_strOrderSysID}')

deal_callback

当委托成交时触发:

def deal_callback(ContextInfo, deal_info):
    """成交通知回调"""
    print(f'成交回报: {deal_info.m_strStockCode}')
    print(f'  方向: {"买入" if deal_info.m_nOrderType == 1 else "卖出"}')
    print(f'  成交数量: {deal_info.m_nVolume}')
    print(f'  成交价格: {deal_info.m_dPrice}')
    print(f'  成交编号: {deal_info.m_strTradeID}')

订单状态详解

状态流转

委托提交 → 已确认 → 部分成交 → 全部成交
                  → 已撤销
                  → 部分成交 + 部分撤销

状态码对照表

状态码 常量名 说明
50 ORDER_SUBMITTED 委托已提交
55 ORDER_CONFIRMED 委托已确认
56 ORDER_PARTIALLY_FILLED 部分成交
57 ORDER_FILLED 全部成交
58 ORDER_CANCELLED 已撤销
59 ORDER_PARTIALLY_CANCELLED 部分撤销

状态判断

def order_callback(ContextInfo, order_info):
    status = order_info.m_nOrderStatus
    
    if status == 57:
        print(f'订单全部成交: {order_info.m_strStockCode}')
        # 更新持仓记录
        update_position(ContextInfo, order_info)
    elif status == 56:
        print(f'订单部分成交: {order_info.m_strStockCode}')
        # 记录部分成交
        record_partial_fill(ContextInfo, order_info)
    elif status == 58:
        print(f'订单已撤销: {order_info.m_strStockCode}')
        # 清理未成交记录
        cleanup_pending_order(ContextInfo, order_info)

订单信息对象

order_info 字段

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型(1=买, 2=卖)
m_nVolume int 委托数量
m_dPrice float 委托价格
m_nOrderStatus int 委托状态
m_strOrderSysID str 委托编号
m_nTradedVolume int 已成交数量
m_dTradedAmount float 已成交金额

deal_info 字段

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型
m_nVolume int 成交数量
m_dPrice float 成交价格
m_strTradeID str 成交编号
m_strOrderSysID str 关联委托编号

订单管理策略

订单跟踪

def init(ContextInfo):
    # 订单跟踪字典
    ContextInfo.pending_orders = {}  # order_id -> order_info
    ContextInfo.filled_orders = []   # 已完成订单列表

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    # 检查超时未成交订单
    check_pending_orders(ContextInfo)

def order_callback(ContextInfo, order_info):
    order_id = order_info.m_strOrderSysID
    
    if order_info.m_nOrderStatus in [57, 58, 59]:
        # 订单结束(全部成交/已撤/部分撤)
        if order_id in ContextInfo.pending_orders:
            del ContextInfo.pending_orders[order_id]
        ContextInfo.filled_orders.append(order_info)
    else:
        # 更新订单状态
        ContextInfo.pending_orders[order_id] = order_info

def check_pending_orders(ContextInfo):
    """检查超时未成交订单"""
    from datetime import datetime, timedelta
    
    now = datetime.now()
    for order_id, order in list(ContextInfo.pending_orders.items()):
        # 超时 5 分钟未成交则撤单
        if hasattr(order, 'submit_time'):
            elapsed = now - order.submit_time
            if elapsed > timedelta(minutes=5):
                ContextInfo.cancel(order_id, ContextInfo)
                print(f'超时撤单: {order_id}')

防止重复下单

def safe_order(ContextInfo, stock, volume, price, order_type=1):
    """安全下单,防止重复"""
    # 检查是否已有该品种的未成交订单
    for order_id, order in ContextInfo.pending_orders.items():
        if order.m_strStockCode == stock:
            print(f'{stock} 已有未成交订单,跳过')
            return None
    
    # 下单
    order_id = ContextInfo.order_volume(
        stockcode=stock,
        volume=volume,
        priceType=11,
        price=price,
        orderType=order_type,
        ContextInfo=ContextInfo,
    )
    
    if order_id:
        ContextInfo.pending_orders[order_id] = {
            'm_strStockCode': stock,
            'submit_time': datetime.now(),
        }
    
    return order_id

错误处理

常见委托错误

def order_callback(ContextInfo, order_info):
    status = order_info.m_nOrderStatus
    
    if status == 50 and order_info.m_strErrorInfo:
        # 委托被拒绝
        print(f'委托被拒绝: {order_info.m_strErrorInfo}')
        handle_rejection(ContextInfo, order_info)

def handle_rejection(ContextInfo, order_info):
    """处理委托被拒绝"""
    error = order_info.m_strErrorInfo
    
    if '资金不足' in error:
        print('错误:资金不足,请减少委托数量')
    elif '权限' in error:
        print('错误:交易权限不足')
    elif '涨跌停' in error:
        print('错误:触及涨跌停限制')
    else:
        print(f'未知错误: {error}')
技巧

在模拟环境中充分测试委托回报处理逻辑,确保各种状态都能正确处理后再用于实盘。