sharpe ratio annualizzato con datatrader

Sharpe Ratio annualizzato con DataTrader

Sommario

In questo articolo discutiamo di un tema molto importante nel trading quantitativo ed automatico: quando “spegnere” una strategia di trading. Descriviamo i motivi per cui le strategie finiscono per sottoperformare nel lungo periodo e come misurare il decadimento nel tempo, quindi vediamo come implementare queste funzionalità all’interno del nostro framework open-source DataTrader per il backtesting event-driven con Python. Infine applichiamo questa metodologia ad alcune strategie presentate in precedenza su DataTrading.info al fine di misurarne l’efficacia.

Il decadimento di una strategia è uno degli aspetti più difficili da gestire nel campo del trading quantitativo. Si tratta di strategie precedentemente eseguite che gradualmente, o talvolta rapidamente, perdono le loro caratteristiche di performance e finiscono per diventare non redditizie.

Le strategie di trading quantitativo si basano quasi unilateralmente sul concetto di previsione e/o errata valutazione statistica. Man mano che sempre più trader, retail o istituzionali, implementano strategie sistematiche simili, le inefficienze sono riassorbite dai prezzi, portando alla scomparsa del bias o edge che avevamo individuato con le nostre analisi statistiche. L’equity della  strategia è eroso e di solito scende al livello dei costi di transazione necessari per realizzarlo, rendendo la strategia non redditizia.

Quindi il trading quantitativo non è un’attività “accendi e dimentica”. In realtà, i trader quantistici devono avere un portafoglio di strategie che vengono lentamente “ruotate” nel tempo una volta che le opportunità di arbitraggio iniziano a erodersi. Pertanto è necessaria una ricerca costante per sviluppare continuamente nuovi “alpha” redditizi che sostituiscano quelli che sono stati “cancellati”.

Tuttavia, alcune strategie sistematiche hanno spesso lunghi periodi di rendimenti mediocri e brevi periodi di ampi drawdown. Questo avviene prevalente nelle strategie basate su dati giornalieri dato che  tendono ad avere molte meno “scommesse” di trading con previsione positiva. Pertanto, una delle principali sfide consiste nell’identificare quando una strategia è veramente sottoperformante a causa dell’erosione del vantaggio statistico o se si tratta di un periodo “temporaneo” con prestazioni inferiori.

A tale scopo è necessario adottare ed implementare una efficace metrica di trailing che catturi le prestazioni attuali della strategia in relazione alle prestazioni precedenti. Una delle misure più utilizzate, almeno nel mondo quantistico istituzionale, è lo Sharpe Ratio annualizzato.

Lo Sharpe Ratio di una strategia è progettato per fornire una misura dei rendimenti medi in eccesso di una strategia, come rapporto della volatilità “sostenuta” per ottenere tali rendimenti. È un’approsimativa misura del rapporto rendimento-rischio di una strategia. Lo Sharpe Ratio annualizzato calcola semplicemente  lo sharpe ratio considerando i dati di trading dell’anno precedente. Fornisce una visione continuamente aggiornata, anche se retrospettiva, dell’attuale rapporto rendimento-rischio.

Un basso Sharpe Ratio (inferiore a 1,0) implica che si deve sopportare una  elevata volatilità dei rendimenti per un rendimento medio scarso. Uno Sharpe Ratio negativo implica che detenere uno strumento che rappresentasse il tasso privo di rischio utilizzato nel calcolo (spesso buoni del tesoro statunitensi) sarebbe stato più redditizio della strategia di trading utilizzata. Non solo i rendimenti medi della strategia sono inferiori a quelli raggiunti dal tasso privo di rischio in questo caso, ma anche la volatilità di quei rendimenti sottoperformanti è stata  superiore al benchmark!

Quindi un modo per determinare se una strategia dovrebbe essere “messa in panchina” è tenere traccia del suo Sharpe Ratio progressivo annualizzato e vedere se questo valore tende a zero o addirittura in territorio negativo.

