参考文献:
https://en.wikipedia.org/wiki/Time-weighted_average_price
https://en.wikipedia.org/wiki/Volume-weighted_average_price
http://blog.sina.com.cn/s/blog_163a2b9700102wdy0.html
https://www.douban.com/note/214362575
算法交易其实主要是用在基金公司、券商量化比较多。例如我已经选好股,要大量买入,但是单凭交易员的操作海量单而且要完成买入100万股这些的操作是有点的困难的。那么这时候怎样解决拆单,防止冲击成本的问题呢?只有依靠算法交易了。
根据各个算法交易中算法的主动程度不同,可以把算法交易分为被动型算法交易、主动型算法交易、综合型算法交易三大类。而TWAP(时间加权平均价格)、VWAP(成交量加权平均价格)就属于被动型算法交易,也是在日常算法交易中应用最为广泛的策略算法。
VWAP
VWAP是Volume Weighted Average Price的缩写,译为成交量加权平均价,VWAP策略是一种拆分大额委托单,在约定时间段内分批执行,以期使得最终买入或卖出成交均价尽量接近这段时间内整个市场成交均价的交易策略。它是量化交易系统中常用的一个基准。作为一个基准量,VWAP就是一个计算公式:
要做到这一点,VWAP模型必须把母单分割成为许多小的子单,并在一个指定的时间段内逐步送出去。这样做的效果就是降低了大单对市场的冲击,改善了执行效果;同时增加了大单的隐秘性。显然,VWAP模型的核心就是如何在市场千变万化的情况下,有的放矢地确定子单的大小、价格和发送时间。
VWAP模型做到这一点的关键是历史成交量、未来成交量的预测、市场动态总成交量以及拆单的时间段(就是总共要将总单拆分成多少单分别以怎样的时间频率交易)。较为高级的VWAP模型要使用交易所单簿(Order Book)的详细信息,这要求系统能够得到即时的第二级市场数据(Level II Market Data)。
VWAP模型对于在几个小时内执行大单的效果最好。在交易量大的市场中,VWAP效果比在流动性差的市场中要好。在市场出现重要事件的时候往往效果不那么好。如果订单非常大,譬如超过市场日交易量的1%的话,即便VWAP可以在相当大的程度上改善市场冲击,但市场冲击仍然会以积累的方式改变市场,最终使得模型的效果差于预期。
VWAP算法交易的目的是最小化冲击成本,并不寻求最小化所有成本。理论上,在没有额外的信息,也没有针对股票价格趋势的预测的情况下,VWAP 是最优的算法交易策略。
TWAP
TWAP交易时间加权平均价格Time Weighted Average Price 模型是把一个母单的数量平均地分配到一个交易时段上。该模型将交易时间进行均匀分割,并在每个分割节点上将拆分的订单进行提交。例如,可以将某个交易日的交易时间平均分为N 段,TWAP 策略会将该交易日需要执行的订单均匀分配在这N 个时间段上去执行,从而使得交易均价跟踪TWAP,也是一个计算公式:
TWAP不考虑交易量的因素。TWAP的基准是交易时段的平均价格,它试图付出比此时段内平均买卖差价小的代价执行一个大订单。TWAP模型设计的目的是使交易对市场影响减小的同时提供一个较低的平均成交价格,从而达到减小交易成本的目的。在分时成交量无法准确估计的情况下,该模型可以较好地实现算法交易的基本目的。但是使用TWAP过程中的一个问题是,在订单规模很大的情况下,均匀分配到每个节点上的下单量仍然较大,当市场流动性不足时仍可能对市场造成一定的冲击。另一方面,真实市场的成交量总是在波动变化的,将所有的订单均匀分配到每个节点上显然是不够合理的。因此,算法交易研究人员很快建立了基于成交量变动预测的VWAP 模型。不过,由于TWAP 操作和理解起来非常简单,因此其对于流动性较好的市场和订单规模较小的交易仍然适用。
代码实现
以A股 平安银行 的股票某一天的分钟线行情为例,分别用C++和python实现twap和vwap的求解。
在实际的交易系统中,将得到的价格分不同时段将大单拆成小单挂单交易,以下是twap和vwap计算的简单实现
C++
// calculate vwap valuedouble calc_vwap(std::vector<std::vector<std::string>> &marketDataTable){ int n = marketDataTable.size() - 1; // skip the first title line double total_sum = 0.0; int volume_sum = 0; for (int i = 1; i <= n; i++) { // get the price and volume according to table structure double high_price = atof(marketDataTable[i][9].c_str()); double low_price = atof(marketDataTable[i][10].c_str()); double price = (high_price + low_price) / 2; int volume = atoi(marketDataTable[i][11].c_str()); // compute total sum and volume sum total_sum += price * volume; volume_sum += volume; } return total_sum / volume_sum;}// calculate twap valuedouble calc_twap(std::vector<std::vector<std::string>> &marketDataTable){ int n = marketDataTable.size() - 1; // skip the first title line double price_sum = 0.0; for (int i = 1; i <= n; i++) { // get the price and volume according to table structure double high_price = atof(marketDataTable[i][9].c_str()); double low_price = atof(marketDataTable[i][10].c_str()); double price = (high_price + low_price) / 2; // compute price sum and time sum // here use the 1 min K-line data, so total time is n minutes price_sum += price; } return price_sum / n;}
python
# calculate vwap valuedef calc_vwap(marketDataTable): n = len(marketDataTable) - 1 total_sum = 0.0 volume_sum = 0 for i in range(1, n + 1): high_price = float(marketDataTable[i][9]) low_price = float(marketDataTable[i][10]) price = (high_price + low_price) / 2 volume = int(marketDataTable[i][11]) total_sum += price * volume volume_sum += volume return total_sum / volume_sum# calculate vwap valuedef calc_twap(marketDataTable): n = len(marketDataTable) - 1 price_sum = 0.0 for i in range(1, n + 1): high_price = float(marketDataTable[i][9]) low_price = float(marketDataTable[i][10]) price = (high_price + low_price) / 2 price_sum += price return price_sum / n
运行结果
reading market datacalculating TWAP and VWAPVWAP: 8.66789TWAP: 8.66475
完整demo下载
csdn: twap/vwap code
github: twap/vwap code
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
<div class="readall_box csdn-tracking-statistics tracking-click readall_box_nobg" data-pid="blog" data-mod="popu_596" style="display: none;">
<div class="read_more_mask"></div>
<a class="btn btn-large btn-gray-fred read_more_btn" target="_self">阅读全文</a>
</div>
<div class="csdn-tracking-statistics" data-pid="blog" data-mod="popu_222"><a href="javascript:void(0);" target="_blank"> </a> </div>
<div class="csdn-tracking-statistics" data-pid="blog" data-mod="popu_223"> <a href="javascript:void(0);" target="_blank"> </a></div>
<div id="digg" articleid="72830003">
</div>
<script type="text/javascript">
function btndigga() {
$(".csdn-tracking-statistics[data-mod='popu_222'] a").click();
}
function btnburya() {
$(".csdn-tracking-statistics[data-mod='popu_223'] a").click();
}
</script>
</ul>
<div style="clear:both; height:10px;"></div>