Breve panoramica sui Futures
I contratti di Futures continui
La principale difficoltà nel cercare di generare un contratto continuo dai contratti sottostanti con differenti scadenze è causata dalla variazione dei prezzi con cui vengono scambiati. Quindi si verificano casi dove i prezzi non sono lineari tra un contratto a scadenza e il successivo. Ciò è dovuto agli effetti di Contango (i prezzi delle scadenze più lontane sono più alti di quelli delle scadenze più vicine) o in Backwardation (esattamente l’opposto). Esistono diversi approcci per affrontare questo problema. Sfortunatamente non esiste un unico metodo “standard” per unire i contratti futures. In definitiva, il metodo scelto dipenderà in gran parte dalla strategia e dal metodo di esecuzione. Nonostante non esista un unico metodo, ci sono i seguenti approcci comuni.Aggiustamento Back/Forward (“Panama”)
Questo metodo riduce il “divario” tra più contratti spostando ciascun contratto in modo tale che le singole scadenze si uniscano in modo agevole con contratti adiacenti. Pertanto, il prezzo di apertura / chiusura tra i contratti coincide. Il problema chiave con il metodo Panama consiste nell’introduzione di un bias di trend, che causa una forte deriva dei prezzi, soprattutto con orizzonti temporali di lungo periodo (e anche la possibilità di prezzi negativi). Inoltre, vi è una perdita delle differenze di prezzo relative a causa di uno spostamento assoluto dei valori. Ciò significa che i rendimenti sono più complicati da calcolare (o semplicemente errati).Aggiustamento Proporzionale
Questo approccio è simile al metodo del “handling stock splits” per le azioni (gestione dei frazionamenti azionari). In questo caso, il rapporto tra il vecchio prezzo di chiusura e il nuovo prezzo di apertura è utilizzato per adeguare proporzionalmente i prezzi dei contratti storici. Ciò consente un flusso continuo senza un’interruzione del calcolo dei ritorni percentuali. Il problema principale con l’adeguamento proporzionale è la necessità di applicare la stessa logica a qualsiasi trading basata su un livello di prezzo assoluto, al fine di eseguire il segnale corretto. Questo è un processo problematico e soggetto a errori. Quindi questo tipo di flusso continuo è spesso utile solo per una analisi statistica sommaria, al contrario della ricerca diretta di backtesting.Rollover e serie Perpetual
La base di questo approccio consiste nel creare un contratto continuo come successione di contratti, considerano una percentuale ponderata linearmente di ciascun contratto su uno specifico numero di giorni, in modo da assicurare una transizione più fluida tra i contratti. Per esempio, consideriamo 5 giorni di transizione. Il prezzo al giorno1,P1
è pari all’80% del prezzo del contratto più lontano (F1
) e il 20% del prezzo del contratto più vicino (N1
).
In modo analogo, al giorno 2 il prezzo è pari a: P2=0.6×F2+0.4×N2
.
Al giorno 5 si ha: P5=0.0×F5+1.0×N5=N5
e quindi il contratto diventa continuo al prezzo più vicino. Dopo 5 giorni il contratto è transitato dal prezzo più lontano a quello più vicino.
Il problema con il metodo rollover consiste nel dovre effettuare operazioni tutti e 5 i giorni e quindi si ha un incremento dei costi di transazione days.
Implementazione del Roll-Return in Python e Pandas
Il resto dell’articolo si concentra sull’implementazione del metodo delle serie perpetue poiché è più appropriato per la fase di backtesting. È un modo utile per condurre ricerche sulle pipeline strategiche. Vogliamo collegare i contratti futures del WTI Crude Oil “near” e “lontano” (simbolo CL) per generare una serie di prezzi continui. Ad esempio possiamo considerare il contratto a breve termine è CLF2014 (gennaio) e il contratto lontano è CLG2014 (febbraio). Per effettuare il download dei dati relativi ai Futures, ho utilizzato la lbreria Quandl. Assicurati di impostare il corretto ambiente virtuale di Python sul tuo sistema e installa il pacchetto Quandl digitando quanto segue 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 il mio tutorial. Crea un nuovo file e inserisci le seguenti istruzioni:
import datetime
import numpy as np
import panda as pd
import quandl
Il lavoro principale è svolto nella funzione futures_rollover_weights
. 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 logica:
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, è possibile 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 si ottiene il seguente output:
Da notare come ora la serie è continua tra i due contratti. Il prossimo passo è eseguire questo per scadenze multiple per un buon numero di anni, a seconda delle vostre esigenze di backtesting.
Per il codice completo riportato in questo articolo utilizzando il modulo di backtesting vettoriale VectorBacktest si può consultare il seguente repository di github:
https://github.com/datatrading-info/VectorBacktest