Calcolo delle Performance – Creare un Trading System Parte 7

calcolo delle performance di un trading system

Nella precedente lezione del corso per creare un trading system event-driven abbiamo descritto la gerarchia della classe ExecutionHandler. In questa lezione introduciamo l’implementazione delle metriche per il calcolo delle performance di una strategia usando la curva equity precedentemente costruita nell’oggetto Portfolio.

Calcolo delle Performance

Una metrica fondamentale nel calcolo delle performance di una strategia è lo Sharpe Ratio. In una precedente lezione abbiamo definito la formula dello Sharpe Ratio(annualizzato) come segue:

\(\begin{eqnarray*}
S_A = \sqrt{N} \frac{\mathbb{E}(R_a – R_b)}{\sqrt{\text{Var} (R_a – R_b)}}
\end{eqnarray*}\)

Dove \(R_a\) è il flusso dei rendimenti della curva equity e \(R_b\) è un indice di riferimento, come uno specifico tasso di interesse o un indice azionario.

Il massimo drawdown e la durata del drawdown sono due ulteriori misure che gli investitori utilizzano per valutare il rischio in un portafoglio. Il primo rappresenta è più grande discesa, la correzione, da un precedente massimo relativo o massimo assoluto, della curva equity, mentre il secondo è definito come il numero di periodi di trading in cui si verifica.

Vediamo ora come implementare il Sharpe Ratio, il drawdown massimo e la durata del drawdown come misure delle prestazioni del portafoglio da utilizzare nel trading system event-driven sviluppato in Python.

Implementazione delle misure delle prestazioni

Il primo passo per implementare il calcolo delle perfomance di un trading system è creare un nuovo file performance.py, Dobbiamo codificare le funzioni per calcolare il Sharpe Ratio e le informazioni sul drawdown. Come per la maggior parte delle classi che prevedono elevati carichi computanzionali, abbiamo bisogno di importare NumPy e Pandas:

				
					# performance.py

import numpy as np
import pandas as pd;
				
			

Calcolare il Sharpe Ratio

Il Sharpe Ratio misura il rapporto rischio/rendimento (è solo una delle tante misure disponibili!) e richiede un parametro: il numero di periodi da considerare per annualizzare il valore.

Di solito, questo valore è fissato su 252, che rappresenta i giorni di negoziazione annuali negli Stati Uniti. Tuttavia, se la strategia apre e chiude posizioni ogni ora, è necessario adattare il Sharpe per annualizzarlo correttamente. In questo caso, si imposta il parametro periods su 252 * 6.5 = 1638, che corrisponde al numero di ore di trading annuali negli Stati Uniti. Se si effettua trading sui minuti, il parametro va impostato su 252 * 6.5 * 60 = 98280.

La funzione create_sharpe_ratio calcola il rapporto tra la media dei rendimenti percentuali e la deviazione standard dei rendimenti percentuali, ridimensionata in base al fattore periods. Questa operazione avviene su una Serie di Pandas denominata returns:

				
					# performance.py

def create_sharpe_ratio(returns, periods=252):
    """
    Crea il Sharpe ratio per la strategia, basato su a benchmark
    pari a zero (ovvero nessuna informazione sui tassi privi di rischio).

    Parametri:
    returns - Una serie panda che rappresenta i rendimenti percentuali nel periodo.
    periods - Giornaliero (252), orario (252 * 6,5), minuto (252 * 6,5 * 60) ecc.
    """
    return np.sqrt(periods) * (np.mean(returns)) / np.std(returns)
				
			

Calcolo del Drawdown

Una misura importante nel calcolo delle performance di una strategia è il “drawdown”. Questo indicatore rappresenta la distanza tra un massimo relativo e un minimo relativo lungo la curva equity.

La funzione create_drawdowns calcola sia il drawdown massimo che la durata massima del drawdown. Il drawdown massimo corrisponde alla discesa più elevata tra un massimo e un minimo relativi, mentre la durata massima del drawdown si riferisce al numero di periodi in cui si verifica questa discesa.

È importante interpretare correttamente la durata del drawdown, poiché questo fattore indica i periodi di trading e non può essere tradotto direttamente in un’unità temporale, come i “giorni”.