Chiaramente questo non copre l’intera gestione del rischio. Lo Sharpe Ratio cattura solo un aspetto del rischio (il suo rapporto con i rendimenti in eccesso) ed è un indicatore retrospettivo. Ad esempio, lo Sharpe Ratio non fornirebbe assolutamente alcuna informazione sulle impreviste modifiche normative o un crash del data center nelle prossime settimane.

Nonostante queste carenze, è utile per indicare se una strategia potrebbe sottoperformare nel prossimo futuro. È anche una buona misura da includere in un prospetto di investimento di capitale, poiché uno Sharpe relativamente costante implica una coerenza tra rendimento e rischio della strategia.

Calcolo dello  Sharpe Ratio progressivo annualizzato

Il rapporto di Sharpe standard per i rendimenti delle strategie è dato dalla seguente formula:

\(\begin{eqnarray}S = \frac{\mathbb{E}(r_s – r_b)}{\sqrt{\text{Var} (r_s – r_b)}}\end{eqnarray}\)

È il rapporto tra l’aspettativa dei rendimenti in eccesso della strategia e la deviazione standard di tali rendimenti in eccesso. In sostanza, cattura il rapporto tra rendimento e rischio, dove il rischio è definito come la volatilità dei rendimenti.

Per calcolare uno Sharpe  Ratio progressivo annualizzato è necessario apportare due modifiche a questa formula. Per prima cosa bisogna considerare solo gli ultimi rendimenti di un periodo di  trading annualizzato (ad es. per i dati giornalieri questo significa considerare gli ultimi 252 rendimenti close-to-close). Quindi è necessario moltiplicare il valore per la radice quadrata del numero di periodi di trading considerato (annuale). Per le strategie di trading su base giornaliera il numero di periodi è pari a 252, il numero (approssimativo) di giorni di negoziazione in un anno negli USA:

\(\begin{eqnarray}S_t = \sqrt{k} \frac{\mathbb{E}(r_{s,t-k} – r_{b,t-k})}{\sqrt{\text{Var} (r_{s,t-k} – r_{b,t-k})}}\end{eqnarray}\)

Dove \(r_{s,t-k}\) si riferisce ai precedenti k rendimenti della strategia piuttosto che l’intera cronologia dei rendimenti durante la vita della strategia.

Questo valore viene calcolato ad ogni periodo di trading, dopo che sono stati generati k risultati. Lo Sharpe progressivo annualizzato non è adatto per il calcolo a meno che non sia stato accumulato un periodo di trading di almeno un anno. Questo perché il rapporto può essere estremamente ampio nei primi periodi a causa di rendimenti elevati e bassa varianza, causando Sharpe ratio gonfiati e irrealistici.

Da notare che lo Sharpe ratio è una misura imperfetta del “rischio”, non solo per le ragioni evidenziate in precedenza, ma perché penalizza anche la volatilità al rialzo dei rendimenti. Cioè, se la varianza dei rendimenti aumenta fortemente verso l’alto, lo Sharpe Ratio viene ridotto a causa di un valore grande al denominatore.

Va ben ricordato che grandi movimenti imprevisti al rialzo sono pericolosi tanto quanto grandi movimenti al ribasso poiché riflettono un comportamento imprevisto della strategia. Ad esempio, un grande salto di performance al rialzo potrebbe implicare un nuovo regime normativo che ha avvantaggiato la strategia. Questo deve ora essere preso in considerazione in qualsiasi successivo sviluppo della strategia al fine di mantenere coerenti le prestazioni.

Implementazione Python  con DataTrader

L’implementazione dello Sharpe ratio progressivo annualizzato va parte del codice base di DataTrader all’interno della classe TearsheetStatistics ed è disponibile nel repository di github. Questa classe fornisce anche l’output visivo di una strategia al completamento del backtest.

