i Futures Continuous nel Backtesting del Trading Algoritmico

i Futures Continuous nel Backtesting del Trading Algoritmico

In questa lezione del corso sulle basi del trading algoritmico con Python descriviamo come usare i futures continuous nel backtesting. Analizziamo le caratteristiche dei contratti futures, che pongono diverse sfide nel contesto del backtesting.

In particolare, approfondiamo i concetti di “continuous contract” e “roll returns”. Illustriamo inoltre le principali criticità legate ai futures e una proposta di implementazione in Python con Pandas per gestire efficacemente tali problematiche.

Breve panoramica sui Futures

I futures sono contratti negoziati in borsa, stipulati tra due parti per acquistare o vendere un’attività sottostante a una data futura prefissata, chiamata scadenza. Alla scadenza, l’acquirente riceve il bene fisico (o l’equivalente in contanti) al prezzo concordato alla stipula. Questi strumenti derivati, standardizzati per quantità e qualità del sottostante, sono regolati giornalmente (“marked to market”) e offrono grande liquidità. Oggi esistono futures su una vasta gamma di asset, inclusi indici azionari, tassi di interesse e valute.

Una panoramica completa di codici e simboli per i contratti futures nelle principali borse è disponibile sul sito CSI Data: Futures Factsheet.

La differenza principale rispetto alle azioni è che i futures hanno una scadenza. Esistono quindi più contratti sullo stesso sottostante, ciascuno con una diversa data. Il contratto più vicino alla scadenza è detto “near contract”. Il trader quantitativo si trova quindi a operare su una serie temporale discontinua.

Questa lezione mira a presentare vari metodi per generare una serie di prezzi continua da più contratti e a valutarne vantaggi e svantaggi.

I contratti Futures Continuous

Il problema centrale nella creazione di contratti continui è la discontinuità nei prezzi tra i contratti, dovuta a fenomeni come contango (prezzi futuri maggiori) o backwardation (prezzi futuri minori).

Vediamo ora le principali tecniche di unione dei contratti.

Aggiustamento Back/Forward (“Panama”)

Questo metodo sposta ogni contratto in modo da far coincidere i prezzi di chiusura e apertura tra contratti adiacenti. Introduce però un bias di trend, che può generare prezzi irrealistici e rendimenti distorti.

Aggiustamento Proporzionale

Simile al metodo per gestire frazionamenti azionari. Utilizza il rapporto tra vecchio e nuovo prezzo per modificare proporzionalmente lo storico. Tuttavia, non è adatto a strategie che si basano su soglie di prezzo assoluto.

Rollover e Serie Perpetual

Consiste nel passare gradualmente da un contratto all’altro utilizzando una media ponderata tra i due. Per esempio, in una transizione su 5 giorni, il prezzo risultante sarà una combinazione progressiva dei prezzi dei due contratti, dal più distante a quello più vicino.

Il principale svantaggio è l’aumento delle operazioni durante il rollover, che comporta costi di transazione maggiori.

I futures continuous nel backtesting con Python e Pandas

Il resto della lezione è dedicato all’implementazione dei futures continuous per il backtesting di strategie.

L’obiettivo è unire i futures WTI Crude Oil “near” e “far” (simbolo CL) in un’unica serie. Ad esempio, i contratti CLF2014 (gennaio) e CLG2014 (febbraio).

Per scaricare i dati usiamo la libreria Quandl. È fondamentale configurare l’ambiente Python e installare Quandl eseguendo nel terminale:

				
					pip install quandl
				
			

Ora che il pacchetto quandl è installato, dobbiamo usare NumPy e Pandas per eseguire la creazione dei roll-return. Se non hai installato NumPy o Pandas, ti consiglio di seguire la lezione precedente 

Creiamo un nuovo file ed inseriamo le seguenti istruzioni:

				
					import datetime
import numpy as np
import panda as pd
import quandl
				
			

Nell’implementazione dei futures continuous per il backtesting prevediamo che la logica principale è codifica nella funzione futures_rollover_weights. La funzione richiede una data di inizio (la prima data del contratto vicino), un dizionario delle date di regolamentazione del contratto (expiry_dates), i simboli dei contratti e il numero di giorni per il rinnovo del contratto (cinque, come default). Di seguito il codice di questa funzione:

				
					
