为了方便用 set_target_volume() 来管理实盘交易,上次发生过一次开仓后,紧接着平仓,再开仓,再平仓,一共循环了4次才稳定下来,浪费了点差和手续费,但是上次没有详细罗列每一步的数据,无法确定原因,后面2次交易又正常了,不过最近一次又发现同样的重复开平问题,这次罗列了每一步的数据,才证实了 api.get_position(SYMBOL).pos_long/short 与api.get_position(SYMBOL).open_price_long/short 居然不是同步更新的,api.get_position(SYMBOL).pos_long/short 取到开仓数据后,进入平仓模块,此时的api.get_position(SYMBOL).open_price_long/short 居然读数为0,以此数据加减止损点差来判断平仓条件的话,就可能会立即触发,从而造成了反复的开平,直到某个点,这两个数据同时更新了才会停下来。用 set_target_volume() 来管理实盘交易的话,这是一个麻烦的问题,希望能解决一下。
我也遇到了这个问题,不过我觉得这个是可以理解的
因为从一方面来说,上期所的底层CTP接口关于所有的数据都是推送的,所以下了单哪怕成交之后也有可能没有position数据推送过来,在tqsdk里也就是wait_update()如果间隔很短,也有可能等不到一个新的position数据。
第二方面也是从底层来说,下了单不一定会成交(流动性不足的情况)可能会导致追价或者反复重新下单的一个过程。在这种情况也是不会有position在第一时间更新
第三方面从期货交易机制来看,set_target_volume有可能会先平仓再开仓,就有可能平仓的时候position先发生一次变化,开仓的时候再次发生一次变化。
上面几点都是交易所需要的交易逻辑,基本上比较难从框架角度能很好地解决,都有可能导致position更新不及时或者多次更新。(也就是说别的框架也都或多或少会遇到同样的麻烦)
所谓的比较难解决的点关键在于思考一个取舍问题:
如果set_target_volume()采用阻塞的方式来完成下单、检查仓位这两个操作的话,因为position更新时间的不确定性,加上网络延迟,就有可能会导致阻塞时间过长(300、500毫秒到1、2秒不等,因为有可能重新下单,从而增加多次的网络延迟),在这样的情况下就无法满足相对高频一些的逻辑,这样需要更快速处理下单的场景就会遇到麻烦。
所以到底是选择快速还是易用性呢?底层框架是无法抉择的,只有上层应用才能做选择。从底层来说,暴露最原始的操作才是更通用的做法,因为底层框架如果选择了分步操作,让上层应用自己去阻塞,上层应用是可以实现的,而如果底层框架选择易用而选择两步操作,上层应用想要实现快速下单都无法做到了。
因此,要么有一个二级的框架来再次封装tqsdk(二级框架与一级框架的关系好比深度学习领域中keras和tensorflow的关系),要么就暂时先自己处理吧