问题描述
解决方案
在PTrade中,若要撤销账户内所有未成交订单(包含手工下单、其他策略下的单以及当前策略的单),必须使用 get_all_orders() 配合 cancel_order_ex() 接口。
常规的 get_orders() 和 cancel_order() 仅能操作当前策略实例产生的订单,无法触及账户级别的其他委托。
核心逻辑说明
- 获取所有订单:使用
get_all_orders()获取当日账户的所有委托记录(返回的是字典列表)。 - 筛选未成交状态:遍历订单列表,检查
status字段。通常需要撤销的状态为'2'(已报/未成交) 和'7'(部成/部分成交)。 - 执行撤单:对符合条件的订单调用
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
关键注意事项
-
接口区别:
cancel_order(order_id):仅用于撤销本策略生成的Order对象或 ID。cancel_order_ex(order_dict):专门用于撤销由get_all_orders()返回的订单字典信息,适用于撤销外部订单(如手工单)。
-
状态判断:
- 代码中判断了
['2', '7'],这是最标准的“挂单”状态。 - 如果订单状态是
'0'(未报) 或'1'(待报),通常意味着订单还没到达交易所确认,此时调用撤单可能会失败或被拒绝,建议只针对已确认的挂单进行撤销。
- 代码中判断了
-
交易频率:
- 如果在
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 均可尝试撤销。