---
title: "3.6.3 VIX and VSTOXX strategies: futures and ETPs"
description: "VIX and VSTOXX futures, the curve and roll yield, the short-term futures index and two ETPs: a long one that loses 99% and an inverse one that blows up."
url: "https://pythonparatrading.com/en/python-trading-course/level-3/vix-and-vstoxx-strategies/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-3/vix-and-vstoxx-strategies.png"
---

# 3.6.3 · VIX and VSTOXX strategies: volatility futures and ETPs

> The VIX is a calculation, not an asset: what trades are futures that converge to it and exchange-traded products that roll those futures every day. This lesson rebuilds with the course data the curve, the short-term futures index and two ETPs, a long one that loses 99.4% in twelve years and an inverse one that disappears in a single session, and measures what is left of volatility-selling strategies when you look at their worst day.

- Course: [Level 3: Derivatives: futures, spreads, forex and options](https://pythonparatrading.com/en/python-trading-course/level-3/)
- Module: 3.6 · Systematic volatility and options strategies
- Duration: 70 min
- Prerequisites: [3.1.2 · Futures curve: basis, cost of carry, contango and roll yield](https://pythonparatrading.com/en/python-trading-course/level-3/futures-curve-basis-contango-roll-yield/), [3.4.6 · Realized vs implied volatility; volatility risk premium; VIX and VSTOXX](https://pythonparatrading.com/en/python-trading-course/level-3/realized-vs-implied-volatility-vix/), [3.6.1 · Systematic premium selling: put-write, strangles and their tail risk](https://pythonparatrading.com/en/python-trading-course/level-3/systematic-premium-selling-tail-risk/)

## By the end of this lesson

- Explain why the VIX and the VSTOXX cannot be bought and how their futures settle, with the Cboe and Eurex rules.
- Measure the term structure of volatility futures, contango and roll yield, and test whether the basis predicts the future or the index.
- Rebuild a short-term volatility futures index and a long and an inverse ETP from the futures, and explain the 99.4% loss of the long one and the liquidation of the inverse one.
- Evaluate volatility-selling and volatility-buying strategies with their worst episode, their sensitivity to signal delay and the rebalancing that leveraged products are forced into.

## An index that cannot be bought

The Cboe VIX measures the 30-day expected volatility of the S&P 500 with the prices of a strip of its options, with
the variance formula that lesson 3.4.6 applies to the VORX of the course data. Cboe launched it in 1993 on S&P 100
options and changed it in 2003 to the current formula, according to its methodology. The VSTOXX is the European
equivalent, on Euro Stoxx 50 options.

Neither of the two can be bought. To hold “the VIX” you would need a basket of 30-day options that changes strikes and
expirations every day; it is not a portfolio you buy and keep. What trades are **futures** on the index and, on top of
them, exchange-traded products (ETPs: funds and notes) that hold a position in those futures and roll it. Each layer
adds a difference from the index the investor believes they are buying.

```mermaid
flowchart TB
  O[30 d options] --> V[Spot VIX]
  V -. settles .-> F[VX futures]
  F --> I[Futures index]
  I --> L[Long ETP]
  I --> N[Inverse ETP]
```

The actual rules of the futures, from their primary sources:

| | VIX futures (Cboe, VX) | VSTOXX futures (Eurex, FVS) |
|---|---|---|
| Multiplier | 1,000 USD per point | 100 EUR per point |
| Tick | 0.05 points (50 USD) | 0.05 points (5 EUR) |
| Final settlement | The Wednesday 30 days before the third Friday of the following month | 30 calendar days before the expiration of the underlying options |
| Settlement price | SOQ: the VIX calculated with that day's opening option prices | Average of the index between 11:00 and 12:00 CET on the last day |
| Settlement | Cash | Cash |

The date of both comes from the same idea: 30 days before the options used to calculate the index expire, so that on
settlement day the index depends on a single 30-day expiration. The SOQ (Special Opening Quotation) is not that
morning's VIX: it is calculated with the opening prices of a special auction of S&P 500 options, with its own rules
(for example, it admits strikes with a zero bid), according to section 3.4 of the Cboe methodology. In the course data
the VORX futures expire on the Wednesday 30 days before the third Friday of the following month, like the VX, and
settle at that day's VORX close (a simplification).

## The VORX futures curve

The data are synthetic (`public/curso/datos/nivel-3/README.md`): `vol3_indices.csv` with VORX, which mimics the VIX
and is recalculated exactly with the Cboe formula from the ORX chain (lesson 3.4.6), and VVGX, which mimics the
VSTOXX; `vol3_futuros.parquet` with eight monthly futures on VORX, and `vol3_etp.csv` with the short-term futures
index and two ETPs. The futures model is the expectation of VORX at its expiration under the pricing measure, plus
today's difference between VORX and its model, which fades with the future's time to expiration (a 10-day time
constant). And it has a planted episode: on 2018-02-05 the first two futures settle 22% above their model value, like
the inverse ETPs' buying in the settlement window, and it unwinds the next day.

```python
import numpy as np
import pandas as pd

vi = pd.read_csv("vol3_indices.csv", parse_dates=["fecha"])
vi = vi.set_index("fecha")
fu = pd.read_parquet("vol3_futuros.parquet")
fu = fu.sort_values(["fecha", "vencimiento"])
fu["orden"] = fu.groupby("fecha").cumcount()   # 0 = the first
vx = vi["vorx"]
print(vx.describe().round(2).to_dict())
curvas = {d: fu[fu["fecha"] == d].set_index("dias")["precio"]
          for d in ("2017-06-14", "2020-03-16")}
for d, c in curvas.items():
    print(d, "VORX", vx[d], "|", c.to_dict())
```
```output
{'count': 3018.0, 'mean': 19.8, 'std': 8.51, 'min': 9.55, '25%': 14.23, '50%': 17.66, '75%': 22.83, 'max': 73.98}
2017-06-14 VORX 11.05 | {7: 12.3, 35: 15.05, 63: 16.4, 98: 17.3, 126: 17.8, 154: 18.3, 189: 18.6, 217: 19.0}
2020-03-16 VORX 73.09 | {2: 71.45, 30: 51.35, 65: 37.9, 93: 31.35, 128: 26.8, 156: 25.15, 184: 24.2, 219: 23.7}
```

*Fig. — VORX futures curve in calm (2017-06-14) and in crisis (2020-03-16); the point at day 0 is spot VORX (synthetic data).* Two curves with points. In calm, VORX is 11.05 and futures rise from 12.30 at 7 days to 19.00 at 217 days: contango. In crisis, highlighted, VORX is 73.09 and futures fall from 71.45 at 2 days to 23.70 at 219: backwardation.

The two snapshots are the two shapes of the curve. On 14 June 2017, with VORX at 11.05, the 7-day future trades at
12.30 and the 217-day one at 19.00: **contango**, each expiration more expensive than the previous one, because low
volatility is expected to return to its higher mean. On 16 March 2020, with VORX at 73.09, the curve falls from 71.45
to 23.70: **backwardation**, because the crisis is expected to pass. Measured over the whole sample:

```python
f1 = fu[fu["orden"] == 0].set_index("fecha")
f2 = fu[fu["orden"] == 1].set_index("fecha")
print(f"first future above VORX: "
      f"{(f1['precio'] > vx).mean():.1%} of sessions")
print(f"second above the first: "
      f"{(f2['precio'] > f1['precio']).mean():.1%}; mean "
      f"difference {(f2['precio'] / f1['precio'] - 1).mean():.1%}")
venc = fu[fu["fecha"] == fu["vencimiento"]].set_index("fecha")
dif = (venc["precio"] - vx.reindex(venc.index)).abs()
print(f"{len(venc)} expirations; |future − VORX| at expiry: "
      f"max. {dif.max():.3f}")
```
```output
first future above VORX: 62.8% of sessions
second above the first: 71.1%; mean difference 4.4%
144 expirations; |future − VORX| at expiry: max. 0.000
```

The three figures of the README's known answer (63%, 71% and 4.4%) come out exactly, and the 144 expirations settle
at that day's VORX. Convergence is the key to everything that follows: a future in contango has to fall to the index
or the index has to rise to it before expiration. Which of the two moves?

## Roll yield: does the future converge or the index?

The **daily roll** of a future is its basis spread over the days it has left: $(F - \text{VORX}) / \text{days}$. If
the basis were an unbiased prediction of the index, the index would rise on average by what the roll says and the
future would not move. If it is a premium, the future would fall toward the index and the index would not move
predictably. The regression of the next day's changes on the roll, with the first future at 10 days or more and
autocorrelation-robust errors (Newey-West with 5 lags):

```python
import statsmodels.api as sm

fu["siguiente"] = fu.groupby("contrato")["precio"].shift(-1)
g = fu[(fu["orden"] == 0) & (fu["dias"] >= 10)].set_index("fecha")
g = g.assign(roll=(g["precio"] - vx.reindex(g.index)) / g["dias"],
             d_futuro=g["siguiente"] - g["precio"],
             d_vorx=(vx.shift(-1) - vx).reindex(g.index)).dropna()
for y in ("d_futuro", "d_vorx"):
    m = sm.OLS(g[y], sm.add_constant(g["roll"])).fit(
        cov_type="HAC", cov_kwds={"maxlags": 5})
    print(f"{y:9}: coefficient {m.params['roll']:6.2f}, "
          f"t {m.tvalues['roll']:5.1f}, R² {m.rsquared:.3f}")
```
```output
d_futuro : coefficient  -1.56, t  -4.3, R² 0.024
d_vorx   : coefficient   0.42, t   1.0, R² 0.001
```

The change in the future has a coefficient of −1.56 on the roll (t = −4.3): in contango the future falls toward the
index and in backwardation it rises. The change in VORX has no significant relationship with the roll (t = 1.0). It is
what Simon and Campasano (2014) find in the real VIX from 2006 to 2011: the basis does not predict the spot VIX but it
does predict the change in the futures. For whoever holds long futures, contango is a cost paid every day; for whoever
sells them, a premium. The R² are small (2.4% for the future) because the daily volatility of the futures is much
larger than the roll: the premium exists, but it is collected amid a lot of noise and the occasional jump.

## The short-term futures index and the long ETP

A product that wants “30-day volatility” holds a mix of the first and second futures that shifts a little weight from
the first to the second every day, so that the average maturity stays around one month. It is the construction of the
S&P 500 VIX Short-Term Futures Index, which the prospectus of the first ETN on it describes as a long position that
rolls daily between the first and second monthly futures[^1]. In the data, `indice_futuros_cp` follows the same rule:
the weight of the first future is the fraction of sessions of the roll period (from one expiration to the next) left
until its expiration. Rebuilding it from the futures is the proof that it is understood:

```python
etp = pd.read_csv("vol3_etp.csv", parse_dates=["fecha"])
etp = etp.set_index("fecha")
tabla = fu.pivot(index="fecha", columns="vencimiento",
                 values="precio")
vencs, ses = sorted(fu["vencimiento"].unique()), tabla.index
rend = [0.0]
for t in range(len(ses) - 1):
    hoy, man = ses[t], ses[t + 1]
    e1 = next(v for v in vencs if v > hoy)      # first future
    e2 = next(v for v in vencs if v > e1)       # second
    previos = [v for v in vencs if v <= hoy]
    e0 = max(previos) if previos else e1 - pd.Timedelta(days=35)
    w1 = (((ses > hoy) & (ses <= e1)).sum()
          / ((ses > e0) & (ses <= e1)).sum())  # weight of the first
    a0 = w1 * tabla.at[hoy, e1] + (1 - w1) * tabla.at[hoy, e2]
    a1 = w1 * tabla.at[man, e1] + (1 - w1) * tabla.at[man, e2]
    rend.append(a1 / a0 - 1)
rend = pd.Series(rend, ses)
indice = 100 * (1 + rend).cumprod()
print(f"maximum difference with the file: "
      f"{(indice - etp['indice_futuros_cp']).abs().max():.5f}")
print(f"index: 100 on {ses[0].date()}, "
      f"{indice.iloc[-1]:.2f} on {ses[-1].date()}")
```
```output
maximum difference with the file: 0.00005
index: 100 on 2014-01-02, 0.49 on 2025-12-31
```

The maximum difference is five hundred-thousandths: the file's rounding to four decimals. The futures index falls
from 100 to 0.49 in twelve years. It is the roll in contango accumulated session after session: every day a little of
the first future, which has fallen toward the index, is sold and the second, more expensive one, is bought.

The long ETP (`lvol`, which mimics the VXX) adds to the index the 3-month rate on its collateral and subtracts an
annual fee of 0.89%, the one set by the VXX prospectus[^1]. With that rule it can also be rebuilt, and the result by
year is this:

```python
ind = pd.read_csv("opciones3_indice.csv", parse_dates=["fecha"])
tb = ind.set_index("fecha")["tipo_3m"] / 100
largo = [100.0]
for t in range(len(ses) - 1):
    largo.append(largo[-1] * (1 + rend.iloc[t + 1]
                              + tb.iloc[t] / 252 - 0.0089 / 252))
largo = pd.Series(largo, ses)
print(f"maximum difference with lvol: "
      f"{(largo - etp['lvol']).abs().max():.5f}")
print(f"total 2014-2025: {largo.iloc[-1] / 100 - 1:.1%}")
anual = etp[["lvol", "ivol"]].resample("YE").last()
anual.loc[pd.Timestamp("2013-12-31")] = 100.0
anual = anual.sort_index().pct_change().iloc[1:]
anual.index = anual.index.year
(100 * anual).round(0).T
```
```output
maximum difference with lvol: 0.00005
total 2014-2025: -99.4%
fecha  2014  2015  2016  2017  2018  2019   2020  2021  2022  2023  2024  2025
lvol  -48.0  11.0 -34.0 -57.0  44.0 -85.0  114.0 -75.0  61.0 -61.0 -54.0  -4.0
ivol   45.0 -44.0  10.0  96.0 -91.0   NaN    NaN   NaN   NaN   NaN   NaN   NaN
```

The header figure is this table over time, on a logarithmic scale. The long ETP loses 99.4% in total, with years of
−85% (2019) and −75% (2021), those following a crisis, when VORX falls from high levels and the curve returns to
contango, and strong gains in crisis years (+114% in 2020). Holding it is paying for expensive insurance; whoever buys
it as a hedge has to get the timing right.

<aside class="callout" data-kind="aviso">

A long volatility product is not “the VIX”. Between the two lie the contango of the curve, paid every day, and the
fee. In these data VORX starts and ends at similar levels (13.42 on 2 January 2014 and 13.74 on 31 December 2025, in
the next cell) while the long ETP loses 99.4%.

</aside>

## 5 February 2018 and the inverse ETP

The daily inverse ETP (`ivol`, which mimics the XIV) delivers each day −1 times the return of the futures index, plus
the rate and minus a 1.35% fee. While the curve is in contango, it earns what the long one loses: it goes from 100 to
221. And it has an acceleration clause: if it loses more than 80% in one day, it is liquidated. The one in the data
mimics that of the real XIV: according to Credit Suisse's notice to the SEC of 6 February 2018, the intraday
indicative value of the XIV on 5 February fell to 20% or less of the previous close, which constituted an acceleration
event; the last trading day would be 20 February and holders would receive the closing indicative value of the
valuation date.

```python
dias = pd.concat([vx.rename("vorx"),
                  f1["precio"].rename("f1"), f2["precio"].rename("f2"),
                  etp], axis=1).loc["2018-01-31":"2018-02-08"]
dias["rend_indice"] = dias["indice_futuros_cp"].pct_change()
print(f"VORX at the end of the sample: {vx.iloc[-1]}")
dias.round(3)
```
```output
VORX at the end of the sample: 13.74
             vorx     f1     f2  indice_futuros_cp    lvol     ivol  rend_indice
fecha
2018-01-31  15.96  16.00  16.65             14.401  14.121  201.189          NaN
2018-02-01  17.44  17.15  16.95             15.041  14.748  192.256        0.044
2018-02-02  20.37  19.45  18.05             16.488  16.168  173.754        0.096
2018-02-05  36.78  41.65  31.45             31.479  30.868   15.780        0.909
2018-02-06  37.46  35.10  26.40             26.468  25.955      NaN       -0.159
2018-02-07  36.74  34.70  26.45             26.390  25.880      NaN       -0.003
2018-02-08  37.04  35.25  26.85             26.795  26.278      NaN        0.015
```

On 2 February the futures index already rises 9.6%. On Monday the 5th VORX goes from 20.37 to 36.78 and the first
future from 19.45 to 41.65, above the index itself: it is the planted 22% rise over the model. The futures index rises
90.9% in one day, the inverse ETP falls from 173.75 to 15.78 and is liquidated; from the 6th its series is empty. The
long one, which almost doubles its value that day, gives back part of it the next day, when the planted rise unwinds.

Why would the futures rise more than the index precisely that day? Because of the rebalancing of the products
themselves. An ETP with daily leverage $L$ and value $A$ has an exposure $L \cdot A$. If its index rises by $x$, its
value becomes $A(1 + Lx)$ and its exposure is worth $LA(1 + x)$; to return to $L$ times its new value it has to trade

$$
L A (1 + L x) - L A (1 + x) = L (L - 1)\, x\, A .
$$

For $L = 1$ it does not trade; for $L = 2$ or $L = -1$, $L(L-1) = 2 > 0$: both **buy** after a rally, and both do it
at the close, when the price of their index is set.

```python
x = dias.loc["2018-02-05", "rend_indice"]
filas = {L: {"valor_tras_subida": 100 * (1 + L * x),
             "compra_de_futuros": 100 * L * (L - 1) * x}
         for L in (-1.0, -0.5, 1.0, 1.5, 2.0)}
pd.DataFrame(filas).T.round(1)
```
```output
      valor_tras_subida  compra_de_futuros
-1.0                9.1              181.8
-0.5               54.5               68.2
 1.0              190.9                0.0
 1.5              236.4               68.2
 2.0              281.8              181.8
```

```mermaid
flowchart TB
  S[Vol rises] --> F[Futures rise]
  F --> P[Inverse ETPs lose]
  P --> R[They buy back]
  R --> F
  P --> A{Loses 80%}
  A -- yes --> Q[Liquidated]
```

For every 100 of value before the rally, a −1× inverse has to buy back 181.8 of futures, 20 times what it has left in
value (9.1). A −0.5× product has to buy back 68.2 and survives with 54.5. That is why ProShares changed its SVXY from
−1× to −0.5× at the close of 27 February 2018, according to the fund's own fact page. When the size of those products
is large relative to futures volume in the closing window, the buying pushes the price, the rise increases the losses
and forces more buying back. In the data that pressure is planted as the 22% over the model; in the real market its
size is a figure to be estimated, not assumed.

## Strategies: selling, buying and filtering volatility

With the daily returns of the futures index the basic strategies can be compared, all on notional (selling 1 of
futures for each 1 of capital, which stays as collateral; the return in excess of the collateral is measured).
Always selling is the inverse ETP without fees and without the acceleration clause; at −0.5×, the post-2018 SVXY; and
the **contango filter** only sells when, at the previous close, the first future is above VORX:

```python
def medidas(x):
    x = x.iloc[1:]
    eq = (1 + x).cumprod()
    mes = (1 + x).resample("ME").prod() - 1
    return {"anual": eq.iloc[-1] ** (252 / len(x)) - 1,
            "vol": x.std() * np.sqrt(252),
            "sharpe": x.mean() / x.std() * np.sqrt(252),
            "caida_max": (eq / eq.cummax() - 1).min(),
            "peor_dia": x.min(), "peor_mes": mes.min(),
            "fecha_peor_dia": str(x.idxmin().date())}

corto = -rend
contango = (f1["precio"] > vx).reindex(ses).astype(float)
estr = {"always sell": corto, "sell at -0.5x": 0.5 * corto}
for lag in (1, 2, 3):
    estr[f"contango, signal t-{lag}"] = corto * contango.shift(lag)
cambios = contango.shift(1).diff().abs()
estr["contango t-1, cost 0.5%"] = (corto * contango.shift(1)
                                   - 0.005 * cambios)
print(f"entries and exits per year: {cambios.sum() / 12:.0f}")
tab = pd.DataFrame({k: medidas(v.fillna(0)) for k, v in estr.items()}).T
num = tab.columns[:-1]
tab[num] = tab[num].astype(float).round(3)
tab
```
```output
entries and exits per year: 33
                         anual    vol  sharpe  caida_max  peor_dia  peor_mes fecha_peor_dia
always sell             -0.071  0.592   0.502     -0.989    -0.921    -0.964     2020-03-09
sell at -0.5x            0.101  0.296   0.502     -0.715    -0.460    -0.628     2020-03-09
contango, signal t-1     0.813  0.314   2.058     -0.433    -0.373    -0.332     2016-06-24
contango, signal t-2     0.784  0.313   2.016     -0.456    -0.373    -0.368     2016-06-24
contango, signal t-3     0.281  0.419   1.022     -0.937    -0.909    -0.923     2018-02-05
contango t-1, cost 0.5%  0.522  0.315   1.499     -0.506    -0.373    -0.342     2016-06-24
```

Always selling gives a Sharpe of 0.50 and a maximum drawdown of 98.9%: the earlier inverse ETP, without its
liquidation. The worst day is 2020-03-09 (−92.1%) and the worst month, March 2020 (−96.4%): whoever sold at 1× would
have lost practically everything twice in the sample. At −0.5× the maximum drawdown is still 71.5%. Selling volatility
futures is the premium selling of lesson 3.6.1 with an even fatter tail: what is collected is the roll, and what is
risked is a 90% jump in one session.

*Fig. — Short VORX futures index, monthly wealth on a log scale: always, with the contango filter from the previous close and with the same filter three sessions later (synthetic data, no costs).* Three lines from 1 in 2014. Always short reaches 2.1 and falls to 0.02 in 2018 and again in 2020; ends at 0.41. The filter with the previous day's signal rises almost without pause to 1,236. The same filter three sessions late, highlighted, tracks it until January 2018, falls 91% in February and ends at 19.

The contango filter with the previous close's signal gives a Sharpe of 2.06 and a maximum drawdown of 43.3%, with the
worst day on 2016-06-24. It is too good, and the table says why: with the signal from two sessions earlier it barely
changes, but with the one from three sessions earlier it sells on 2018-02-05, loses 90.9% that day and its maximum
drawdown goes to 93.7%. The filter works in these data because, in the two big VORX jumps in the sample, the spot index
rises one or two days before the futures and the curve inverts just in time to exit. It is a property of how the data
are generated (VORX departs from its model and the difference fades with a 10-day time constant), not a law of the
market. With a cost of 0.5% of notional each time the position is opened or closed (about 33 times a year), the Sharpe
falls to 1.50 and the maximum drawdown rises to 50.6%.

<aside class="callout" data-kind="riesgo">

A result that goes from a 43% drawdown to a 94% one by looking at the signal one day later is not proven: it is fitted
to two or three episodes. Before selling volatility with any filter, the backtest has to show the worst day with the
delayed signal, the costs of entering and exiting, and what happens with a jump that gives no warning. The course's
synthetic data are not evidence that a filter works on the real VIX.

</aside>

The other side is buying volatility as insurance. A portfolio that holds a part in the long ETP and the rest in the ORX
index with dividends, rebalanced every month:

```python
rt = ind.set_index("fecha")["cierre_rt"]
mens = (pd.concat([rt, etp["lvol"]], axis=1).resample("ME").last()
        .pct_change().dropna())
seguro = {}
for w in (0.0, 0.05, 0.10):
    p = (1 - w) * mens["cierre_rt"] + w * mens["lvol"]
    eq = (1 + p).cumprod()
    seguro[f"{w:.0%} in LVOL"] = {
        "anual": eq.iloc[-1] ** (12 / len(p)) - 1,
        "vol": p.std() * np.sqrt(12),
        "caida_max": (eq / eq.cummax() - 1).min(),
        "peor_mes": p.min()}
pd.DataFrame(seguro).T.round(3)
```
```output
             anual    vol  caida_max  peor_mes
0% in LVOL   0.122  0.187     -0.366    -0.288
5% in LVOL   0.116  0.157     -0.269    -0.269
10% in LVOL  0.106  0.146     -0.249    -0.249
```

With 10% in the long ETP, the portfolio's maximum drawdown falls from 36.6% to 24.9% and the worst month from −28.8%
to −24.9%. In exchange, the annual return falls from 12.2% to 10.6%: 1.6 points a year for twelve years to trim the
worst drawdown. The insurance works because it is rebalanced every month (what rises in crises is sold) and because
the crises in the sample were short; with a slow crisis, without volatility jumps, the cost is paid all the same and
the hedge barely shows up.

## VSTOXX and VIX: what can be compared

The VVGX in the data mimics the VSTOXX: the 30-day volatility of a fictitious European index with a variance 1.2 times
that of ORX, returns correlated 0.8 with it and its own noise. There is only the index: no option chain and no
futures.

```python
dif = vi["vvgx"] - vi["vorx"]
print(f"correlation of levels: {vi['vorx'].corr(vi['vvgx']):.3f}; "
      f"of daily changes: "
      f"{vi['vorx'].diff().corr(vi['vvgx'].diff()):.3f}")
print(f"VVGX − VORX: mean {dif.mean():.2f}, std. {dif.std():.2f},"
      f" from {dif.min():.2f} to {dif.max():.2f} points")
vi[["vorx", "vvgx"]].describe().loc[["mean", "50%", "max"]].round(2)
```
```output
correlation of levels: 0.992; of daily changes: 0.964
VVGX − VORX: mean 1.50, std. 1.22, from -3.89 to 6.97 points
       vorx   vvgx
mean  19.80  21.31
50%   17.66  19.05
max   73.98  72.48
```

The European index trades on average 1.5 points above the US one, with a correlation of levels of 0.99. With a
differential like that, a **volatility spread** is often proposed: buying VSTOXX futures and selling VIX futures when
the differential is low, or the other way around. With these data it cannot be tested, for three reasons: there are
no VVGX futures; the futures of the two exchanges expire on different dates (each 30 days before the expiration of its
options) and settle with different methods (the Cboe SOQ versus the Eurex 11:00 to 12:00 CET average); and the
multiplier and the currency change (1,000 USD versus 100 EUR per point), so the hedge needs a ratio and leaves
currency risk (lesson 3.3.3).

## Exercises

1. Compute a daily 2× long ETP on the futures index (without fee or rate) and compare it with twice the return of the
   index over the whole period. Why do they not match?

**Solution.**

```python
doble = (1 + 2 * rend).cumprod()
print(f"index over the period: {indice.iloc[-1] / 100 - 1:.2%}")
print(f"daily 2x: {doble.iloc[-1] - 1:.2%}")
print(f"2x of the period (impossible below -100%): "
      f"{2 * (indice.iloc[-1] / 100 - 1):.2%}")
print(f"maximum of the daily 2x: {doble.max():.2f} on "
      f"{doble.idxmax().date()}")
```
```output
index over the period: -99.51%
daily 2x: -100.00%
2x of the period (impossible below -100%): -199.02%
maximum of the daily 2x: 1.08 on 2014-04-22
```

The daily 2× ends up practically at zero (its maximum, 1.08, was in April 2014). It multiplies each daily return by 2,
not that of the period. With a very volatile index trending down, the product of the $(1 + 2r_t)$ falls much faster
than the index: the volatility drag grows with the square of the leverage. That is why the prospectuses of these
products say their objective is for a single day.

2. Repeat the roll yield regression with the second future (`orden == 1`). Is the coefficient larger or smaller than
   for the first?

**Solution.**

```python
g2 = fu[fu["orden"] == 1].set_index("fecha")
g2 = g2.assign(roll=(g2["precio"] - vx.reindex(g2.index))
               / g2["dias"],
               d_futuro=g2["siguiente"] - g2["precio"]).dropna()
m2 = sm.OLS(g2["d_futuro"], sm.add_constant(g2["roll"])).fit(
    cov_type="HAC", cov_kwds={"maxlags": 5})
print(f"coefficient {m2.params['roll']:.2f}, "
      f"t {m2.tvalues['roll']:.1f}")
```
```output
coefficient -1.48, t -4.3
```

The coefficient is similar (−1.48 versus −1.56, both with t = −4.3): the second future also falls with its roll. Its
basis against spot VORX is, even so, a more indirect measure, because it has more than 30 days left to converge and
first takes the place of the first future; with so little difference between the two coefficients, the data do not
allow saying that one is larger than the other.

3. An investor wants to “buy the VIX” because they believe there will be a crisis at some point in the next three
   years and proposes holding a long volatility ETP. Explain what will happen to them if they are right about the
   crisis but not about the timing.

**Solution.**

The long ETP does not track the VIX: it tracks a futures index that rolls in contango. While the crisis does not
arrive, it loses a large fraction of its value every year (in the course data, between 4% and 85% in the years it
falls). If the crisis arrives in the third year, the ETP rises a lot in percentage terms, but on a value that has
already lost most of itself: in the data, after losing 85% in 2019, the +114% of 2020 leaves the ETP far below where it
was at the start of 2019. The alternative consistent with their idea is to buy long-dated options (calls on volatility
futures or index puts), whose cost is known when they are bought, or to hold a small rebalanced part as in this
lesson's portfolio.

[^1]: Barclays Bank PLC, free writing prospectus of the iPath S&P 500 VIX Short-Term Futures ETN (VXX), 2 December
    2009, at the SEC:
    <https://www.sec.gov/Archives/edgar/data/312070/000119312509245713/dfwp.htm>. It describes the index as a long
    position that rolls daily from the first to the second VIX monthly future, with a constant one-month maturity, and
    an annual fee of 0.89%.

## Self-assessment

1. Why is there no ETP that replicates the spot VIX?

   - A. Because the SEC prohibits it
   - B. Because the VIX is only calculated once a day
   - C. Because the VIX is a calculation on 30-day S&P 500 option prices that cannot be held as a static portfolio: what can be replicated are the futures, which converge to it only at expiration
   - D. Because S&P 500 options are not liquid enough

   *Answer C: Because the VIX is a calculation on 30-day S&P 500 option prices that cannot be held as a static portfolio: what can be replicated are the futures, which converge to it only at expiration.* The VIX measures 30-day expected volatility with a basket of options that changes every day (strikes and expirations). Exchange-traded products hold futures, and a VIX future is worth the expectation of the VIX at its expiration, not today's VIX.

2. In the data, the first future is above VORX in 63% of sessions. What happens on average to whoever holds a long position in the first future?

   - A. They earn the roll yield, because the future rises toward the index
   - B. Nothing: future and index move the same
   - C. They win only if the index rises
   - D. They lose: in contango the future tends to fall toward the index as expiration nears, and the lesson's regression gives a coefficient of −1.56 on the daily roll, while the index does not move predictably

   *Answer D: They lose: in contango the future tends to fall toward the index as expiration nears, and the lesson's regression gives a coefficient of −1.56 on the daily roll, while the index does not move predictably.* The basis predicts the change in the future (t = −4.3) and not that of the index (t = 1.0). It is the same conclusion Simon and Campasano (2014) draw from the real VIX from 2006 to 2011: the basis is above all a premium collected by selling futures in contango.

3. A daily inverse ETP (−1×) has a value of 100 and its index rises 90.9% in one day. How much of the index does it have to buy back at the close to return to −1×?

   - A. Nothing: inverse products do not rebalance
   - B. 181.8: the short position is now worth 190.9 and the target is 9.1; buying back means buying futures right after the rally
   - C. 9.1, what it has left in value
   - D. 90.9

   *Answer B: 181.8: the short position is now worth 190.9 and the target is 9.1; buying back means buying futures right after the rally.* With leverage L, the rebalancing purchase is L·(L − 1)·x per unit of value. With L = −1 and x = 0.909, 2·0.909 = 1.818 times the previous value. Inverse and leveraged products buy after rallies, which pushes the price in the same direction.

4. Selling the futures index only when the first future is in contango gives a Sharpe of 2.06 in the data. What invalidates it as evidence?

   - A. That with the signal from three sessions earlier instead of yesterday's it drops 90.9% on 2018-02-05 and its maximum drawdown goes from 43% to 94%: the result depends on dodging by one or two days a jump planted in synthetic data
   - B. Nothing: the contango filter works
   - C. That the Sharpe is computed with daily returns
   - D. That it does not include the index dividend

   *Answer A: That with the signal from three sessions earlier instead of yesterday's it drops 90.9% on 2018-02-05 and its maximum drawdown goes from 43% to 94%: the result depends on dodging by one or two days a jump planted in synthetic data.* A result that changes radically with one or two days of delay is fitted to a few episodes. In the synthetic data, VORX rises before the jumps and the curve inverts one day earlier; in a real market nothing guarantees that warning, and selling volatility is still short the tail.

5. What do the course data allow you to do with the VSTOXX?

   - A. Compare its level with that of VORX (the VVGX index), but not backtest its futures: the file only has the index
   - B. Backtest its futures, like those of VORX
   - C. Nothing, there are no European data
   - D. Rebuild the VSTOXX from Euro Stoxx 50 options

   *Answer A: Compare its level with that of VORX (the VVGX index), but not backtest its futures: the file only has the index.* `vol3_indices.csv` has `vvgx`, the 30-day volatility of a fictitious European index, with no chain or futures. The rules of VSTOXX futures (Eurex, FVS) can be explained, but not tested with these data.

## Key points

- The VIX and the VSTOXX are calculated with 30-day options and cannot be held in a portfolio; what trades are futures that settle to the index at expiration (Cboe: Special Opening Quotation; Eurex: average from 11:00 to 12:00 CET).
- The futures curve is in contango almost always (63% of sessions with the first future above VORX, 71% with the second above the first) and inverts in crises; the basis predicts the change in the future, not that of the index.
- An index that rolls daily from the first to the second future loses in contango: the long ETP falls 99.4% from 2014 to 2025 and wins only in crises.
- The daily inverse ETP wins while it lasts and loses 90.9% on 2018-02-05: inverse and leveraged products have to buy after rallies, and their acceleration clause liquidates them.
- Selling volatility has a Sharpe of 0.50 with a maximum drawdown of 98.9%; contango filters greatly improve the result in these data, but they depend on dodging the jumps by one or two days.

## Resources

### Documentation

- [Cboe: methodology of the Cboe Volatility Index (VIX), including derivatives settlement (SOQ)](https://cdn.cboe.com/api/global/us_indices/governance/Volatility_Index_Methodology_Cboe_Volatility_Index.pdf) · cdn.cboe.com
- [Cboe Futures Exchange: rule book (chapter 12, VX futures specifications)](https://cdn.cboe.com/resources/regulation/rule_book/cfe-rule-book.pdf) · cdn.cboe.com
- [Eurex: VSTOXX futures specifications (FVS)](https://www.eurex.com/ex-en/markets/vol/vstoxx/vstoxx-futures-and-options/VSTOXX-Futures-253604) · eurex.com
- [Credit Suisse AG (SEC, Form 6-K, 6 February 2018): acceleration of the XIV ETNs](https://www.sec.gov/Archives/edgar/data/0001053092/000095010318001572/dp86358_ex9901.htm) · sec.gov
- [ProShares: SVXY, −0.5× target of the S&P 500 VIX Short-Term Futures Index since 27 February 2018](https://www.proshares.com/our-etfs/strategic/svxy) · proshares.com

### Books

- [Simon, D. P. and Campasano, J. (2014): The VIX Futures Basis: Evidence and Trading Strategies. The Journal of Derivatives 21(3), 54-69](https://doi.org/10.3905/jod.2014.21.3.054) · doi.org

### Data

- [Level 3 data: short-term futures index and volatility ETPs, 2014-2025 (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/vol3_etp.csv) · Download · vol3_etp.csv

Previous lesson: [3.6.2 · Delta hedging, gamma scalping and dispersion](https://pythonparatrading.com/en/python-trading-course/level-3/delta-hedging-gamma-scalping-dispersion/)

Next lesson: [3.6.4 · Options backtesting: data, fills and event adjustments](https://pythonparatrading.com/en/python-trading-course/level-3/options-backtesting/)
