vnpy在cta策略实盘时为什么不直接使用米矿的实时分钟数据,而是将交易所返回的tick数据合成分钟?
可能存在问题的代码块如下
if self.last_dt and self.last_dt.minute != tick.datetime.minute:
for bar in self.bars.values():
bar.datetime = bar.datetime.replace(second=0, microsecond=0)
self.on_bars(self.bars)
self.bars = {}
bar = self.bars.get(tick.vt_symbol, None)
if not bar:
bar = BarData(
symbol=tick.symbol,
exchange=tick.exchange,
interval=Interval.MINUTE,
datetime=tick.datetime,
gateway_name=tick.gateway_name,
open_price=tick.last_price,
high_price=tick.last_price,
low_price=tick.last_price,
close_price=tick.last_price,
open_interest=tick.open_interest
)
self.bars[bar.vt_symbol] = bar
else:
bar.high_price = max(bar.high_price, tick.last_price)
bar.low_price = min(bar.low_price, tick.last_price)
bar.close_price = tick.last_price
bar.open_interest = tick.open_interest
bar.datetime = tick.datetime
last_tick = self.last_ticks.get(tick.vt_symbol, None)
if last_tick:
bar.volume += max(tick.volume - last_tick.volume, 0)
bar.turnover += max(tick.turnover - last_tick.turnover, 0)
self.last_ticks[tick.vt_symbol] = tick
self.last_dt = tick.datetime
其中的基本逻辑为当tick的datetime标识中的minute改变时,就将已经缓存好的self.bars推出(不包含当前tick),并将self.bars清空,当前tick进入self.bars。
在这种逻辑下导致了如下问题,以下截图为实盘打印,使用品种SA209.CZCE、FG209.CZCE、MA209.CZCE
截图中开头为@NormTick的是在on_tick首行进行打印,开头为@minbar是在on_bars首行进行打印,可梳理出运行逻辑如下:
在论坛中找到解决类似问题的帖子:https://www.vnpy.com/forum/topic/7028-portfolio-strategy-zhong-on-tick-han-shu-zhong-geng-xin-bars-de-luo-ji-shi-cuo-wu-de-xiu-zheng-ban-de-luo-ji-ru-xia
基本思想为将 self.last_dt.minute != tick.datetime.minute 修改为 self.last_dt.minute < tick.datetime.minute,这样的确可以避免on_bars反复运行,但是在我的例子中会将14:46:59的纯碱tick包裹在14:47的min bar中,虽说数据仍然不准确,但好在没有很离谱(一个min bar实则只包含了一个tick)
目前正在思考更完善的解决方案
我在策略的开发过程中涉及到了不少修改vnpy官方代码的地方,但与此同时官方的代码也在不断迭代,这样的话后续我本地代码想要跟上官方升级会遇到比较多的兼容性问题,请问有什么好的管理代码方式吗