问题描述
客户反馈量化查持仓数据有延迟,策略刚成交一笔买入,但是get_position查持仓数据没有更新这一笔!
解决方案
问题解析:为什么 get_position 会有延迟?
在 ptrade 量化交易平台中,策略刚成交一笔订单后,立即调用 get_position 发现持仓数据没有更新,这是一个非常常见的现象。根据 ptrade 官方 API 文档说明,这主要与券商柜台的持仓数据同步机制有关:
- 持仓信息同步存在时滞:在实盘交易场景中,柜台返回持仓数据体现当日变化时,同步通常有 6秒左右的延迟。这意味着订单成交后,持仓数据不会瞬时更新。
- 部分柜台不体现当日变化:某些券商柜台的配置可能是不体现当日变化的,这种情况下持仓数量只会一天同步一次。
潜在风险
这种延迟在使用 order_target(指定目标数量买卖)或 order_target_value(指定持仓市值买卖)时极其危险。如果在持仓未更新的这 6 秒内,策略逻辑再次被触发(例如在 tick_data 或高频 handle_data 中),引擎会认为你还没有达到目标仓位,从而导致重复下单。
解决方案
为了避免因持仓数据延迟导致的逻辑错误或重复下单,建议采取以下三种解决方案:
1. 确认券商柜台配置
首先,联系您的券商,确认当前交易账户所在的柜台配置:
- 是否支持实时更新持仓情况?
- 延迟的具体时间大概是几秒?
2. 使用主推事件获取更快的反馈
相比于主动调用 get_position,ptrade 提供了速度更快的主推回调函数。您可以利用这两个函数来实时更新本地的持仓状态:
on_order_response(context, order_list):委托主推,比引擎和get_order()更新更快。on_trade_response(context, trade_list):成交主推,在订单成交时第一时间回调。
3. 在策略中增加“本地订单与持仓同步管理”(推荐)
最稳妥的做法是:不要完全依赖 get_position 来判断是否需要下单,而是在全局变量 g 中自行维护一个“在途/已下单”状态。
示例代码:使用全局变量防止重复下单
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 初始化一个字典,记录标的是否正在交易中(防止延迟导致的重复下单)
g.trading_status = {g.security: False}
def handle_data(context, data):
security = g.security
current_price = data[security]['close']
# 获取当前持仓
pos = get_position(security)
# 假设我们的逻辑是:价格突破 40 元,且当前无持仓,则买入 1000 股
if current_price > 40.0 and pos.amount == 0:
# 检查本地状态,确保没有在途订单
if not g.trading_status[security]:
order(security, 1000)
log.info(f"触发买入 {security} 1000股")
# 立即将本地状态设为 True,即使 get_position 还没更新,下一秒也不会重复下单
g.trading_status[security] = True
# 利用成交主推,在确认成交后,重置本地状态(可选,视具体策略逻辑而定)
def on_trade_response(context, trade_list):
for trade in trade_list:
if trade['status'] == '8': # '8' 表示已成
log.info(f"订单已成交: {trade['stock_code']}")
# 可以在这里结合实际逻辑更新本地维护的持仓量
总结
在编写 ptrade 实盘策略时,永远要考虑异步和延迟。尽量避免高频连续调用 order_target,如果必须使用,请务必结合 g 变量记录下单状态或使用 get_open_orders() 检查是否有未完成的订单,从而规避持仓同步时滞带来的风险。