yfinance — scaricare dati storici

yfinance è la libreria Python più usata per scaricare dati finanziari da Yahoo Finance gratuitamente. Supporta azioni, ETF, indici, forex, crypto e futures.

In:
import yfinance as yf import pandas as pd # Metodo 1: download diretto (più veloce per singolo ticker) df = yf.download( "AAPL", start="2022-01-01", end="2024-01-01", interval="1d", # 1m, 5m, 15m, 1h, 1d, 1wk, 1mo auto_adjust=True # prezzi aggiustati per split e dividendi ) # Metodo 2: oggetto Ticker (più funzionale) ticker = yf.Ticker("AAPL") df = ticker.history(period="2y", interval="1d") # Metadati aziendali info = ticker.info print(f"Settore: {info['sector']}") print(f"Capitaliz.: ${info['marketCap']/1e12:.2f}T") print(f"P/E ratio: {info['trailingPE']:.1f}") print(f"52w High: ${info['fiftyTwoWeekHigh']:.2f}")
Out:
[*********************100%***********************] 1 of 1 completed Settore: Technology Capitaliz.: $3.74T P/E ratio: 32.3 52w High: $288.62

Struttura del DataFrame restituito

yfinance restituisce un oggetto pandas.DataFrame con l'indice di tipo DatetimeIndex. Ecco le colonne principali:

ColonnaTipoDescrizione
Openfloat64Prezzo di apertura (aggiustato)
Highfloat64Massimo intraday
Lowfloat64Minimo intraday
Closefloat64Prezzo di chiusura (aggiustato)
Volumeint64Numero di azioni scambiate
Dividendsfloat64Dividendi distribuiti (se presenti)
Stock Splitsfloat64Rapporto di split (es. 4 per split 4:1)

Pulizia e validazione dei dati

I dati finanziari reali contengono spesso valori mancanti, outlier e discontinuità. Prima di qualsiasi analisi, è necessaria una fase di pulizia sistematica.

In:
import numpy as np df = yf.download("AAPL", period="5y", auto_adjust=True) # ── 1. Diagnosi iniziale ── print(f"Righe totali: {len(df)}") print(f"Valori NaN:\n{df.isnull().sum()}") print(f"Periodo: {df.index[0].date()} → {df.index[-1].date()}") # ── 2. Rimuovi giorni senza volume (festività) ── df = df[df["Volume"] > 0] # ── 3. Interpola i valori mancanti ── df[('Close', 'AAPL')] = df[('Close', 'AAPL')].interpolate(method="linear") # ── 4. Rileva outlier con z-score sui rendimenti ── # Ensure 'returns' is a Series by explicitly selecting the 'AAPL' column returns = df[('Close', 'AAPL')].pct_change() z_score = ((returns - returns.mean()) / returns.std()).abs() outlier_giorni = df[z_score > 4].index print(f"\nGiorni anomali (z>4): {len(outlier_giorni)}") for d in outlier_giorni: # Correctly access the value from the 'AAPL' column of the 'returns' Series print(f" {d.date()} rendimento: {returns.loc[d]*100:+.1f}%") # ── 5. Verifica continuità temporale ── diff_giorni = df.index.to_series().diff().dt.days gap = diff_giorni[diff_giorni > 5] print(f"\nGap > 5gg: {len(gap)} trovati")
Out:
[*********************100%***********************] 1 of 1 completed Righe totali: 1256 Valori NaN: Price Ticker Close AAPL 0 High AAPL 0 Low AAPL 0 Open AAPL 0 Volume AAPL 0 dtype: int64 Periodo: 2021-03-17 → 2026-03-17 Giorni anomali (z>4): 6 2022-10-28 rendimento: +7.6% 2022-11-10 rendimento: +8.9% 2024-06-11 rendimento: +7.3% 2025-04-03 rendimento: -9.2% 2025-04-04 rendimento: -7.3% 2025-04-09 rendimento: +15.3% Gap > 5gg: 0 trovati

Più ticker contemporaneamente

Per analisi di portafoglio o confronti settoriali è necessario gestire dati di più strumenti insieme. yfinance supporta download multipli e pandas offre strutture MultiIndex per gestirli.

