Quant Buffet放轻松,别过度思虑

交易VIX交易所交易基金(VIX ETFs)

登录后收藏

学术论文

Easy Volatility Investing

作者简单波动率投资 [点击查看论文]

机构
  • ?Double-Digit Numerics

策略概要

该策略投资于4种波动率交易所交易票据(ETNs)(XIV、VXX、ZIV、VXZ),每日根据其83天动量对其进行排名。投资者持有过去83天表现最高的正表现交易所交易票据(ETN),前提是该表现为正。如果没有任何交易所交易票据(ETN)具有正表现,则投资组合保持未分配状态。交易信号每日检查,投资组合相应地进行再平衡,以确保与基于动量的策略保持一致。这种方法旨在通过优先考虑表现最佳的资产,同时避免那些具有负动量的资产,来捕捉波动率交易所交易票据(ETNs)的趋势,从而确保一个纪律性和动态性的投资过程。

II. 策略合理性

波动率溢价由时变投资者效用理论解释,该理论指出,投资者重视在危机期间表现良好的策略。长期波动率敞口提供危机保护,但带有负风险溢价。相反,做空波动率提供正风险溢价,但由于其高偏度,使投资者在危机期间面临极端损失。动量过滤器策略通过根据当前趋势在多空波动率敞口之间动态切换来解决这个问题,使投资者能够在危机期间获得波动率溢价,同时减轻严重负回报的风险。

回测表现

波动率51.2%
夏普比率1.57
索提诺比率0.14
最大回撤-43.2%
胜率55%

完整 Python 代码

from AlgorithmImports import *
class TradingVIXETFs(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.symbols = ["SVXY", "VXX", "ZIV", "VXZ"]
self.data = {}
self.period = 83
self.SetWarmUp(self.period)
for symbol in self.symbols:
    data = self.AddEquity(symbol, Resolution.Daily)
    self.data[symbol] = RollingWindow[float](self.period)
def OnData(self, data):
for symbol in self.data:
    symbol_obj = self.Symbol(symbol)
    if symbol_obj in data.Keys:
        if data[symbol_obj]:
            price = data[symbol_obj].Value
            if price != 0:
                self.data[symbol].Add(price)

if self.IsWarmingUp: return
self.Liquidate()
returns = {}
for symbol in self.symbols:
    if self.data[symbol].IsReady:
        prices = [x for x in self.data[symbol]]
        returns[symbol] = prices[0] / prices[-1] - 1

if len(returns) != 0:
    sorted_by_return = sorted(returns.items(), key = lambda x: x[1], reverse = True)
    
    symbols = [x[0] for x in sorted_by_return]
    top_symbol = symbols[0]
    top_val = returns[top_symbol]

    # if self.Portfolio.Invested:
    #     if not self.Securities[top_symbol].Invested:
    #         self.Liquidate()
    #         if top_val > 0:
    #             self.SetHoldings(top_symbol, 1/2)
    # else:
    #     self.SetHoldings(top_symbol, 1/2)
    
    if top_val > 0:
        if self.Securities[top_symbol] != 0:
            self.SetHoldings(top_symbol, 1/2)