🚀 AI 一键生成 ptrade 策略代码

PTrade 订单管理:如何使用 cancel_order_ex 撤销账户当日全部挂单?

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

问题描述

如何撤销我交易账户里今天所有的未成交订单,不管是不是当前这个策略下的单?

解决方案

在PTrade中,若要撤销账户内所有未成交订单(包含手工下单、其他策略下的单以及当前策略的单),必须使用 get_all_orders() 配合 cancel_order_ex() 接口。

常规的 get_orders()cancel_order() 仅能操作当前策略实例产生的订单,无法触及账户级别的其他委托。

核心逻辑说明

  1. 获取所有订单:使用 get_all_orders() 获取当日账户的所有委托记录(返回的是字典列表)。
  2. 筛选未成交状态:遍历订单列表,检查 status 字段。通常需要撤销的状态为 '2' (已报/未成交) 和 '7' (部成/部分成交)。
  3. 执行撤单:对符合条件的订单调用 cancel_order_ex(order_dict)

策略代码实现

以下是一个完整的策略示例,它会在每次 handle_data 运行时检查并撤销账户内所有的活动委托。

def initialize(context):
    """
    初始化函数
    """
    # 设置股票池(示例),实际撤单逻辑不依赖具体的股票池
    g.security = ['600570.SS']
    set_universe(g.security)
    
    # 设定一个计数器或标志位,用于控制撤单频率(可选)
    g.counter = 0

def handle_data(context, data):
    """
    盘中运行函数
    """
    # 获取账户当日全部订单(包含非本策略产生的订单)
    # 不传参数则获取所有标的,传参数则获取指定标的
    all_orders = get_all_orders()
    
    if all_orders is None:
        return

    has_open_orders = False
    
    # 遍历所有订单
    for order_info in all_orders:
        # 获取订单状态
        # 状态码说明:
        # '2': 已报 (完全未成交,在撮合中)
        # '7': 部成 (部分成交,剩余部分在撮合中)
        # 注意:'1'(待报)通常是发往柜台途中,可能无法立即撤单,视柜台情况而定
        status = order_info['status']
        
        if status in ['2', '7']:
            has_open_orders = True
            entrust_no = order_info['entrust_no']
            symbol = order_info['symbol']
            
            log.info("发现未成交订单,准备撤单。代码: %s, 委托编号: %s, 状态: %s" % (symbol, entrust_no, status))
            
            # 使用 cancel_order_ex 进行撤单
            # 注意:这里传入的是 get_all_orders 返回的字典对象
            cancel_order_ex(order_info)
    
    if not has_open_orders:
        # 仅为了演示,避免日志过多
        if g.counter % 10 == 0: 
            log.info("当前账户没有可撤销的未成交订单。")
    
    g.counter += 1

关键注意事项

  1. 接口区别

    • cancel_order(order_id):仅用于撤销本策略生成的 Order 对象或 ID。
    • cancel_order_ex(order_dict):专门用于撤销由 get_all_orders() 返回的订单字典信息,适用于撤销外部订单(如手工单)。
  2. 状态判断

    • 代码中判断了 ['2', '7'],这是最标准的“挂单”状态。
    • 如果订单状态是 '0' (未报) 或 '1' (待报),通常意味着订单还没到达交易所确认,此时调用撤单可能会失败或被拒绝,建议只针对已确认的挂单进行撤销。
  3. 交易频率

    • 如果在 handle_data(分钟级或Tick级)中无条件调用此逻辑,可能会导致策略不断尝试撤单。建议根据实际需求(例如在特定时间点,或当某个风控条件触发时)再执行此逻辑。

Q&A

Q: get_all_orders() 返回的数据结构是什么样的?
A: 它返回一个列表,列表中每个元素是一个字典(dict),包含 symbol (代码), entrust_no (委托编号), status (状态), amount (数量) 等字段。这与 get_orders() 返回的对象列表不同。

Q: 为什么我调用 cancel_order_ex 后订单没有立即消失?
A: 撤单是一个异步过程。发送撤单指令后,交易所需要处理并返回确认。在下一个时间切片或收到 on_order_response 回调之前,get_all_orders() 可能仍然会返回该订单(状态可能变为 "已报待撤" 或 "部成待撤")。

Q: 这个代码能撤销融资融券的单子吗?
A: 可以。get_all_orders() 会返回账户内所有的委托,包括普通买卖和两融委托。只要状态符合未成交条件,cancel_order_ex 均可尝试撤销。