
“该策略基于VIX期货的期货溢价/期货贴水交易SPY、SH、VXX和XIV,通过对冲调整头寸。当相对基差超过预定义阈值时,平仓,对冲水平各不相同。”
资产类别: ETF | 地区: 美国 | 周期: 每日 | 市场: 股票 | 关键词: VIX,ETF
I. 策略概要
该策略涉及交易SPY和SH以获得标普500指数的敞口,以及交易VXX和XIV以获得短期VIX期货的敞口。计算近月VIX期货和现货VIX之间的相对差额,以检查期货溢价或期货贴水。如果市场处于期货溢价状态(VIX期货高于现货),投资者买入XIV并用SH对冲。如果处于期货贴水状态(VIX期货低于现货),投资者买入VXX并用SPY对冲。当相对基差超过预定的卖出阈值时,平仓。该策略在0%的对冲比率下效果最佳,但可以采用多种对冲水平以获得不同的结果。
II. 策略合理性
根据理性预期假说,期货价格应该预测未来的现货价格,但这不适用于VIX期货,因为VIX不是可交易的工具。与标的VIX指数相比,VIX期货一直被高估。Simon和Campasano(2014)的研究表明,VIX期货价格可以通过VIX近月期货价格与VIX指数之间的差额来预测。当期货高于VIX时,它们往往会下跌,当低于VIX时,它们往往会上涨。这种定价行为可以用风险厌恶来解释,因为投资者为VIX敞口支付溢价,预期通常为负回报。
III. 来源论文
VIX交易所交易产品:价格发现、对冲和交易策略 [点击查看论文]
- 博尔多纳多、莫尔纳、萨姆达尔,挪威科技大学(NTNU),斯塔万格大学,挪威科技大学(NTNU)
<摘要>
本文研究了交易最活跃的VIX交易所交易产品(ETP),重点关注其表现、价格发现、对冲能力和交易策略。VIX ETP很好地跟踪了它们的基准指数。因此,它们与这些指数一样,都面临时间衰减(高负预期回报)。这使得它们不适合买入并持有投资,但却产生了一种利润丰厚的交易策略。尽管与标普500指数呈负相关,但ETP作为对冲工具的表现很差;将它们纳入基于标普500指数的投资组合会降低投资组合的风险调整后表现。


IV. 回测表现
| 年化回报 | 69% |
| 波动率 | 39% |
| β值 | -0.243 |
| 夏普比率 | 2.11 |
| 索提诺比率 | 0.239 |
| 最大回撤 | -24.5% |
| 胜率 | 53% |
V. 完整的 Python 代码
from QuantConnect.Python import PythonQuandl
from AlgorithmImports import *
class TradingVIXETFsv2(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.vixy = self.AddEquity('VIXY', Resolution.Minute).Symbol
# Vix futures data.
self.vix_future = self.AddFuture(Futures.Indices.VIX, Resolution.Minute)
# Vix spot.
self.vix_spot = self.AddData(CBOE, 'VIX', Resolution.Daily).Symbol
self.vix_future.SetFilter(timedelta(0), timedelta(30))
# Vix futures active contract updated on expiration.
self.active_contract = None
self.Schedule.On(self.DateRules.EveryDay(self.vixy), self.TimeRules.AfterMarketOpen(self.vixy, 1), self.Rebalance)
def Rebalance(self):
# split data error prevention
if self.Time.year == 2021 and self.Time.month == 5:
self.Liquidate()
return
if self.active_contract:
if self.Securities.ContainsKey(self.vix_spot):
spot_price = self.Securities[self.vix_spot].Price
vix_future_price = self.active_contract.LastPrice
if spot_price == 0 or vix_future_price == 0:
return
relative_basis = vix_future_price / spot_price
# BU 8%, SU 6%, BL -8%, SL -6% thresholds.
# Short volatility.
if relative_basis > 1.08:
if not self.Portfolio[self.vixy].IsShort and self.Securities[self.vixy].Price != 0:
self.SetHoldings(self.vixy, -1)
if relative_basis >= 1.06 and relative_basis <= 1.08 and self.Portfolio[self.vixy].IsLong:
self.Liquidate(self.vixy)
if relative_basis < 1.06 and relative_basis > 0.94:
if self.Portfolio[self.vixy].Invested:
self.Liquidate(self.vixy)
if relative_basis <= 0.94 and relative_basis >= 0.92 and self.Portfolio[self.vixy].IsShort:
self.Liquidate(self.vixy)
# Long volatility.
if not self.Portfolio[self.vixy].IsLong and relative_basis < 0.92:
if self.Securities[self.vixy].Price != 0:
self.SetHoldings(self.vixy, 1)
def OnData(self, slice):
chains = [x for x in slice.FutureChains]
cl_chain = None
if len(chains) > 0:
cl_chain = chains[0]
else:
return
if cl_chain.Value.Contracts.Count >= 1:
contracts = [i for i in cl_chain.Value]
contracts = sorted(contracts, key = lambda x: x.Expiry)
near_contract = contracts[0]
self.active_contract = near_contract