VXX/XIV量化分析演示
(因為黏貼關係,格式有所變化,原文可以參照optionwings.com網站策略研發->VXX/XIV量化分析演示)
本節講解並通過Python代碼逐步驗證Tony Cooper關於VIX衍生品VXX及XIV的量化分析方法和實踐策略
原論文請參考:
Easy Volatility Investing: Tony Cooper, Feb 2013
簡介
該論文嚐試以波動率指數(VIX Index)衍生的ETP產品建立波動率投資策略。
論文結構大致如下:
1. 引言
論文總結了以下幾點VIX波動率指數的既有規律(典型化事實):
論文目錄
2. 波動率的誘惑
關於CBOE VIX指數,我們在VIX衍生品係列講座中已經涉及( http://bit.ly/2lcQIEb),這裏不再重複,著重陳述一下論文中的觀點。
論文認為:VIX是可以預測的,這是基於VIX具有均值回歸特性這一假設作出的推斷。
論文指出:VIX的變化與S&P500的變化為負相關
下圖是我們用Python代碼進行的驗證,圖形顯示VIX與S&P指數SPX日收益的移動一年相關係數。注意二者負相關性逐漸趨強。
In [2]:
import pandas as pd
import pandas_datareader as web
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline
vix = web . DataReader( '^vix' , 'yahoo' , '1990-01-01' )
spx = web . DataReader( '^GSPC' , 'yahoo' , '1990-01-01' )
xiv = web . DataReader( 'xiv' , 'yahoo' , '2010-10-30' )
data = pd . DataFrame()
data[ 'VIX' ] = vix[ 'Adj Close' ]
data[ 'SPX' ] = spx[ 'Adj Close' ]
data[ 'XIV' ] = xiv[ 'Adj Close' ]
data[ 'VIX_Ret' ] = data[ 'VIX' ] . pct_change()
data[ 'SPX_Ret' ] = data[ 'SPX' ] . pct_change()
data[ 'VIX_Ret' ] . rolling( 252 ) . corr(data[ 'SPX_Ret' ]) . plot(figsize = ( 15 , 4 ))
Out[2]:
論文中展示VIX和XIV在2012-04-03至2012-10-01間的走勢圖,我們用以下代碼實現。
In [3]:
data_scaled = pd . DataFrame()
data_scaled[ 'VIX' ] = data[ 'VIX' ] / data . ix[ '2012-04-03' ][ 'VIX' ]
data_scaled[ 'XIV' ] = data[ 'XIV' ] / data . ix[ '2012-04-03' ][ 'XIV' ]
data_scaled . ix[ '2012-04-01' : '2012-10-01' ][[ 'VIX' , 'XIV' ]] . plot(figsize = ( 15 , 8 ))
Out[3]:
如上圖所示,期間VIX基本回到初始值,但XIV升幅近40%。
3. 波動率風險溢價(The Volatility Risk Premium)
論文在這一章節主要解釋及論證VRP的存在。
論文認為:在波動率交易雙方,對衝套保交易員情願付錢給投機交易員,用於減少自身的波動率風險。
In [4]:
data[ 'SPX_HV21' ] = data[ 'SPX_Ret' ] . rolling( 21 ) . std() * np . sqrt( 252 ) * 100
data[ 'SPX_HV21_Shift' ] = data[ 'SPX_HV21' ] . shift( -21 )
data[[ 'VIX' , 'SPX_HV21_Shift' ]] . plot(figsize = ( 15 , 8 ))
Out[4]:
我們進一步用下圖顯示二者之間的差異。按論文陳述,我們取二者對數差,使顯示更加清晰。
In [5]:
(np . log(data[ 'VIX' ]) - np . log(data[ 'SPX_HV21_Shift' ])) . plot(figsize = ( 15 , 8 ),grid =1 )
Out[5]:
4. VIX期貨
關於VIX期貨,讀者可以參考我們的專題( http://bit.ly/2lX0iIF)。
VIX衍生品ETP是建立在VIX期貨基礎上的。因為VIX指數沒有現貨產品,不能直接交易,因此VIX期貨價格代表市場對未來VIX水平的共同期待值。
下圖顯示的是2017年2月23日VIX期貨的展期結構曲線,這一天呈明顯的溢價形態(Contango)。
In [6]:
import sys
sys . path . append( "/Users/valley11/Google Drive/Projects/Python/Samples" )
import cboe_vx as cboe
VXF = pd . DataFrame()
VXF[ 'VIX' ] = data[ 'VIX' ]
f = cboe . getCboeData( 2017 , 3 )
VXF[ 'Mar' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 4 )
VXF[ 'Apr' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 5 )
VXF[ 'May' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 6 )
VXF[ 'Jun' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 7 )
VXF[ 'Jul' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 8 )
VXF[ 'Aug' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 9 )
VXF[ 'Sep' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2017 , 10 )
VXF[ 'Oct' ] = f[ 'Settle' ]
VXF . ix[ '2017-02-23' ] . plot(figsize = ( 15 , 5 ))
Out[6]:
下圖我們再展示曆史上展期結構呈逆向形態的曲線,這是發生在金融危機中的2008年10月3日。
In [7]:
VXF = pd . DataFrame()
VXF[ 'VIX' ] = data[ 'VIX' ]
f = cboe . getCboeData( 2008 , 10 )
VXF[ 'Oct' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2008 , 11 )
VXF[ 'Nov' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2008 , 12 )
VXF[ 'Dec' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 1 )
VXF[ 'Jan' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 2 )
VXF[ 'Feb' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 3 )
VXF[ 'Mar' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 4 )
VXF[ 'Apr' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 5 )
VXF[ 'May' ] = f[ 'Settle' ]
f = cboe . getCboeData( 2009 , 6 )
VXF[ 'Jun' ] = f[ 'Settle' ]
VXF . ix[ '2008-10-03' ] . plot(figsize = ( 15 , 5 ))
Out[7]:
前文通過VIX與SPX曆史波動率的比對,論證了VRP的存在;但因為VIX不可直接交易,無法獲取這一交易優勢。
在介紹VIX期貨後,論文提出問題:VRP在VIX期貨市場中存在麽?
這個驗證有點難度,因為VIX期貨產品距到期日時間是逐漸減少的,無法用VIX即期價格(30日估值)和沒有準確時間的期貨直接比較。
論文借鑒了S&P500 VIX短期期貨指數的一個方法,即建立一個假設的恒定一個月到期的VIX期貨產品,該期貨30天後會以當時VIX即期作為結算價格。因此恒定一個月到期的期貨與30天後的VIX之間具有了可比性。
下麵的代碼及圖形嚐試描述兩者間的關係:
In [8]:
import Quandl
VXF30 = pd . DataFrame()
x = Quandl . get( "CHRIS/CBOE_VX1" ) # continuous F1
VXF30[ 'F1' ] = x[ 'Settle' ]
x = Quandl . get( "CHRIS/CBOE_VX2" ) # continuous F2
VXF30[ 'F2' ] = x[ 'Settle' ]
calendar = pd . read_csv( 'f1_f2_ttm.csv' ) # read in expiry dates and days till maturity
calendar = calendar . set_index( 'Date' )
VXF30 = pd . merge(VXF30, calendar, how = 'left' , left_index = True , right_index = True )
VXF30[ 'X1' ] = 30 - VXF30[ 'TTM1' ]
VXF30[ 'X2' ] = VXF30[ 'TTM2' ] - 30
VXF30[ 'W1' ] = VXF30[ 'X2' ] / (VXF30[ 'X1' ] + VXF30[ 'X2' ])
VXF30[ 'W2' ] = VXF30[ 'X1' ] / (VXF30[ 'X1' ] + VXF30[ 'X2' ])
VXF30[ 'VXF30' ] = VXF30[ 'F1' ] * VXF30[ 'W1' ] + VXF30[ 'F2' ] * VXF30[ 'W2' ]
VXF30[ 'VIX' ] = data[ 'VIX' ]
VXF30[ 'VIX_ShiftF21' ] = data[ 'VIX' ] . shift( -21 )
#VXF30['VIX'] = data['VIX'].shift(-21)
VXF30[[ 'VXF30' , 'VIX_ShiftF21' ]] . ix[ '2007-10-01' :] . plot(figsize = ( 15 , 8 ))
Out[8]:
可以看出,多數時間裏,假設的恒定30天期貨價格高於30天後VIX的即期價格。
論文認為這意味著VRP在VIX期貨市場中同樣存在。
下圖進一步顯示二者間的對數差。
In [9]:
(np . log(VXF30[ 'VXF30' ] . ix[ '2007-10-01' :]) - np . log(VXF30[ 'VIX_ShiftF21' ] . ix[ '2007-10-01' :])) . plot(figsize = ( 15 , 8 ),grid = True )
(np . log(VXF30[ 'VXF30' ] . ix[ '2007-10-01' :]) - np . log(VXF30[ 'VIX_ShiftF21' ] . ix[ '2007-10-01' :])) . mean()
Out[9]:
0.07111734832772859
5. 滾動收益(Roll Yield)
在明確了VIX與VIX期貨間的關係後,論文提出以下問題:
這個問題實際就是即期與期貨,哪個對預測未來波動率更有效。
論文繼續陳述以下觀點:
- 滾動收益描述的是VIX即期與期貨價格之間的差值
- 滾動收益可以精確測量,但VRP不能
- 當期貨展期呈溢價形態(Contango)時,滾動收益為正;反之為負
我們用下圖顯示滾動收益的表現。
In [11]:
VXF[ 'F1_VIX_Yield' ] = (VXF30[ 'F1' ] - VXF30[ 'VIX' ]) / VXF30[ 'VIX' ] / VXF30[ 'TTM1' ]
VXF[ 'F1_VIX_Yield' ] . ix[ '2007-10-01' :] . plot(figsize = ( 15 , 8 ),grid = True )
Out[11]:
從2007年10月1日至今,首月期貨與即期價格間的滾動收益率日均大約為0.34%,相當於每月7%。
In [12]:
VXF[ 'F1_VIX_Yield' ] . ix[ '2007-10-01' :] . mean()
Out[12]:
0.0033657100890936895
6. 基於VIX期貨的ETP產品
關於基於VIX期貨的ETP產品,我們有專題講解,這裏不做過多陳述。簡單列舉論文中涉及的幾個產品。
基於S&P 500 VIX短期期貨指數的ETP:正向VXX,反向XIV
基於S&P 500 VIX中期期貨指數的ETP:正向VXZ,反向ZIV
除此以外,還有很多正向、反向、單倍、與多倍的ETP產品,但基本遵從非常近似的產品結構。
7. XIV 動態特性
XIV的產品設計為跟蹤S&P500 VIX短期期貨指數,希望通過持有VIX前兩個月期貨的空倉,實現每日反向的指數收益率:
XIV每日在第一與第二月期貨產品間調倉,維持恒定的一個月到期的期貨。
下麵我們用Python代碼展示XIV相對於VIX的回歸分析。
In [14]:
import OLS_Regression as ols
data[ 'XIV_Ret' ] = data[ 'XIV' ] . pct_change()
ols . linreg(data[ 'VIX_Ret' ] . ix[ '2010-12-01' :] . values, data[ 'XIV_Ret' ] . ix[ '2010-12-01' :] . values)
Out[14]:
OLS Regression Results
Dep. Variable: |
y |
R-squared: |
0.777 |
Model: |
OLS |
Adj. R-squared: |
0.777 |
Method: |
Least Squares |
F-statistic: |
5466. |
Date: |
Wed, 01 Mar 2017 |
Prob (F-statistic): |
0.00 |
Time: |
13:02:31 |
Log-Likelihood: |
3990.8 |
No. Observations: |
1571 |
AIC: |
-7978. |
Df Residuals: |
1569 |
BIC: |
-7967. |
Df Model: |
1 |
|
|
Covariance Type: |
nonrobust |
|
|
|
coef |
std err |
t |
P>|t| |
[95.0% Conf. Int.] |
const |
0.0032 |
0.000 |
6.584 |
0.000 |
0.002 0.004 |
x1 |
-0.4613 |
0.006 |
-73.930 |
0.000 |
-0.474 -0.449 |
Omnibus: |
325.865 |
Durbin-Watson: |
2.115 |
Prob(Omnibus): |
0.000 |
Jarque-Bera (JB): |
2968.399 |
Skew: |
-0.697 |
Prob(JB): |
0.00 |
Kurtosis: |
9.588 |
Cond. No. |
13.0 |
論文進一步定義:
下圖我們嚐試繪製該期待值自XIV發布以來的時間序列以及累計效果。
In [15]:
VXF30[ 'F2_F1_Yield' ] = (VXF30[ 'F2' ] - VXF30[ 'F1' ]) / (VXF30[ 'F1' ]) /30
(VXF30[ 'F2_F1_Yield' ] . ix[ '2010-10-30' :] *100 ) . plot(figsize = ( 15 , 8 ), grid = True )
Out[15]:
上圖同時清晰的顯示了首月與次月呈溢價與逆向結構的階段:
In [240]:
VXF30[ 'F2_F1_Yield' ] . ix[ '2010-10-30' :] . add( 1 ) . cumprod() . plot(figsize = ( 15 , 8 ),grid = True )
Out[240]:
上圖為日滾動收益期待值的累積效果。如圖所示,如果滾動收益的期待值可以實現,XIV會在短短幾年獲得巨大收益。顯然,事實並非如此。
8. 更多的XIV動態特性
我們先展示VXX與XIV自發布之日起至今的2009-01-29與2010-11-30間的走勢圖。
In [16]:
data[ 'VXX' ] = web . DataReader( 'vxx' , 'yahoo' , '2009-01-29' )[ 'Adj Close' ]
data[[ 'VXX' ]] . ix[ '2009-01-29' :] . plot(figsize = ( 15 , 4 ))
Out[16]:
In [17]:
data[[ 'XIV' ]] . ix[ '2010-11-30' :] . plot(figsize = ( 15 , 4 ))
Out[17]:
從上麵兩個圖,我們看出:
下麵我們用代碼演示回撤計算。
In [22]:
ret = data[ 'XIV_Ret' ] . add( 1 ) . cumprod()
dd = ret . div(ret . cummax()) . sub( 1 )
mdd = dd . min()
end = dd . argmin()
start = ret . loc[:end] . argmax()
print "Maximum Drawdown:" , mdd
print "Peak Date:" , start
print "Trough Date:" , end
Maximum Drawdown: -0.743870631195
Peak Date: 2011-07-07 00:00:00
Trough Date: 2011-11-25 00:00:00
9. 交易策略
論文闡述了5種交易策略,每種策略包含多種交易信號。
策略一:買入持有
策略二:動量策略
(i) 計算並比較過去k日中收益最高的ETN,買入並持有
(ii) 當所有k日收益為零,保持空倉
論文建議使用83天作為參數。
策略三:溢價/逆向滾動收益策略(Contango-Backwardation Roll Yield)
策略尋求獲取最大的滾動收益:在展期為溢價(Contango)時,買入XIV, 當展期為逆向(Backwardation)時,買入VXX
該策略信號清晰,比較容易把握(VXV為90日波動率指數):
論文同時給出多個信號變種:
論文建議使用Vratio或10日均值的Vratio10
策略四:波動率風險溢價(Volatility Risk Premium)
信號組合:
論文推薦使用HVOL10S,即10日曆史波動率附加5日移動平均值
策略五:對衝
該策略對於ETN的發行者有利,因為涉及持續的對衝與調倉,我們不做過多解釋。
其它策略
既然波動率拖拉對XIV投資有阻礙作用,論文建議可以講VIX本事波動率引入策略開發之中,用來提高收益。例如:
stdlVIX 定義為VIX對數的標準差,對上述策略的一個改進就是:
當Vratio > 1,並且在stdlVIX < 0.14,買入XIV。
10. 交易風險
論文提到上述策略在截止至2013年2月的曆史回測中都獲得了很好的收益。我們需要指出,2013年以前和以後的波動率市場不盡相同,如果回測自VXX/XIV發布之日至今,結論並不一致。我們本節的講解主要針對熟悉分析方法,所以並不做過多評論。
在探討交易風險時,論文主要談及以下兩個方麵:
1) 未來難以獲得同樣收益的風險(類似於統計中的過度適應問題Overfitting)
2) 將這些策略引入已有投資組合中的帶來的裨益
VRP會持續麽?論文認為:
論文列舉以下幾點實證分析中的風險因素:
波動率拖拉
波動率指的是日收益率的年化波動率。
論文指出,當日收益率的波動率增加時,複利累計的收益會減少,也就是收益率波動率越高,累計收益越低。
我們參考下圖。
In [23]:
data . ix[ '2012-03-25' : '2012-08-15' ][[ 'VIX' , 'XIV' ]] . plot(figsize = ( 15 , 8 ))
Out[23]:
上圖顯示的是VIX指數與XIV在2012年3月25日至2012年8月15日間的走勢圖。論文指出:
下麵我們分析期間的滾動收益。
In [24]:
VXF30 . ix[ '2012-03-25' : '2012-08-15' ][ 'F2_F1_Yield' ] . plot(figsize = ( 15 , 4 ))
VXF30 . ix[ '2012-03-25' : '2012-08-15' ][ 'F2_F1_Yield' ] . mean()
Out[24]:
0.0032925691048866844
如上圖所示,日滾動收益的期待值非常顯著:
我們再用下圖展示VIX,首月F1, 次月F2期貨在此期間的走勢。
In [25]:
data = pd . merge(data, VXF30[[ 'F1' , 'F2' , 'F2_F1_Yield' ]], how = 'left' ,left_index = True ,right_index = True )
data . ix[ '2012-03-25' : '2012-08-15' ][[ 'F1' , 'F2' , 'VIX' ]] . plot(figsize = ( 15 , 8 ))
Out[25]:
聯係上麵三張圖,我們很難解釋為什麽XIV在此期間收益幾乎為零。
論文指出,其中的原因是因為波動率拖拉抵消了滾動收益。
關於波動率拖拉的計量方法,我們這裏暫不做詳細討論。
時間同步風險
論文指出:
當展期結構在溢價與逆向間頻繁變化時,每次依照信號執行的投資很有可能連續踏空。例如展期每天調轉方向,依照信號會造成每日投資損失。
同步風險是周期性風險,隻發生在溢價與逆向結構調換的時候。
在操作中,可以用10日均線來避免頻繁波動。
VRP/滾動收益風險(VRP-RYR)
論文指出,當我們追求滾動收益,而不是VRP時,我們會麵臨該風險。雖然兩者相關,但這種相關性會弱化或消失-特別是在VIX指數頻繁做均值回歸運動時(即拒絕滾動收益時)。我們可以嚐試這樣理解:當展期為溢價時,VIX有上升趨勢,但此時我們持倉XIV(做空VIX);當展期為逆向時,VIX有下降趨勢,但此時我們持倉VXX(做多VIX) 。
VIX體製變化
VIX體製是通過觀察VIX長期走勢圖,根據VIX水平及發展方向,大致按時間段區分的具有不同特性的階段。例如2008年金融危機前後,VIX處於20以上的高位;而2012年後至今,VIX呈下降趨勢,並逐漸降至12以下水平。
不同的VIX特性階段,適用於不同的交易策略。因此判斷VIX體製的變化,也是ETP交易的重要一環。論文特此將體製變化最為交易風險之一。
回撤風險
前麵論述關於XIV高達-74%的回撤值,充分說明VIX ETP交易屬於高風險品種。
11. 分散投資
論文認為VIX衍生品交易可以作為獨立投資資產類別,依靠其與股指的負相關性,可以為已有投資組合帶來分散投資的優勢。論文論證通過上升策略,可以幫助投資組合減少收益波動率,增加收益,減小回撤,提升Sharpe。
12. 未來研究課題
論文探討通過矢量回歸算法預測VRP作為將來的研究課題,希望避免過度適應,提高Sharpe至2~3之間。
13. 總結
總結上述五種策略:
1 - 買入持有
2 - 動量方法
3 - 基於溢價/逆向結構的滾動收益:優勢是交易頻率非常低,通常一年幾次交易
4 - VRP基於波動率風險溢價:交易比較頻繁
5 - 對衝: 需要頻繁調倉,以及特殊軟件,適用於ETP發行機構
下麵我們舉例如何生成交易信號
在交易信號產生後,可以在回測平台(例如Quantopian)進行回測。
In [26]:
# show Vratio10 smoothed by 10 day moving average
# If the 10 day moving average of VXV/VIX > 1, long XIV; otherwise, long VXX
Vratio = pd . DataFrame()
Vratio[ 'VIX' ] = web . DataReader( '^vix' , 'yahoo' , '2000-01-01' )[ 'Adj Close' ]
Vratio[ 'VXV' ] = web . DataReader( '^vxv' , 'yahoo' , '2000-01-01' )[ 'Adj Close' ]
Vratio[ 'VXV/VIX' ] = Vratio[ 'VXV' ] / Vratio[ 'VIX' ]
Vratio[ 'VXV/VIX MA10' ] = Vratio[ 'VXV/VIX' ] . rolling( 10 ) . mean()
Vratio . ix[ '2011-08-01' :][ 'VXV/VIX MA10' ] . plot(figsize = ( 15 , 8 ))
Vratio[ 'VXV/VIX MA10' ] . to_csv( 'vratio_ma10.csv' )
In [27]:
# show VRP
# If the 5 day moving average of (VIX - HV10) > 0, long XIV; otherwise, long VXX
VRP = pd . DataFrame()
VRP[ 'VIX' ] = web . DataReader( '^vix' , 'yahoo' , '2000-01-01' )[ 'Adj Close' ]
VRP[ 'SPX' ] = web . DataReader( '^gspc' , 'yahoo' , '2000-01-01' )[ 'Adj Close' ]
VRP[ 'SPX_Ret' ] = VRP[ 'SPX' ] . pct_change()
VRP[ 'HV10' ] = VRP[ 'SPX_Ret' ] . rolling( 10 ) . std() * np . sqrt( 252 )
VRP[ 'HV10 MA5' ] = VRP[ 'HV10' ] . rolling( 5 ) . mean()
(VRP[ 'VIX' ] - VRP[ 'HV10 MA5' ] *100 ) . plot(figsize = ( 15 , 8 ),grid = True )
(VRP[ 'VIX' ] - VRP[ 'HV10 MA5' ] *100 ) . to_csv( 'vrp_hv10_ma5.csv' )