问题描述
使用order_target/order_target_value为什么会产生重复下单?
解决方案
在 ptrade 量化交易平台中,order_target(指定目标数量买卖)和 order_target_value(指定持仓市值买卖)是非常便捷的调仓函数。然而,在实盘交易场景中,如果不谨慎使用,极易导致重复下单的问题。根据 ptrade 官方 API 文档,产生重复下单的核心原因主要与柜台持仓数据同步机制有关。
产生重复下单的三大原因
-
持仓信息同步存在时滞(约6秒)
如果券商柜台配置为“持仓数据体现当日变化”,持仓信息的同步通常会有约 6 秒的时滞。假如在这 6 秒之内,策略连续触发了两笔或多笔order_target委托,由于底层持仓数量/市值尚未瞬时更新,引擎会认为目标尚未达成,从而按照旧的持仓数据再次计算差额并下单,造成重复委托。 -
未计算“在途订单”数量
同样在“持仓数据体现当日变化”的配置下,如果第一笔委托尚未完全成交(即存在在途订单),此时策略再次调用order_target设定相同的目标数量。由于 ptrade 引擎在计算时不会自动包含在途的总委托数量,它会认为当前持仓仍未达到目标,进而再次发出委托,导致重复下单。 -
柜台持仓数据不体现当日变化
如果券商柜台配置为“持仓数据不体现当日变化”,这意味着持仓数量/市值每天只会同步一次(通常在盘后)。在这种情况下,盘中的任何买卖操作都不会实时反映在get_position的结果中。因此,只要策略在盘中多次调用order_target,必然会因为读取到未更新的持仓数据而疯狂重复下单。
解决方案与最佳实践
为了避免上述问题,建议在实盘交易中采取以下措施:
1. 确认券商柜台配置
在使用 order_target 系列接口前,务必向您的券商确认其柜台的持仓同步机制:是否实时更新?延迟大概是多少?是否体现当日变化?
2. 增加订单与持仓的同步管理逻辑
在调用 order_target 之前,主动检查当前是否有未完成的订单(在途订单)。可以使用 get_open_orders() 函数来拦截重复下单。
def handle_data(context, data):
security = '600570.SS'
target_amount = 1000
# 检查是否有该股票的未完成订单(在途订单)
open_orders = get_open_orders(security)
if len(open_orders) > 0:
log.info(f"{security} 存在未完成订单,暂不进行 order_target 操作以防重复下单。")
return
# 确认无在途订单后,再执行目标调仓
order_target(security, target_amount)
3. 使用全局变量控制下单频率
如果策略逻辑允许,可以使用全局变量(如 g.ordered_today)来限制同一标的在特定时间段(如一分钟内或一天内)的下单次数,等待持仓数据确实更新后再进行下一次判断。
4. 替代方案:自行计算差额并使用 order
最稳妥的方法是放弃使用 order_target,改为在策略内部自行维护一个虚拟持仓(结合 get_position 和 get_open_orders),计算出需要买卖的差额后,直接使用 order() 或 order_value() 进行下单。
总结:order_target 和 order_target_value 在回测环境中表现完美,但在实盘中受限于物理柜台的同步延迟。增加严谨的订单状态检查(如判断 get_open_orders)是规避重复下单的关键。