最近策略研究方向中要使用到成交总金额(turnover),在这里中已经讲解了在实时的tickdata中加入成交总金额的方法。我沿着这个思路,增加修改的几个地方,实现在bardata中加入成交总金额。
注意一点是要先确保在tickdata中已成功加入成交总金额,再修改下面几个地方才能实现BarData中加入成交总金额。
1、object.py (为了上下文统一,所有的turnover改为小写,tickdata中也是)
class BarData(BaseData):
******省略
interval: Interval = None
volume: float = 0
turnover: float = 0 ##增加,turnover小写
open_interest: float = 0
open_price: float = 0
******省略
2、database_sql.py(database_sql.py主要用于保存与读取数据库,也作修改,保证整个VNPY都能使用turnover)
①
def init_models(db: Database, driver: Driver):
class DbBarData(ModelBase):
******省略
volume: float = DoubleField()
turnover: float = DoubleField() ##增加,volume、turnover、open_interest改了Field类型,后面会说明原因
open_interest: float = DoubleField()
open_price: float = FloatField()
high_price: float = FloatField()
low_price: float = FloatField()
close_price: float = FloatField()
②
def from_bar(bar: BarData):
******省略
db_bar.volume = bar.volume
db_bar.turnover = bar.turnover ##增加
db_bar.open_interest = bar.open_interest
db_bar.open_price = bar.open_price
db_bar.high_price = bar.high_price
db_bar.low_price = bar.low_price
db_bar.close_price = bar.close_price
return db_bar
③
def to_bar(self):
******省略
volume=self.volume,
turnover=self.turnover, ##增加
open_price=self.open_price,
high_price=self.high_price,
open_interest=self.open_interest,
low_price=self.low_price,
close_price=self.close_price,
gateway_name="DB",
)
return bar
3、utility.py(修改了合成1分钟Bar的update_tick(),update_bar()中window_bar.volume不知道为什么要对bar.volume整型处理,也先统一吧)
①
def update_tick(self, tick: TickData):
******省略
if self.last_tick:
volume_change = tick.volume - self.last_tick.volume
turnover_change = tick.turnover - self.last_tick.turnover ##增加,对照volume
self.bar.volume += max(volume_change, 0)
self.bar.turnover += max(turnover_change, 0) ##增加,对照volume
# print(self.bar.turnover)
self.last_tick = tick
②
def update_bar(self, bar: BarData):
******省略
# Update close price/volume into window bar
self.window_bar.close_price = bar.close_price
self.window_bar.volume += int(bar.volume)
self.window_bar.turnover += int(bar.turnover) ## 增加,对照window_bar.volume,不知道int()作用,int的范围更大?
self.window_bar.open_interest = bar.open_interest
删除原来保存的bar数据库 database.db(会同时删掉dbtickdata表,或者可以直接删库下的dbbardata表),再重启VNPY,bardata中就加入了成交金额turnover。
完成上面的步骤后,输出bardata中的turnover,结果正确。我启动了datarecorder连接MySQL数据库,开始实时记录数据。发现turnover能够写入到MySQL中,但是后几位数字全是0。我在VNPY内各流程模块中打印出turnover,都是精确无误的,由此确定了问题应该出在本地的MySQL上。
查阅了peewee的文档,得知peewee的FloatField相当于MySQL的Real。MySQL中的Real一般是Float类型,在64位电脑上不设置长度、小数位,默认的Float精度只能到6位数,turnover存入时就溢出了。鉴于大于6位数挺常见的,所以将database_sql.py建表时的volume、turnover、open_interest改了Field类型为DoubleField(),问题解决。
还有几个注意要点:
①. VNPY的tick数据是CTP的源数据,turnover字段在郑商所中处理有点不太一样,turnover要乘以合约乘数才是真正的成交总金额。
②. 跟turnover相关还有一个是当日均价,这时郑商所是正确的,另外两商品交易所的要除以合约乘数。