🚀 AI 一键生成 joinquant 策略代码

如何在 JoinQuant 策略中查询未成交订单并进行撤单操作?

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

问题描述

如何查询我的策略里还没有成交的订单,并且把它们取消掉?

解决方案

在 JoinQuant 聚宽平台中,查询未成交订单并将其取消的操作主要涉及两个 API 函数:get_open_orders()cancel_order()

以下是具体的实现步骤和代码示例。

核心逻辑说明

  1. 获取未完成订单:使用 get_open_orders() 函数。该函数返回一个字典(dict),其中 Key 是订单 ID,Value 是订单对象(Order Object)。
  2. 遍历并撤单:遍历字典中的所有订单对象,并将它们逐一传入 cancel_order() 函数进行撤销。

代码实现

你可以将这段逻辑放在 handle_data 中,或者更常见的是放在 after_trading_end(收盘后)或自定义的定时运行函数中,以确保清理当天的挂单。

以下是一个完整的策略代码示例,展示了如何在每天收盘后自动撤销所有未完成订单:

# -*- coding: utf-8 -*-

def initialize(context):
    # 设置基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 每天收盘后执行撤单逻辑
    # 注意:回测中未完成订单会在当日结算时自动撤销,但在模拟交易或实盘中,
    # 显式撤单是一个好的风控习惯,或者用于盘中策略逻辑控制。
    run_daily(cancel_all_open_orders, '14:55')

def handle_data(context, data):
    # 示例:每个单位时间随机下一个限价单(为了演示撤单)
    # 实际策略中请替换为你的交易逻辑
    current_price = data['000001.XSHE'].close
    # 下一个很难成交的限价单(买入价为当前价的90%)
    order('000001.XSHE', 100, style=LimitOrderStyle(current_price * 0.9))

def cancel_all_open_orders(context):
    """
    自定义函数:查询并撤销所有未完成订单
    """
    # 1. 获取当前所有未完成的订单
    # 返回的是一个dict,key为order_id,value为Order对象
    open_orders = get_open_orders()
    
    if len(open_orders) > 0:
        log.info("检测到 %d 个未完成订单,开始撤单..." % len(open_orders))
        
        # 2. 遍历字典的 values (即 Order 对象)
        for _order in open_orders.values():
            # 3. 执行撤单
            cancel_order(_order)
            log.info("已撤销订单, 标的: %s, 订单ID: %s" % (_order.security, _order.order_id))
    else:
        log.info("当前没有未完成的订单。")

def after_trading_end(context):
    log.info('盘后处理结束')

API 详解

1. get_open_orders()

  • 功能:获得当天的所有未完成的订单。
  • 参数:无。
  • 返回值:一个字典(dict),Key 是 order_id,Value 是 Order 对象。

2. cancel_order(order)

  • 功能:取消订单。
  • 参数order,可以是 Order 对象,也可以是 order_id(字符串)。
  • 返回值:如果取消成功,返回对应的 Order 对象;如果订单不存在或已完成,返回 None

常见问题 Q&A

Q: 为什么要显式调用撤单?回测不是会自动撤销吗?
A: 在回测环境中,每天收盘后系统确实会自动撤销未成交的订单。但在模拟交易或实盘中,或者在分钟级策略中(例如需要在当前分钟结束前撤销上一分钟的挂单),显式调用 cancel_order 是必须的,这有助于防止资金被无效挂单占用,或防止过期的信号在错误的时间成交。

Q: get_open_orders() 能获取到已经成交的订单吗?
A: 不能。它只返回状态为 open(已委托未成交)或 new(新创建未委托)的订单。如果订单已经全部成交(held)、已撤销(canceled)或被拒绝(rejected),不会包含在返回结果中。

Q: 如果我想撤销特定股票的订单怎么办?
A: 你可以在遍历时判断订单对象的 security 属性。例如:

orders = get_open_orders()
for _order in orders.values():
    if _order.security == '000001.XSHE':
        cancel_order(_order)