Per calcolare il rapporto Sharpe progressivo annualizzato usiamo il metodo rolling di Pandas. Il metodo dataframe.rolling() fornisce la funzione di calcolo della finestra mobile. Il concetto di calcolo della finestra mobile è utilizzato principalmente nell’elaborazione del segnale e nei dati di serie temporali. In parole molto semplici prendiamo una finestra della dimensione di k alla volta ed eseguiamo alcune operazioni matematiche desiderate su di essa.

La funzione di Sharpe a rotazione annualizzata viene fornita come un grafico che si trova al di sotto della curva di equity nell’output visivo del tearSheet. È facoltativo e può essere attivato impostando rolling_sharpe=True nell’istanza della classe TearsheetStatistics del backtest. Nella stessa classe si può vedere come è semplicemente implementato con  un attributo booleano:

				
					
class TearsheetStatistics(AbstractStatistics):
    def __init__(
        self, config, portfolio_handler,
        title=None, benchmark=None, periods=252,
        rolling_sharpe=False
    ):
        ..
        ..
        self.rolling_sharpe = rolling_sharpe
        ..
        ..
				
			

Per calcolare lo Sharpe rolling annualizzato, è necessario calcolare l’ oggetto rolling utilizzando il metodo rolling sulla serie dei rendimenti della strategia, con una finestra di lookback pari al numero di periodi di trading ( self.periods).

Il calcolo moltiplica semplicemente la radice quadrata dei periodi di trading per il rapporto tra la media mobile dei rendimenti e la deviazione standard mobile. Da notare che non è incluso alcun tasso privo di rischio. I rendimenti zero sono considerati l’alternativa priva di rischio. Lo stesso vale per il benchmark. Tutto ciò avviene nel metodo get_results della clasee TearsheetStatistics:

				
					
def get_results(self):
    # Equity
    equity_s = pd.Series(self.equity).sort_index()

    # Returns
    returns_s = equity_s.pct_change().fillna(0.0)

    # Sharpe progressivo annualizzato
    rolling = returns_s.rolling(window=self.periods)
    rolling_sharpe_s = np.sqrt(self.periods) * (
        rolling.mean() / rolling.std()
    )

    ..
    ..
    
    statistics["rolling_sharpe"] = rolling_sharpe_s

    # Statistiche sul Benchmark se il ticker di benchmark è  specificato
    if self.benchmark is not None:
        equity_b = pd.Series(self.equity_benchmark).sort_index()
        returns_b = equity_b.pct_change().fillna(0.0)
        rolling_b = returns_b.rolling(window=self.periods)
        rolling_sharpe_b = np.sqrt(self.periods) * (
            rolling_b.mean() / rolling_b.std()
        )
        ..
        ..
        statistics["rolling_sharpe_b"] = rolling_sharpe_b
        ..
        ..
    return statistics
				
			

Per visualizzare il grafico dello Sharpe progressivo annualizzato  abbiamo implementato il metodo _plot_rolling_sharpe. È molto simile al metodo  _plot_equity. Crea un grafico simile alla curva  equity, usando colori identici per aiutare a distinguere la performance della strategia e la performance del benchmark. L’unica differenza è una linea verticale tratteggiata posta a k periodi nella simulazione della strategia per rappresentare il primo punto in cui viene calcolato lo Sharpe Ratio:

				
					
def get_results(self):
    # Equity
    equity_s = pd.Series(self.equity).sort_index()

    # Returns
    returns_s = equity_s.pct_change().fillna(0.0)

    # Sharpe progressivo annualizzato
    rolling = returns_s.rolling(window=self.periods)
    rolling_sharpe_s = np.sqrt(self.periods) * (
        rolling.mean() / rolling.std()
    )

    ..
    ..
    
    statistics["rolling_sharpe"] = rolling_sharpe_s

    # Statistiche sul Benchmark se il ticker di benchmark è  specificato
    if self.benchmark is not None:
        equity_b = pd.Series(self.equity_benchmark).sort_index()
        returns_b = equity_b.pct_change().fillna(0.0)
        rolling_b = returns_b.rolling(window=self.periods)
        rolling_sharpe_b = np.sqrt(self.periods) * (
            rolling_b.mean() / rolling_b.std()
        )
        ..
        ..
        statistics["rolling_sharpe_b"] = rolling_sharpe_b
        ..
        ..
    return statistics
				
			