La funzione inizia creando due oggetti Serie di Pandas che rappresentano il drawdown e la durata di ogni “barra” di trading. Successivamente, determina l’attuale high water mark (HWM), verificando se la curva equity supera i picchi precedenti.

Il drawdown si calcola come la differenza tra l’attuale HWM e la curva equity. Se il valore risulta negativo, la durata aumenta per ogni barra che si verifica fino al raggiungimento del prossimo HWM. Infine, la funzione restituisce il massimo di ciascuna delle due serie.

				
					# performance.py

def create_drawdowns(pnl):
    """
    Calcola il massimo drawdown tra il picco e il minimo della curva PnL
    così come la durata del drawdown. Richiede che il pnl_returns
    sia una serie di pandas.

    Parametri:
    pnl - Una serie pandas che rappresenta i rendimenti percentuali del periodo.

    Restituisce:
    Drawdown, duration - Massimo drawdown picco-minimo e relativa durata.
    """

    # Calcola la curva cumulativa dei rendimenti
    # e imposta un "High Water Mark"
    # Quindi crea le serie dei drawdown e relative durate
    hwm = [0]
    idx = pnl.index
    drawdown = pd.Series(index = idx)
    duration = pd.Series(index = idx)

    # Ciclo sul range dell'indice
    for t in range(1, len(idx)):
        cur_hwm = max(hwm[t-1], pnl[t])
        hwm.append(cur_hwm)
        dd = (hwm[t] - pnl[t])
        drawdown[t]= dd
        duration[t]= (0 if drawdown[t] == 0 else duration[t-1] + 1)
    return drawdown, drawdown.max(), duration.max()
				
			

Gestione delle Performance

Per utilizzare correttamente le misure, è fondamentale disporre di un metodo per il calcolo delle performance dopo aver effettuato un backtest, ossia quando è disponibile una curva di equity adeguata.

Inoltre, è necessario associare questo metodo a una struttura di oggetti specifica. Poiché le misure di rendimento derivano dal portafoglio, è logico implementare i calcoli delle performance all’interno di un metodo della classe Portfolio.

Il primo passo consiste nell’aprire portfolio.py e importare le funzioni di calcolo delle performance.

				
					# portfolio.py

..  # Other imports

from performance import create_sharpe_ratio, create_drawdowns

				
			

Poiché Portfolio è una classe base astratta, si deve associare un metodo a una delle sue classi derivate, che in questo caso corrisponde a NaivePortfolio. Quindi si crea un metodo chiamato output_summary_stats che elabora la curva equity del portafoglio per generare le informazioni relative allo Sharpe e drawdown.

Il metodo è semplice. Utilizza semplicemente le due misure di performance e le applica direttamente al DataFrame Pandas relativo alla curva equity, restituendo le statistiche come una lista di tuple in un formato “user-friendly”:

				
					# portfolio.py

..
..

class NaivePortfolio(object):

    ..
    ..

    def output_summary_stats(self):
        """
        Crea un elenco di statistiche di riepilogo per il portafoglio
        come lo Sharpe Ratio e le informazioni sul drowdown.
        """
        total_return = self.equity_curve['equity_curve'][-1]
        returns = self.equity_curve['returns']
        pnl = self.equity_curve['equity_curve']

        sharpe_ratio = create_sharpe_ratio(returns)
        drawdown, max_dd, dd_duration = create_drawdowns(pnl)
        self.equity_curve['drawdown'] = drawdown
        stats = [("Total Return", "%0.2f%%" % \
                  ((total_return - 1.0) * 100.0)),
                 ("Sharpe Ratio", "%0.2f" % sharpe_ratio),
                 ("Max Drawdown", "%0.2f%%" % (max_dd * 100.0)),
                 ("Drawdown Duration", "%d" % dd_duration)]
        self.equity_curve.to_csv('equity.csv')
        return stats

				
			

Conclusione

In questa lezione abbiamo descritto un calcolo delle performance di un portfolio molto semplice. Non considera l’analisi dei singoli trade o altre misure del rapporto rischio/rendimento. Tuttavia, è facile estendere questa analisi, aggiungendo nuovi metodi in performance.py e integrandoli in output_summary_stats secondo le necessità.

Il codice completo presentato in questa lezione, basato sul sistema di trading event-driven TQTradingSystem, è disponibile nel seguente repository GitHub: https://github.com/tradingquant-it/TQTradingSystem.”

Torna in alto