使用 VIX 期权进行投资组合对冲
登录后收藏学术论文
A Study in Portfolio Diversification Using VIX Options [点击查看论文]
策略概要
该策略采用60%的股票和40%的债券投资组合,股票使用SPDR标准普尔500指数ETF(SPY),债券使用iShares 7-10年期美国国债ETF(IEF)。投资组合分配0-100个基点(bps)给VIX看涨期权,投资于VIX期货的1个月、2个月、3个月和4个月期权。VIX看涨期权的权重根据VIX指数水平调整:若VIX在15至30之间,则为1%;若在30至50之间,则为0.5%;否则为0%。期权在到期前展期,若具有内在价值则卖出。股票/债券部分每月重新平衡,期权销售所得现金再投资于该投资组合。该策略利用VIX期权对冲波动性,重点是基于市场状况的系统性动态分配。
II. 策略合理性
该策略通过每月将投资组合的固定百分比分配给VIX看涨期权,利用波动率的均值回复特性。当VIX低于均值时,购买更多期权;当VIX高于均值时,购买较少期权。该策略旨在确定期权的最佳实值性、到期时间和最小资本要求。仅当VIX在15%至50%之间时才购买看涨期权,确保投资者避免为可能不必要的期权支付过高的费用,从而调整投资组合的风险和回报状况。
回测表现
波动率8.44%
夏普比率1.02
索提诺比率0.504
最大回撤-10.47%
胜率35%
完整 Python 代码
from AlgorithmImports import *
class PortfolioHedgingUsingVIXOptions(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(1000000)
data = self.AddEquity("SPY", Resolution.Minute)
data.SetLeverage(5)
self.spy = data.Symbol
data = self.AddEquity("IEF", Resolution.Minute)
data.SetLeverage(5)
self.ief = data.Symbol
data = self.AddEquity("VIXY", Resolution.Minute)
data.SetLeverage(5)
self.vix = data.Symbol
option = self.AddOption('VIXY', Resolution.Minute)
option.SetFilter(-20, 20, 25, 35)
def OnData(self,slice):
for i in slice.OptionChains:
chains = i.Value
# Max 2 positions - spy and ief are opened. That means option expired.
invested = [x.Key for x in self.Portfolio if x.Value.Invested]
if len(invested) <= 2:
calls = list(filter(lambda x: x.Right == OptionRight.Call, chains))
if not calls: return
underlying_price = self.Securities[self.vix].Price
expiries = [i.Expiry for i in calls]
# Determine expiration date nearly one month.
expiry = min(expiries, key=lambda x: abs((x.date() - self.Time.date()).days - 30))
strikes = [i.Strike for i in calls]
# Determine out-of-the-money strike.
otm_strike = min(strikes, key = lambda x:abs(x - (float(1.35) * underlying_price)))
otm_call = [i for i in calls if i.Expiry == expiry and i.Strike == otm_strike]
if otm_call:
# Option weighting.
weight = 0.0
if underlying_price >= 15 and underlying_price <= 30:
weight = 0.01
elif underlying_price > 30 and underlying_price <= 50:
weight = 0.005
if weight != 0:
options_q = int((self.Portfolio.MarginRemaining * weight) / (underlying_price * 100))
# Set max leverage.
self.Securities[otm_call[0].Symbol].MarginModel = BuyingPowerModel(5)
# Sell out-the-money call.
self.Buy(otm_call[0].Symbol, options_q)
self.SetHoldings(self.spy, 0.6)
self.SetHoldings(self.ief, 0.4)