时间加权平均价格算法(TWAP)和成交量平均算法(VWAP)在量化回测的应用
为什么要引入TWAP和 VWAP?
为了评估策略的资金容量,我们对M.trade模块里买入点和卖出点这两个参数进行了更丰富的扩展,支持了策略能够按更丰富的算法交易价格(WAP)进行撮合。
如果资金是10万的话,那么在开盘买入基本上没有什么问题,如果资金量是300万、或者1000万呢?开盘如果只买入几只股票的话,本身的交易行为就会改变市场状态,冲击成本巨大。因此我们支持了算法交易里TWAP和VWAP。
TWAP (Time Weighted Average Price),时间加权平均价格算法,是一种最简单的传统算法交易策略。TWAP模型设计的目的是使交易对市场影响减小的同时提供一个较低的平均成交价格,从而达到减小交易成本的目的。在分时成交量无法准确估计的情况下,该模型可以较好地实现算法交易的基本目的。
VWAP (Volume Weighted Average Price), 成交量加权平均价格。VWAP策略即是一种拆分大额委托单,在约定时间段内分批执行,以期使得最终买入或卖出成交均价尽量接近该段时间内整个市场成交均价的算法交易策略。
上述两种方式是最常用的算法交易执行方式。其实在我们实际交易的过程中也会发现,如果是一笔较大的订单,我们肯定不会直接全部下单,而是把订单进行拆分,逐渐成交。因此如果我们在回测的过程中也可以使用TWAP和VWAP的价格进行撮合,最直接的目的就是能够检验我们策略的资金容量,如果按照TWAP和VWAP进行撮合以后,收益率变动不大,那我们对策略的资金容量会有很大信心,即策略不再是只能管理几十万,管理上百万、上千万是没有问题的。
我们在stockranker模板策略的基础上,用多组WAP价格进行回测,并和默认回测价格做了一个对比,回测结果如下表所示:
可以看到使用WAP价格回测和使用默认的open买入close卖出回测相比,各项指标变化不大,这也一定程度上表明单一策略的资金容量其实比我们想象地要大很多。
字段查看
WAP相关的文档见:WAP算法交易字段18,截图如下:
设置方法
在回测模块右侧属性栏中,可以看到有买入点和卖出点的参数设置:
字段介绍
-
我们支持了TWAP,VWAP 两种WAP价格
-
每个字段对应了1-11 共11种时间规则指标,具体时间规则如下:
-
每一个字段对应了买卖两个方向
-
每一个字段又对应了两种数据:价格和成交量
综上,字段示例如下:
以上字段均储存在 bar1d_wap_CN_STOCK_A表 和 bar1d_wap_CN_STOCK_A_adj表 中,如果要手动核查下撮合价格的话,可以访问这两个表来获取股票的TWAP,VWAP价格以及成交量。(其中第一个表是真实的加权价格数据,后一个表是后复权的价格加权数据,两表中的字段相同)。
DataSource('bar1d_wap_CN_STOCK_A_adj').read(start_date='2017-12-28',end_date='2017-12-28',instruments=['000002.SZA'],fields=['date','instrument','wap_1_buy_volume', 'wap_1_sell_volume', 'wap_1_twap_buy','wap_1_twap_sell', 'wap_1_vwap_buy', 'wap_1_vwap_sell'])
也可以查询到表中所有字段如下:
DataSource('bar1d_wap_CN_STOCK_A_adj').read(start_date='2017-12-28',end_date='2017-12-28',instruments=['000002.SZA']).columns
我们选择买入点为twap_1,卖出点为twap_8,回测价格类型选择后复权,回测结果部分截图如下:
可以看到002801.SZA的买入价为128.17,000503.SZA的卖出价为319.99。
我们再从bar1d_wap_CN_STOCK_A_adj 表(如果回测价格类型选择的是真实价格,则用bar1d_wap_CN_STOCK_A 表)中读出这两只股票的wap_1_twap_buy和wap_8_twap_sell价格:
DataSource('bar1d_wap_CN_STOCK_A_adj').read(start_date='2016-12-30',end_date='2016-12-30',instruments=['002801.SZA','000503.SZA'],fields=['date','instrument','wap_1_twap_buy','wap_8_twap_sell'])
可以看到表中的价格和回测中的成交价是一致的,回测时确实使用了我们选择的WAP价格进行撮合成交。
计算方法和成交逻辑
-
成交量: 如果对应的是买,将涨停的分钟k线去除,不参与计算,即非涨停的量 如果对应的是卖,将跌停的分钟k线去除,不参与计算,即非跌停的量 例如: 假设000002股票在上午【2h】成交100手,涨停;下午【1h】打开涨停(非跌停),成交200手,收盘【1h】跌停,成交50手。 则,买入经调整的成交量是250 ,卖出经调整的成交量是 300
600339.SHA在2016-12-30这天盘中涨停,我们读这天的价量数据可以看到,当天的总成交量为15055283.0
DataSource('bar1d_CN_STOCK_A').read(start_date='2016-12-30',end_date='2016-12-30',instruments=['600339.SHA'])
而我们读取这个股票这一天的全天的buy_volume,可以看到交易量为8937100.0,去除了涨停的量:
DataSource('bar1d_wap_CN_STOCK_A_adj').read(start_date='2016-12-30',end_date='2016-12-30',instruments=['600339.SHA'],fields=['date','instrument','wap_11_buy_volume'])
-
平均价格: 如果对应的是买,将涨停的分钟k线去除 如果对应的是卖,将跌停的分钟k线去除 TWAP: Time Weighted Average Price, 是时间加权平均价格。 计算公式为 mean(Pm,n) ,其中n为k线数量,Pm为典型价格(等于 (high+low+close)/3)。 VWAP: Volume Weighted Average Price, 是交易量加权平均价格。 计算公式为 (close_0 * volume_0 + close_1 * volume_1 +close_2 * volume_2 +…+close_59* volume_59) / (volume_0+volume_1+…+volume_59) 。
-
成交逻辑: 实际成交量会受到我们选择的买点卖点的价格类型所对应的的成交量的影响,例如: 假设某天A股票成交1万手,而我们想买入2万手,假如买入点选择close,则实际可以成交1万手;假如买入点选择twap1,而当天wap_1_buy的成交量为500手,则实际只会成交500手。
更新后的WAP功能相比之前做了更进一步的细化和优化,考虑到了真实交易的涨跌和跌停情形,因此计算出来的算法交易平均价格更精准和符合实际,进一步提高了回测的准确性。