In:
tickers = ["AAPL", "MSFT", "GOOGL", "AMZN", "NVDA"] # Download multiplo — restituisce MultiIndex DataFrame raw = yf.download(tickers, period="2y", auto_adjust=True) # Estrai solo il Close di tutti i ticker prezzi = raw["Close"] # DataFrame con colonne = ticker volumi = raw["Volume"] # Normalizza a base 100 per confronto visivo normalizzati = prezzi / prezzi.iloc[0] * 100 # Statistiche comparative stats = pd.DataFrame({ "rendimento_2y": (prezzi.iloc[-1] / prezzi.iloc[0] - 1) * 100, "volatilita_ann": prezzi.pct_change().std() * (252 ** 0.5) * 100, "max": prezzi.max(), "min": prezzi.min() }).round(2) print(stats)
Out:
[*********************100%***********************] 5 of 5 completed rendimento_2y volatilita_ann max min Ticker AAPL 47.88 28.51 285.92 163.51 AMZN 22.75 31.61 254.00 161.02 GOOGL 109.48 29.59 343.45 144.20 MSFT -2.23 23.90 539.83 351.87 NVDA 106.87 49.30 207.02 76.16

Rendimenti e statistiche descrittive

La trasformazione più importante in finance quantitativo è il passaggio dai prezzi ai rendimenti. I prezzi non sono stazionari (cambiano nel tempo), mentre i rendimenti percentuali hanno proprietà statistiche molto più stabili e confrontabili.

Rendimento semplice vs logaritmico r_semplice = (P_t P_{t-1}) / P_{t-1}
r_log = ln(P_t / P_{t-1})
In:
df = yf.download("AAPL", period="3y", auto_adjust=True) close = df["Close"] # Rendimenti giornalieri r = close.pct_change().dropna() # semplici r_log = np.log(close / close.shift(1)).dropna() # logaritmici # Statistiche chiave mu = r.mean() * 252 # rendimento medio annualizzato sigma = r.std() * np.sqrt(252) # volatilità annualizzata sharpe= mu / sigma # Sharpe ratio senza risk-free # Value at Risk (VaR) al 95% var_95 = r.quantile(0.05) cvar_95= r[r <= var_95].mean() # Expected Shortfall # Maximum Drawdown cummax = close.cummax() drawdown = (close - cummax) / cummax max_dd = drawdown.min() print(f"Rendimento ann.: {mu.item()*100:+.1f}%") print(f"Volatilità ann.: {sigma.item()*100:.1f}%") print(f"Sharpe ratio: {sharpe.item():.2f}") print(f"VaR 95% giorn.: {var_95.item()*100:.2f}%") print(f"CVaR 95% giorn.: {cvar_95.item()*100:.2f}%") print(f"Max Drawdown: {max_dd.item()*100:.1f}%")
Out:
[*********************100%***********************] 1 of 1 completed Rendimento ann.: +20.4% Volatilità ann.: 25.7% Sharpe ratio: 0.79 VaR 95% giorn.: -2.48% CVaR 95% giorn.: -3.67% Max Drawdown: -33.4%

Visualizzazione con matplotlib e plotly

La visualizzazione è fondamentale per capire i dati prima di costruire qualsiasi strategia. matplotlib è ottimo per grafici statici da inserire in report; plotly produce grafici interattivi ideali per l'esplorazione.

In:
import plotly.graph_objects as go from plotly.subplots import make_subplots df = yf.download("AAPL", period="6mo", interval="1d", auto_adjust=True) # Flatten the MultiIndex columns to single-level strings df.columns = [col[0] for col in df.columns] # Grafico con 2 pannelli: prezzo + volume fig = make_subplots( rows=2, cols=1, row_heights=[0.75, 0.25], shared_xaxes=True, vertical_spacing=0.02 ) # Pannello 1: candele OHLC fig.add_trace(go.Candlestick( x=df.index, open=df["Open"], high=df["High"], low=df["Low"], close=df["Close"], name="AAPL" ), row=1, col=1) # SMA 20 sovrapposta sma20 = df["Close"].rolling(20).mean() fig.add_trace(go.Scatter( x=df.index, y=sma20, name="SMA 20", line=dict(color="#b8f04a", width=1.5) ), row=1, col=1) fig.add_trace(go.Bar( x=df.index, y=df["Volume"], name="Volume" ), row=2, col=1) fig.update_layout( xaxis_rangeslider_visible=False, height=600 ) fig.show()
Consiglio

Usa plotly durante l'esplorazione interattiva e matplotlib quando vuoi esportare grafici statici in PNG/PDF per report. Per notebook Jupyter, plotly si integra perfettamente con fig.show().

ESERCIZIOAnalisi comparativa di un settore

Scarica 2 anni di dati giornalieri per i 5 maggiori titoli del settore tecnologico (AAPL, MSFT, GOOGL, META, NVDA) e costruisci un report che includa:

  • Tabella con rendimento, volatilità annualizzata e Sharpe ratio per ciascun titolo
  • Grafico a linee normalizzato a base 100 per confrontare le performance
  • Matrice di correlazione tra i rendimenti giornalieri (usa df.corr())
  • VaR al 95% e 99% per ciascun titolo