问题描述
/
解决方案
在 ptrade 量化交易平台中,使用 get_position 获取持仓数据时遇到延迟,从而导致 order_target 或 order_target_value 等接口重复下单,是一个非常经典的实盘问题。
为什么会出现持仓延迟?
根据 ptrade 官方 API 文档说明,持仓数据的更新依赖于券商柜台的配置:
- 实时更新但有时滞:交易场景中持仓信息同步通常有 6秒左右的时滞。如果在这6秒内连续触发策略逻辑,由于
get_position返回的数量尚未更新,策略会误以为目标未达成,从而再次发出委托,造成重复下单。 - 日终同步:部分柜台配置为持仓数据不体现当日变化,一天只同步一次。这种情况下使用目标数量下单接口必然会导致严重的重复下单。
解决方案
为了避免重复下单,我们需要在策略代码中引入订单和持仓的本地同步管理机制。以下是几种常用的解决思路:
方案一:使用全局变量(状态机)控制下单频率
最简单有效的方法是使用全局对象 g 来记录当日或当前周期的下单状态。一旦触发下单,立即修改状态,阻止后续重复触发。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 初始化下单标识
g.order_flag = False
def before_trading_start(context, data):
# 每天盘前重置标识
g.order_flag = False
def handle_data(context, data):
if not g.order_flag:
# 满足策略条件时下单
if data[g.security]['close'] > 40:
order_target(g.security, 1000)
# 下单后立即锁定标识
g.order_flag = True
log.info('已触发下单,锁定状态防止重复')
方案二:结合 get_open_orders 检查未完成订单
在发出新的委托前,先检查当前标的是否存在尚未成交的挂单。如果存在,则说明之前的委托还在处理中,应当跳过本次下单。
def handle_data(context, data):
security = '600570.SS'
# 获取当前标的的未完成订单
open_orders = get_open_orders(security)
# 如果有未完成的订单,说明之前的委托还在途,直接返回
if len(open_orders) > 0:
log.info(f'{security} 存在未完成订单,跳过本次下单')
return
# 获取当前持仓
pos = get_position(security)
# 策略逻辑:假设目标持仓为 1000 股
target_amount = 1000
if pos.amount < target_amount:
order_target(security, target_amount)
log.info(f'发起委托,目标数量: {target_amount}')
方案三:本地维护虚拟持仓(高级用法)
对于高频或复杂的策略,可以在本地维护一个“虚拟持仓”字典。每次调用 order 系列函数后,立即在本地字典中更新预期持仓量。后续的逻辑判断优先依赖本地虚拟持仓,而不是直接依赖 get_position。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 本地维护的预期持仓
g.virtual_positions = {}
def before_trading_start(context, data):
# 每天盘前以柜台真实持仓初始化虚拟持仓
pos = get_position(g.security)
g.virtual_positions[g.security] = pos.amount if pos else 0
def handle_data(context, data):
security = g.security
current_virtual_pos = g.virtual_positions.get(security, 0)
target_amount = 1000
# 使用虚拟持仓进行判断
if current_virtual_pos < target_amount:
# 计算需要买入的差额
buy_amount = target_amount - current_virtual_pos
order(security, buy_amount)
# 立即更新本地虚拟持仓
g.virtual_positions[security] = target_amount
log.info(f'下单 {buy_amount} 股,更新虚拟持仓为 {target_amount}')
总结建议
- 谨慎使用
order_target和order_target_value:在实盘交易中,尽量通过计算差额后使用order或order_value进行增量下单,配合本地状态管理。 - 确认券商配置:在实盘前,务必向券商确认其柜台的持仓同步机制(是实时、有延迟还是日终同步),以便选择最合适的代码架构。