def futures_rollover_weights(start_date, expiry_dates, contracts, rollover_days=5):
    """
    Si costruisce un DataFrame pandas che contiene pesi (tra 0,0 e 1,0)
    di posizioni contrattuali da mantenere per eseguire un rollover di rollover_days
    prima della scadenza del primo contratto. La matrice può quindi essere
    'moltiplicato' con un altro DataFrame contenente i prezzi di settle di ciascuno
    contratto al fine di produrre una serie temporali per un contratto future 
    continuo.
    """

    # Costruisci una sequenza di date a partire dalla data inizio del primo contratto
    # alla data di fine del contratto finale
    dates = pd.date_range(start_date, expiry_dates[-1], freq='B')

    # Crea il DataFrame 'roll weights' che memorizzerà i moltiplicatori per
    # ogni contratto (tra 0,0 e 1,0)
    roll_weights = pd.DataFrame(np.zeros((len(dates), len(contracts))),
                                index=dates, columns=contracts)
    prev_date = roll_weights.index[0]

    # Si scorre ogni contratto e si crea i pesi specifiche per ogni
    # contratto che dipende dalla data di settlement e dai rollover_days
    for i, (item, ex_date) in enumerate(expiry_dates.iteritems()):
        if i < len(expiry_dates) - 1:
            roll_weights.ix[prev_date:ex_date - pd.offsets.BDay(), item] = 1
            roll_rng = pd.date_range(end=ex_date - pd.offsets.BDay(),
                                     periods=rollover_days + 1, freq='B')

            # Crea una sequenza di pesi a finesta mobile (cioè [0.0,0.2, ..., 
            # 0.8,1.0] e si usano per regolare i pesi di ogni future
            decay_weights = np.linspace(0, 1, rollover_days + 1)
            roll_weights.ix[roll_rng, item] = 1 - decay_weights
            roll_weights.ix[roll_rng, expiry_dates.index[i+1]] = decay_weights
        else:
            roll_weights.ix[prev_date:, item] = 1
        prev_date = ex_date
    return roll_weights
				
			

Ora che la matrice pesata è stata prodotta, possiamo applicarla alle singole serie temporali. La funzione principale scarica i contratti vicini e lontani, crea un singolo DataFrame per entrambi, costruisce la matrice del rollover ed infine produce una serie continua di entrambi i prezzi, opportunamente ponderata:

				
					
if __name__ == "__main__":
    # Scarica gli attuali contratti future Front e Back (vicino e lontano)
    # per il petrolio WTI, negoziato al NYMEX, da Quandl.com. Avrai bisogno di
    # aggiustare i contratti per riflettere gli attuali contratti vicini / lontani
    # a seconda del punto in cui leggi questo!
    wti_near = quandl.get("OFDP/FUTURE_CLF2014")
    wti_far = quandl.get("OFDP/FUTURE_CLG2014")
    wti = pd.DataFrame({'CLF2014': wti_near['Settle'],
                        'CLG2014': wti_far['Settle']}, index=wti_far.index)

    # Crea un dizionario delle date di scadenza di ogni contratto
    expiry_dates = pd.Series({'CLF2014': datetime.datetime(2013, 12, 19),
                              'CLG2014': datetime.datetime(2014, 2, 21)}).order()

    # Calcolare la matrice (Dataframe) dei pesi di rollover
    weights = futures_rollover_weights(wti_near.index[0], expiry_dates, wti.columns)

    # Costruzione del future continuo dei contratti del petrolio WTI (CL)
    wti_cts = (wti * weights).sum(1).dropna()

    # Stammpa delle serie aggregate dei prezzi di settle dei contratti
    wti_cts.tail(60)
				
			

Eseguendo questo script otteniamo il seguente output:

Da notare come ora la serie è continua tra i due contratti.

Conclusione

Il prossimo passo per implementare i futures continuous nel backtesting è eseguire il codice in scadenze multiple per un buon numero di anni, a seconda delle vostre esigenze.

Il codice completo presentato in questa lezione, parte del pacchetto python per il backtest TQBacktest, è disponibile nel seguente repository GitHub: https://github.com/tradingquant-it/TQBacktest.”

Torna in alto