问题描述
/
解决方案
在ptrade量化平台的仿真交易或实盘交易中,出现重复下单通常是由持仓同步延迟、服务器重启重拉机制或事件回调逻辑不当引起的。以下是常见原因及对应的解决方案:
1. 滥用 order_target 或 order_target_value 导致重复下单
原因分析:
在实盘/仿真交易场景中,柜台返回持仓数据体现当日变化通常有时滞(一般在6秒左右)。如果在短时间内连续调用 order_target,由于底层持仓数量尚未更新,引擎会认为目标未达成,从而重复发出委托单。此外,如果第一笔委托未完全成交且未撤单,再次调用也会导致重复下单。
解决方案:
在调用目标数量下单接口前,务必检查当前是否有未完成的订单(在途订单),或者改用 order 接口结合本地变量自行计算下单量。
def handle_data(context, data):
security = '600570.SS'
# 检查是否有未完成的订单,防止重复下单
open_orders = get_open_orders(security)
if len(open_orders) > 0:
log.info("存在在途订单,跳过本次下单")
return
# 确认无在途订单后,再使用 order_target
order_target(security, 1000)
2. 服务器重启导致 before_trading_start 重复执行
原因分析:
券商服务器升级或环境重启后恢复交易时,框架会重新执行 initialize 和 before_trading_start 函数。如果在这些函数中编写了下单逻辑,或者初始化了无法被持久化保存的全局变量,就会导致重复下单或逻辑错乱。
解决方案:
在 initialize 中使用 set_parameters 接口,配置 not_restart_trade 和 server_restart_not_do_before 参数,避免交易时间段重启拉起交易。
def initialize(context):
g.security = "600570.SS"
set_universe(g.security)
# 设置交易时间段服务器重启不再拉起本交易
# 设置服务器重启重拉交易时不再执行before_trading_start函数
set_parameters(not_restart_trade="1", server_restart_not_do_before="1")
3. 主推事件(on_order_response / on_trade_response)引发死循环
原因分析:
如果在委托主推或成交主推的回调函数中直接调用下单接口(如 order),且没有设置严格的状态锁(Flag),一旦下单触发回调,回调又触发下单,就会形成死循环,瞬间产生大量重复订单。
解决方案:
在主推回调中下单必须引入全局状态标识(如 g.flag)进行拦截。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
g.order_flag = False # 引入状态锁
def on_order_response(context, order_list):
if not g.order_flag:
order(g.security, 100)
g.order_flag = True # 下单后立即锁死
else:
log.info("已下单,拦截重复触发")
总结建议
- 尽量使用
order替代order_target:在实盘高频或分钟级策略中,自行维护持仓状态并使用order增量下单,比依赖底层持仓同步的order_target更安全。 - 分离下单与初始化逻辑:绝对不要在
initialize或before_trading_start中直接调用下单接口。 - 增加在途订单校验:任何下单动作前,调用
get_open_orders()检查是量化实盘防重发的标准最佳实践。