🚀 AI 一键生成 ptrade 策略代码

PTrade API 教程:深入理解 Order 对象的 status 属性并应用于实战

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

问题描述

如何判断我的一个委托是已经全部成交,还是部分成交,或者是一个无效的废单?并根据不同状态执行后续操作。

解决方案

在PTrade中,判断委托状态的核心在于获取 Order对象,并检查其 status 属性。

核心步骤

  1. 获取订单对象:使用 get_order(order_id)get_orders() 获取订单信息。
  2. 检查 status 字段:根据数据字典中的定义判断状态。
    • '8':已成(全部成交)
    • '7':部成(部分成交,剩余部分仍在挂单中)
    • '9':废单(无效委托,通常因资金不足、价格超限或非交易时间导致)
    • '6':已撤(订单已取消)
    • '5':部撤(部分成交后,剩余部分已取消)

策略代码示例

以下是一个完整的策略示例。该策略在 initialize 中设置股票,在 handle_data 中下单,并在随后的运行中持续监控该订单的状态,根据不同状态打印日志或执行逻辑。

def initialize(context):
    # 设置要操作的股票,这里以恒生电子为例
    g.security = '600570.SS'
    set_universe(g.security)
    
    # 用于存储订单ID的全局变量
    g.order_id = None
    # 标记是否已经下过单
    g.has_ordered = False

def handle_data(context, data):
    # 1. 如果还没有下单,先执行下单操作
    if not g.has_ordered:
        # 下单买入100股,这里故意使用限价单以便观察状态(如果是市价单可能瞬间成交)
        # 注意:为了演示废单,你可以将价格设置得非常低(如1.0),或者数量设置超过资金上限
        current_price = data[g.security]['close']
        g.order_id = order(g.security, 100, limit_price=current_price)
        
        if g.order_id is not None:
            log.info("已下单,订单ID: %s" % g.order_id)
            g.has_ordered = True
        else:
            log.error("下单失败,未生成订单ID")
        return

    # 2. 如果已经下单,获取订单对象并检查状态
    if g.order_id:
        # get_order 返回的是一个列表,包含一个Order对象
        order_list = get_order(g.order_id)
        
        if order_list is not None and len(order_list) > 0:
            # 获取具体的订单对象
            my_order = order_list[0]
            status = my_order.status
            
            # --- 状态判断逻辑 ---
            
            # 情况一:全部成交
            if status == '8':
                log.info("【全部成交】订单 %s 已全部成交,成交数量: %s" % (g.order_id, my_order.filled))
                # 后续操作:例如更新策略状态,准备卖出等
                # g.order_id = None # 重置ID以便下一次逻辑使用
                
            # 情况二:部分成交
            elif status == '7':
                log.info("【部分成交】订单 %s 部分成交,已成交: %s,剩余: %s" % (
                    g.order_id, my_order.filled, my_order.amount - my_order.filled
                ))
                # 后续操作:可以选择继续等待,或者如果长时间未完全成交则撤单
                # cancel_order(g.order_id) 
                
            # 情况三:废单
            elif status == '9':
                log.error("【废单】订单 %s 是废单,请检查资金或价格限制。" % g.order_id)
                # 后续操作:重置状态,尝试重新下单或停止策略
                g.has_ordered = False 
                g.order_id = None
                
            # 情况四:已撤单 (包含 '6':已撤 和 '5':部撤)
            elif status in ['6', '5']:
                log.info("【已撤单】订单 %s 已撤销。" % g.order_id)
                
            # 情况五:已报/待报 (订单还在排队中)
            elif status in ['1', '2', '3', '4']:
                log.info("【挂单中】订单 %s 正在排队,状态码: %s" % (g.order_id, status))
                
            else:
                log.info("订单 %s 当前状态码: %s" % (g.order_id, status))

关键点说明

  1. get_order 返回值:请注意 get_order(order_id) 返回的是一个 list,所以代码中使用了 order_list[0] 来获取实际的 Order 对象。
  2. 实盘与回测的区别
    • 回测:状态更新是基于撮合逻辑的,通常在下一个 handle_data 周期或者同一周期的后续逻辑中可以看到状态变化。
    • 交易(实盘):状态更新依赖柜台回报。如果您需要极低延迟的状态监控(例如高频交易),建议使用 on_order_response 回调函数,它会在委托状态发生变化时立即被触发,比在 handle_data 中轮询更高效。

补充:使用 on_order_response (仅限交易模式)

如果您是在实盘交易中,推荐使用回调函数来处理状态变化:

def on_order_response(context, order_list):
    # order_list 是发生变化的委托单列表
    for order_dict in order_list:
        status = order_dict['status']
        order_id = order_dict['order_id']
        
        if status == '8':
            log.info("实盘主推:订单 %s 全部成交" % order_id)
        elif status == '9':
            log.error("实盘主推:订单 %s 废单,原因: %s" % (order_id, order_dict.get('error_info', '未知')))

Q&A

Q: 为什么我的订单状态一直是 "2" (已报)?
A: "2" 表示订单已经成功报送到交易所,正在排队等待成交。如果价格没有达到市场价,或者流动性不足,订单会一直保持这个状态直到成交或收盘自动撤单。

Q: 废单(状态9)常见的原因有哪些?
A: 常见原因包括:可用资金不足、可用持仓不足(卖出时)、价格超过涨跌停限制、不在交易时间段内、委托数量不符合最小单位(如不足100股)。

Q: 部分成交(状态7)后,剩余部分会自动撤销吗?
A: 不会。剩余部分会继续挂在市场上等待成交。如果您希望在部分成交后不再等待,需要手动调用 cancel_order() 函数撤销剩余部分。撤销成功后,状态会变为 '5' (部撤)。