Il codice plot_results è stato modificato per includere il grafico Sharpe  progressivo se il  parametro self.rolling_sharpe è impostato su True. Questa operazione viene eseguita utilizzando un offset_index. L’indice viene utilizzato per far sapere a matplotlib se ci sono cinque o sei sezioni verticali nel grafico e, in tal caso, regolare la posizione del grafico:

				
					
def plot_results(self, filename=None):
    ..
    ..

    if self.rolling_sharpe:
        offset_index = 1
    else:
        offset_index = 0
    vertical_sections = 5 + offset_index
    fig = plt.figure(figsize=(10, vertical_sections * 3.5))
    fig.suptitle(self.title, y=0.94, weight='bold')
    gs = gridspec.GridSpec(vertical_sections, 3, wspace=0.25, hspace=0.5)

    stats = self.get_results()
    ax_equity = plt.subplot(gs[:2, :])
    if self.rolling_sharpe:
        ax_sharpe = plt.subplot(gs[2, :])
    ax_drawdown = plt.subplot(gs[2 + offset_index, :])
    ax_monthly_returns = plt.subplot(gs[3 + offset_index, :2])
    ax_yearly_returns = plt.subplot(gs[3 + offset_index, 2])
    ax_txt_curve = plt.subplot(gs[4 + offset_index, 0])
    ax_txt_trade = plt.subplot(gs[4 + offset_index, 1])
    ax_txt_time = plt.subplot(gs[4 + offset_index, 2])

    self._plot_equity(stats, ax=ax_equity)
    if self.rolling_sharpe:
        self._plot_rolling_sharpe(stats, ax=ax_sharpe)
    self._plot_drawdown(stats, ax=ax_drawdown)
    ..
    ..
				
			

Per usare lo Sharpe progressivo annualizzato nel backtest di una strategia è sufficiente impostare a True il parametro nel file di configurazione della strategia, dove si inizializza il tearsheet:

				
					
..
..
# Uso delle statistiche Tearsheet
title = ["Example Systematic Trading Strategy"]
statistics = TearsheetStatistics(
    config, portfolio_handler, title,
    benchmark="SPY", rolling_sharpe=True
)
..
..
				
			

Nella prossima sezione vediamo i tearsheet aggiornati con lo sharpe progressivo annualizzato per varie strategie descritte negli articoli precedenti.

 

Risultati della strategia

Tutte le strategie visualizzate di seguito  possono essere ricreate visitando i collegamenti agli specifici articoli appropriati. I risultati sono semplicemente ristampanti aggiungendo la visualizzazione dello Sharpe ratio progressivo annualizzato.

Pairs trading con i filtri  di Kalman

L’articolo originale per il Pairs Trading con i filtri di  Kalman è disponibile qui . Si prega di visitare l’articolo per ottenere tutti i dettagli della strategia.

trading-algoritmico-datatrader-rolling-sharpe-kalman-tearsheet

Il calcolo dello Sharpe ratio annualizzato per la strategia inizia poco più di metà del 2010, dopo 252 periodi di trading. L’indice di Sharpe inizialmente tende a superare il 2,0 fino alla metà del 2011, in un periodo di elevata volatilità dei rendimenti, culminato in una performance piatta e successivamente in calo nel 2012-2014, che riduce pesantemente l’indice di Sharpe in territorio negativo in questo periodo.

Dopo la ripresa della strategia nel 2013, lo Sharpe annualizzato si riprende lentamente verso 2,0. Inoltre non è chiaro se la strategia stia ricominciando a decadere a fine del 2016.

Da notare la difficoltà in un’implementazione live di determinare, verso la fine del 2013, se la strategia avrebbe dovuto essere “spenta” a causa della lunga tendenza al ribasso dello Sharpe annualizzato. Ciò evidenzia quanto sia importante avere una solida comprensione del comportamento statistico della distribuzione dei rendimenti in un backtest.

