Introduzione


La volatilità rientra nell'ambito di un concetto generale, quello che permette di rispondere alla domanda: "Quanto si discostano i dati dal loro valore centrale?".

La volatilità di un asset o di un portafoglio riguarda la dimensione temporale, informa sul rischio connesso all'investimento misurando l'incertezza dei rendimenti passati o previsti nell'immediato futuro; nella dimensione trasversale, la dispersione tra asset diversi in uno stesso momento ci informa se il mercato è guidato da fattori comuni o se dominano fattori specifici, settoriali o aziendali, e guida alla costruzione dei portafogli.
Soprattutto la volatilità prevista nell'immediato futuro valuta l'imprevedibilità e quindi il rischio che preoccupa molti investitori, fenomeno del tutto normale in questo tipo di attività e nel quale si nascondono rilevanti opportunità.

In queste pagine si vogliono esaminare questi concetti in maniera prevalentemente sperimentale a partire da dati reali e avvalendosi di un linguaggio di programmazione, Python in ambiente interattivo Google Colab (basato su Jupyter, un progetto Open Source).

Introduttivamente vediamo come esaminare la serie storica di un asset o di un indice finaziario prelevandola da Yahoo Finanza con il modulo yfinance che, innanzitutto, va installato.

!pip install yfinance
Quindi, dopo aver importato come oggetto yf.Ticker() un dizionario di eventi, guadagni e dividendi relativi al simbolo, ad esempio ^GSPC oppure ^SPX per S&P 500, si può scaricare lo storico mediante .history() come oggetto DataFrame del modulo pandas e poi visualizzare i primi e gli ultimi dati della tabella.
import yfinance as yf stock = yf.Ticker("^GSPC") df = stock.history(period="5y") df
Open High Low Close Volume Dividends Stock Splits
Date
2021-05-06 00:00:00-04:00 4169.140137 4202.700195 4147.330078 4201.620117 4511000000 0.0 0.0
2021-05-07 00:00:00-04:00 4210.339844 4238.040039 4201.640137 4232.600098 4016080000 0.0 0.0
2021-05-10 00:00:00-04:00 4228.290039 4236.390137 4188.129883 4188.430176 4560700000 0.0 0.0
2021-05-11 00:00:00-04:00 4150.339844 4162.040039 4111.529785 4152.100098 4870710000 0.0 0.0
2021-05-12 00:00:00-04:00 4130.549805 4134.729980 4056.879883 4063.040039 4733070000 0.0 0.0
... ... ... ... ... ... ... ...
2026-04-29 00:00:00-04:00 7131.609863 7145.629883 7107.859863 7135.950195 5123100000 0.0 0.0
2026-04-30 00:00:00-04:00 7161.750000 7219.830078 7126.149902 7209.009766 5723790000 0.0 0.0
2026-05-01 00:00:00-04:00 7234.540039 7272.520020 7229.319824 7230.120117 4847390000 0.0 0.0
2026-05-04 00:00:00-04:00 7228.379883 7244.540039 7174.120117 7200.750000 5215480000 0.0 0.0
2026-05-05 00:00:00-04:00 7233.620117 7273.259766 7233.620117 7259.220215 5279760000 0.0 0.0
Data una serie storica \(P(t)\) di prezzi, i relativi rendimenti nell'intervallo di tempo \(\Delta t\) sono \[R(t)=\frac{\Delta P(t-\Delta t)}{P(t-\Delta t)} = \frac{P(t)-P(t-\Delta t)}{P(t - \Delta t)} = \frac{P(t)}{P(t-\Delta t)}-1,\] Dal DataFrame df dello storico relativo a un asset, si possono ottenere applicando alla colonna df.Close il metodo .pt_change().
D'altra parte, poiché i prezzi sono strettamente positivi, è ragionevole rappresentarli come un'esponenziale \[P(t)=e^{\log P(t)}\] e, piuttosto che \(P(t),\) studiare \(\log P(t)\) le cui variazioni sono detti log-rendimenti dei prezzi \[ r(t)=\Delta \log P(t-\Delta t)=\log\frac{P(t)}{P(t-\Delta t)}=\log(1+R(t)),\] ottenibili con np.log(df.Close).diff() o anche np.log(df.Close/df.Close.shift()).
Considerando che per valori piccoli di \(x\) \[\log(1+x) = x - \frac{x^2}{2}+\frac{x^3}{3}-\dots\] possiamo dire che \[r(t)\approx R(t)-\frac{R^2(t)}{2}+O(R^3(t))\] I log-rendimenti, più che i rendimenti semplici, tendono a seguire una distribuzione normale \[r(t) ∼ N (\mu, σ^2 ), \quad t = 1, \dots, T,\] con valore atteso \(\mu,\) la tendenza o drift, e varianza \(σ^2\), un indice di dispersione rispetto al valore atteso.
import matplotlib.pyplot as plt import numpy as np log_returns = np.log(df.Close/df.Close.shift()) # Istogramma dei log-rendimenti reali log_returns.plot(kind='hist',bins=20, title='log-rendimenti', density=True) # Curva normale teorica μ, σ = log_returns.mean(), log_returns.std() x = np.linspace(log_returns.min(), log_returns.max(), 100) normal_pdf = np.exp(-(x - μ)**2 / (2 * σ**2)) / (σ * np.sqrt(2 * np.pi)) plt.plot(x, normal_pdf, label='Distribuzione Normale', color='r', linestyle='--') plt.legend()

Scelti ragionevoli valori per \(\mu\) e per \(σ^2\), diverse simulazioni possono fornire previsioni.
Nel seguito esamineremo metodi di valutazione dell'incertezza, sia quella legata allo storico sia quella prevedibile.

Riferimenti sito/bibliografici