🚀 AI 一键生成 joinquant 策略代码

JoinQuant 教程:深入理解 OrderStatus 订单状态生命周期

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

问题描述

请解释一下订单的各种状态(如 new, open, filled, canceled)分别代表什么意思,以及它们之间是如何转换的?

解决方案

在聚宽(JoinQuant)的交易系统中,订单状态(OrderStatus)用于描述一个订单从创建到最终结束的生命周期。理解这些状态对于编写稳健的交易策略至关重要,特别是在处理未完成订单和撤单逻辑时。

以下是各个状态的详细解释及其转换逻辑:

1. 订单状态详解

聚宽的 OrderStatus 是一个枚举类型(Enum),主要包含以下几种状态:

new (8): 新创建未委托

  • 含义:订单已经创建,但尚未报送至交易所或撮合引擎。
  • 常见场景:通常出现在盘前(如 9:00 - 9:30 之间)或非交易时间下的单。
  • 特点:此时订单尚未生效,等待开盘后进入撮合系统。

open (0): 已委托,无成交

  • 含义:订单已成功提交并被交易所/撮合引擎接收,正在排队等待成交,但目前成交数量为 0
  • 常见场景:开盘后下的限价单,价格尚未达到对手价;或市价单刚下单的一瞬间。
  • 特点:订单处于“未完成”状态,可以被撤销(Cancel)。

filled (1): 部分成交

  • 含义:订单已经成交了一部分数量,但仍有剩余数量未成交。
  • 注意:在聚宽的定义中,filled 状态表示订单尚未结束,仍在等待剩余部分成交。
  • 特点:订单处于“未完成”状态,可以撤销剩余未成交的部分。

held (4): 全部成交

  • 含义:订单的委托数量已经全部成交。
  • 特点:订单处于“完成”状态,生命周期结束,不可撤销。
  • 注意:很多用户容易将 filled 误认为是全部成交,但在聚宽中 held 才是全部成交。

canceled (2): 已撤销

  • 含义:订单被用户手动撤销,或者因为收盘(每日 15:00 后)系统自动撤销了未完成的订单。
  • 特点:订单处于“完成”状态。
  • 注意:撤销的订单可能在撤销前已经有“部分成交”,需要查看 Order.filled 属性确认实际成交量。

rejected (3): 废单/已拒绝

  • 含义:订单被交易所或柜台拒绝。
  • 常见场景:资金不足、持仓不足(卖出时)、标的停牌、价格超过涨跌停板、科创板未设置保护价等。
  • 特点:订单处于“完成”状态,交易失败。

2. 订单状态转换流程

订单状态的流转通常遵循以下逻辑:

正常交易流程

  1. 下单
    • 如果在非交易时间(如 9:15)下单 $\rightarrow$ 状态为 new
    • 9:30 开盘后,new $\rightarrow$ open
    • 如果在交易时间直接下单 $\rightarrow$ 直接为 open
  2. 撮合
    • 如果撮合成功且一次性全部买入 $\rightarrow$ held(结束)。
    • 如果只买入了一部分 $\rightarrow$ filled
    • 剩余部分继续成交直至全部买完 $\rightarrow$ held(结束)。

撤单流程

  1. 全额撤单
    • 状态为 newopen 时调用 cancel_order $\rightarrow$ canceled
  2. 部成部撤
    • 状态为 filled(部分成交)时调用 cancel_order $\rightarrow$ canceled
    • 注:此时订单状态虽为 canceled,但实际上已经买入了一部分股票。

废单流程

  1. 下单失败
    • 下单时校验不通过(如没钱、跌停板卖出) $\rightarrow$ rejected

3. 代码示例

在策略代码中,通常需要判断订单状态来决定是否撤单或追单。

# -*- coding: utf-8 -*-
from jqdata import *

def initialize(context):
    run_daily(check_orders, '14:50') # 每天收盘前检查

def check_orders(context):
    # 获取当前所有未完成的订单 (状态为 open, new, filled 的订单)
    open_orders = get_open_orders()
    
    for order_id, order_obj in open_orders.items():
        # 打印订单当前状态
        log.info("订单标的: %s, 状态: %s" % (order_obj.security, order_obj.status))
        
        # 判断状态示例
        if order_obj.status == OrderStatus.new:
            log.info("订单尚未报盘")
        elif order_obj.status == OrderStatus.open:
            log.info("订单已委托,暂无成交")
        elif order_obj.status == OrderStatus.filled:
            log.info("订单部分成交,已成交数量: %s" % order_obj.filled)
            
        # 示例:如果临近收盘还是部分成交或未成交,强制撤单
        cancel_order(order_obj)

Q&A

Q: 为什么我的订单状态一直是 new
A: 这通常是因为您在非交易时间(如盘前或午休)下单,或者在模拟交易中使用了分钟回测但时间未推进到下一分钟。订单会在进入正式交易时间片后转为 open

Q: canceled 的订单是否意味着完全没有买入?
A: 不一定。如果订单先处于 filled(部分成交)状态,然后被撤销,最终状态会变成 canceled。此时需要检查 order.filled 属性来确认实际成交了多少股。

Q: 如何判断一个订单是否彻底结束了?
A:order.statusheld(全部成交)、canceled(已撤销)或 rejected(已拒绝)时,该订单即为结束状态(Closed),不会再有后续变化。get_open_orders() 函数只会返回状态为 newopenfilled 的订单。