Strategia di cointegrazione tra asset

L’articolo originale per la strategia di cointegrazione tas asset può essere trovata qui . Si prega di visitare l’articolo per ottenere tutti i dettagli della strategia.

trading-algoritmico-datatrader-rolling-sharpe-cointegrated-tearsheet

Poiché questa strategia viene eseguita in un arco di tempo relativamente breve (poco meno di due anni), lo Sharpe annualizzato progressivo viene calcolato solo per un breve periodo.

Inizialmente il rapporto Sharpe è alto a circa 2,25. Questa è una conseguenza del rapido aumento della performance all’inizio del 2015, ma presto si appiattisce. Una volta che questi periodi di rendimento elevato sono “caduti” dal calcolo progressivo, l’indice di Sharpe scende rapidamente a -0,5 durante la prima metà del 2016, e rimane  costante fino alla fine del 2016.

Un calo così sostanziale della performance aggiustata per il rischio sarebbe un chiaro indicatore del fatto che la strategia dovrebbe essere presa in considerazione per essere spenta. Questo decadimento può essere causato da qualsiasi particolare alpha/edge precedentemente associato alle sue previsioni è stato ora annullato con l’arbitraggio o dalla  modifica relazione strutturale sottostante.

In questo esempio, potrebbe essere che l’azienda di raffinazione dell’alluminio abbia introdotto la propria strategia di copertura della fusione dell’alluminio negoziando i prezzi del gas naturale per proprio conto. Ciò avrebbe l’effetto di diminuire l’impatto dei prezzi del gas naturale sulla propria redditività, rendendo così difficile, se non impossibile, attuare proficuamente questa strategia.

Strategia di analisi del sentiment

L’articolo originale per la strategia di analisi del sentimento può essere trovato qui . Si prega di visitare l’articolo per ottenere tutti i dettagli della strategia.

trading-algoritmico-datatrader-rolling-sharpe-sentiment-tearsheet

Nell’articolo sulla strategia sono state effettuate tre simulazioni separate, una per i titoli tecnologici, una per l’energia e una per la difesa. Questo particolare esempio utilizza l’insieme dei titoli del settore della difesa, che includono BA, GD, LMT, RTN e NOC, tutti componenti dell’S&P500.

Da notare che la strategia ha avuto un periodo di rialzo significativo nel 2013, con uno Sharpe annualizzato di 2,5, superiore a 3,5 all’inizio del 2014. Tuttavia, la performance della strategia è rimasta stabile fino al 2014, che ha causato una graduale riduzione del Sharpe progressiva annualizzato poiché la volatilità dei rendimenti è stata in gran parte simile. All’inizio del 2015 lo Sharpe era compreso tra 0,5 e 1,0, che significa assumersi un rischio maggiore per unità di rendimento in questa fase. Entro la fine del 2015 lo Sharpe era leggermente aumentato a circa 1,5, in gran parte a causa di alcuni consistenti guadagni al rialzo nella seconda metà del 2015.

Inoltre l’indice di Sharpe, sia del benchmark che della strategia, è stato sostanzialmente simile dalla metà del 2014 in poi, suggerendo che c’era poco da guadagnare (dal punto di vista del rendimento/rischio) investendo nella strategia invece di acquistare e tenendo SPY. Ovviamente in questo caso si ignora i guadagni iniziali realizzati dalla strategia nel 2013.

Benvenuto su DataTrading!

Sono Gianluca, ingegnere software e data scientist. Sono appassionato di coding, finanza e trading. Leggi la mia storia.

Ho creato DataTrading per aiutare le altre persone ad utilizzare nuovi approcci e nuovi strumenti, ed applicarli correttamente al mondo del trading.

DataTrading vuole essere un punto di ritrovo per scambiare esperienze, opinioni ed idee.

SCRIVIMI SU TELEGRAM

Per informazioni, suggerimenti, collaborazioni...

Torna in alto
Scroll to Top