历史文档

【历史文档】策略回测-WAP价格回测功能

由small_q创建,最终由small_q 被浏览 503 用户

更新

本文内容对应旧版平台与旧版资源,其内容不再适合最新版平台,请查看新版平台的使用说明

新版量化开发IDE(AIStudio):

https://bigquant.com/wiki/doc/aistudio-aiide-NzAjgKapzW

新版模版策略:

https://bigquant.com/wiki/doc/demos-ecdRvuM1TU

新版数据平台:

https://bigquant.com/data/home

https://bigquant.com/wiki/doc/dai-PLSbc1SbZX

新版表达式算子:

https://bigquant.com/wiki/doc/dai-sql-Rceb2JQBdS

新版因子平台:

https://bigquant.com/wiki/doc/bigalpha-EOVmVtJMS5


近期平台对WAP价格回测功能做了一些更新升级,升级目的是尽可能保证回测和真实实盘场景一致。本文是对更新内容做示例介绍。

为什么要引入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价格进行回测,并和默认回测价格做了一个对比,回测结果如下表所示:

买点 卖点 夏普比率 年化收益 总收益 最大回撤
open close 1.91 108.29% 314.1% 47.39%
twap_1 twap_8 1.87 110.21% 321.51% 46.48%
twap_2 twap_7 1.7 97.49% 273.53% 45.07%
twap_3 twap_6 1.78 101.26% 287.48% 43.16%
twap_4 twap_5 1.83 98.75% 278.14% 43.11%
twap_9 twap_10 1.72 86.66% 234.89% 40.13%
vwap_1 vwap_8 1.87 110.77% 323.69% 45.46%
vwap_2 vwap_7 1.74 100.74% 285.53% 44.63%
vwap_3 vwap_6 1.78 103.06% 294.2% 43.63%
vwap_4 vwap_5 1.78 95.54% 266.4% 43.55%
vwap_9 vwap_10 1.81 91.45% 251.72% 37.73%

可以看到使用WAP价格回测和使用默认的open买入close卖出回测相比,各项指标变化不大,这也一定程度上表明单一策略的资金容量其实比我们想象地要大很多。

设置方法

在回测模块右侧属性栏中,可以看到有买入点和卖出点的参数设置:下拉即可选择想要的WAP价格

{w:100}{w:100}{w:100}

\

字段介绍

我们支持了TWAP,VWAP 两种WAP价格

每个字段对应了1-11 共11种时间规则指标,具体时间规则如下:

字段 时间规则 明细
twap_1/vwap_1 早盘前5分钟 9:30到9:35
twap_2/vwap_2 早盘前15分钟 9:30到9:45
twap_3/vwap_3 早盘前30分钟 9:30到10点
twap_4/vwap_4 早盘前60分钟 9:30到10:30
twap_5/vwap_5 尾盘前60分钟 14:00到15:00
twap_6/vwap_6 尾盘前30分钟 14:30到15:00
twap_7/vwap_7 尾盘前15分钟 14:45到15:00
twap_8/vwap_8 尾盘前5分钟 14:55到15:00
twap_9/vwap_9 上午 9:30到11:30
twap_10/vwap_10 下午 13:00到15:00
twap_11/vwap_11 全天 上午+下午

每一个字段对应了买卖两个方向

每一个字段又对应了两种数据:价格和成交量

综上,字段示例如下:

字段 解释
wap_1_twap_buy 早盘前5分钟买单的twap价格
wap_1_twap_sell 早盘前5分钟卖单的twap价格
wap_1_vwap_buy 早盘前5分钟买单的vwap价格
wap_1_vwap_sell 早盘前5分钟卖单的vwap价格
wap_1_buy_volume 早盘前5分钟买单的成交量(经调整后)
wap_1_sell_volume 早盘前5分钟卖单的成交量(经调整后)

以上字段均储存在 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'])

{w:100}{w:100}{w:100}也可以查询到表中所有字段如下:

DataSource('bar1d_wap_CN_STOCK_A_adj').read(start_date='2017-12-28',end_date='2017-12-28',instruments=['000002.SZA']).columns

{w:100}{w:100}{w:100}

我们选择买入点为twap_1,卖出点为twap_8,回测价格类型选择后复权,回测结果部分截图如下:

{w:100}{w:100}{w:100}可以看到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'])

{w:100}{w:100}{w:100}可以看到表中的价格和回测中的成交价是一致的,回测时确实使用了我们选择的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'])

{w:100}{w:100}{w:100}而我们读取这个股票这一天的全天的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'])

{w:100}{w:100}{w:100}

  • 平均价格:

    如果对应的是买,将涨停的分钟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功能相比之前做了更进一步的细化和优化,考虑到了真实交易的涨跌和跌停情形,因此计算出来的算法交易平均价格更精准和符合实际,进一步提高了回测的准确性。欢迎大家使用和反馈意见。

评论
  • 000505,2020年8月21日 , twap_8 价格不对,比前一日高了好几倍
  • 有个疑问,尾盘前5分钟(甚至尾盘前20分钟),如果此时涨停,默认触发了当日涨停不卖出的条件,那又因为这段时间在个人眼里为非强势涨停股,弊大于利,如果说直接取消掉当日涨停不卖的条件的话,又导致早盘强势封涨停的票因为没有这个前置条件而被卖出
  • 另外,这个功能是否会过拟合?本来某些票一天之内会收十字星,然而因设置了中午休市前卖出刚好是当天高位,确定了利益最大化,有没有可能本来20%的年化直接变成100%?
  • 是不是后复权了?
  • 其他的股票,其他的时间,都对,就这个点的数据不对