In questa nuova serie di articoli introduciamo un nuovo framework open-source per il backtesting di strategie di trading quantitative e sistematiche a cui sto lavorando e sarà rilasciato nei prossimi mesi.
Un nuovo framework per il backtesting basato sugli eventi
Il precedente framework DataTrader è stato sviluppato come un sistema modulare di backtesting basato su eventi, rivolto principalmente a strategie per il mercato azionario. Tuttavia, ben presto è diventato chiaro che i trader retail e i fondi istituzionali usano un approccio diverso da quello inizialmente previsto in DataTrader.
Sebbene DataTrader permette una gestione di base del portafoglio, è lontano da un sistema multi-account e multi-strategia richiesto da molti trader. Questo ha motivato l’implementazione “da zero” di un sistema più sofisticato.
Il nostro obiettivo è implementare uno strumento per poter simulare grandi allocazioni di capitale dalla fase di backtesting/ricerca, alla simulazione foward (ad es. con vari modelli matematici per allocazione di asset), fino al paper trading e infine al passaggio al trading live.
A tale scopo vogliamo migliorare DataTrader da un semplice backtester azionario basato sugli eventi a un vero e proprio motore di trading in tempo reale e un ambiente di reporting delle prestazioni su molteplici classi di asset, valute e strumenti, utilizzando un framework per costruire un portafoglio in stile istituzionale.
I seguenti paragrafi descrivono in dettaglio alcuni delle principali componenti proposti.
Brokerage
Nella versione attuale di DataTrader non esiste il concetto di “fornitore di liquidità” o “broker” che può essere usato dal trading system, né per i dati di mercato in tempo reale né per il monitoraggio del portafoglio. In DataInvestor è stata introdotta la gerarchia di classi Broker
, progettata per gestire il tracciamento delle posizioni.
L’entità broker supporta un account “master” con più account secondari, ciascuno dei quali tiene traccia del proprio PnL. Ciascun conto può essere denominato in una valuta separata, consentendo portafogli multiregione. I PnL del sottoconto verranno aggregati per ottenere il PnL totale del conto, che sarà mark-to-market nelle varie valute, utilizzando i dati F/X point-in-time.
La strategia di trading si interfaccia con l’entità broker esclusivamente per depositare/prelevare capitale, creare e eliminare sottoconti, acquisire i dati di mercato più recenti ed eseguire gli ordini. Ciò consente che tutta la logica interna di gestione del portafoglio e della posizione è eseguita dalla stessa entità broker.
In questa fase riteniamo che questo sia un modello sufficientemente generico per supportare molte varietà di trader, dai retail di piccole dimensioni fino ai gestori di “amici e familiari” e persino family office/fondi di piccole dimensioni senza requisiti stringenti.
In futuro è probabile introdurre una gerarchia di classi LiquidityProvider
più ampia, di cui Broker
è una sottoclasse. In questo modo è possibile gestire diversi fornitori di accesso al mercato, disponibili per determinati partecipanti ai mercati finanziari (ad esempio prime brokerage, ECN ).
Margine
In DataInvestor sono implementati metodi per calcolare il margine in modo realistico.
Questi calcoli sono inizialmente basati sui requisiti di margine previsti da Interactive Brokers . IB fornisce due forme di conto a margine: un conto Reg T e un conto “portafoglio commodities” più sofisticato. Quest’ultimo tiene conto delle posizioni di copertura per compensare il rischio. Entrambi prevedono calcoli non banali per i requisiti di margine e gli scenari di liquidazione, che devono essere presi in considerazione.
Inoltre, il prestito sul margine genera interessi che comportano calcoli non banali su più valute e dipendono da tassi point-in-time esterni (come il LIBOR). Per un esempio di come Interactive Brokers calcola gli interessi, dai un’occhiata alla loro pagina sul Programma interessi. DataInvestor prevede di gestire il margine e l’interesse in questo modo che consente quindi posizioni con leva su futures e f/x.
Commissioni
In DataInvestor le commissioni sono calcolate in modo molto accurato. I broker prevedono diverse strutture di commissioni, la maggior parte a più livelli a seconda degli asset totali e della frequenza delle negoziazioni, con una tariffa introduttiva per un primo periodo di vita del conto. Inoltre, bisogna prevedere che la maggior parte delle transazioni sono soggette a un’imposta, sebbene alcuni asset siano esenti.
Dato che le commissioni possono essere relativamente rilevanti, per un backtest realistico dobbiamo calcolare accuratamente questi costi. A tale scopo DataInvestor implementa alcuni funzioni basi basate su IB.
Questo è un esempio tra i tanti. In futuro prevediamo di implementare la gestione di più broker in modo che DataInvestor sia veramente un backtester “internazionale”, piuttosto che uno specificamente implementato per i vincoli di IB.
Flussi di cassa
DataInvestor permette la gestione dei flussi di cassa. In questo modo è possibile aggiungere o rimuovere ulteriori contanti al capitale iniziale durante la durata della strategia.
Questo è abbastanza realistico. Verosimilmente i trader retail di fascia alta prelevano i dividendi e i guadagni del trading come reddito per vivere, o aggiungono una regolare iniezione di denaro per finanziare l’acquisto di nuovi asset. Quindi depositi e prelievi di fondi si verificano frequentemente.
DataInvestor implementa i trasferimenti di denaro in entrata e in uscita dal broker, insieme all’allocazione su vari sottoconti in più valute. Tale funzionalità è fondamentale per gestire i dividendi in contanti, come descritto nel prossimo paragrafo.
Dividendi
In DataInvestor i dividendi in contanti sono gestiti come iniezioni dirette di contanti in un sottoconto del portafoglio. A tale scopo è necessario gestire la data di stacco del dividendo dell’asset, oltre a garantire che la posizione sia stata aperta prima della data dello stacco.
L’obiettivo è gestire le azioni aziendali più complesse come i frazionamenti stock-for-stock. Aggiungendo i contanti dei dividendi nel sottoconto, l’algoritmo di trading può scegliere automaticamente come reinvestire il denaro, piuttosto che farlo “dettare” dalla strategia usando una forma di serie del rendimento totale.
Exchange e Asset
DataTrader gestisce i dati di mercato attraverso l’uso di un’entità PriceHandler
, richiamata per generare oggetti BarEvent
o TickEvent
.
In DataInvestor questa logica è stata completamente ricostruita. In particolare DataInvestor prevede un disaccoppiamento dei dati a barre OHLCV dagli eventi di trading. Gli eventi con timestamp sono generati da un’entità “timer di simulazione”, con una specifica frequenza (giornaliera/intraday) che interroga un oggetto Exchange
per ricavare gli orari di apertura, al fine di generare una serie di eventi a cui risponderà il backtest.
Invece di lavorare direttamente con le “barre”, l’oggetto Strategy
(la strategia di trading) richiama il metodo get_latest_price_volume(asset)
, che restituisce l’ultimo prezzo di mercato come interpretato dal broker. Dietro le quinte, il Dataframe dei dati OHLCV è interrogati per ricavare il prezzo di mercato corretto per uno specifico timestamp.
Questo significa che la frequenza dei dati OHLCV e la frequenza di generazione del segnale sono disaccoppiati. Ad esempio sarebbe possibile prevedere un ribilanciamento orario con dati a barre di un minuto. Questo rende il passaggio dal backtest al trading dal vivo molto più semplice.
Inoltre l’oggetto Exchange conosce gli orari di chiusura del mercato e le festività specifici per area geografica sia nel passato che nel futuro, riducendo ancora di più il “delta” tra la simulazione del backtest e i risultati del trading in tempo reale.
Modelli Alpha/Previsioni
In tutti i nostri precedenti framework di backtesting basati sugli eventi abbiamo usato un modello Strategy
dove ad ogni iterazione si acquisisce i dati di mercato e si generano oggetti Order
. Questo è certamente sufficiente per un semplice sistema basato su eventi while-loop. Tuttavia, è insufficiente per i requisiti di ricerca di un moderno hedge fund. È necessario un approccio più sofisticato alla previsione.
Negli ambienti quant professionali capita spesso che i ricercatori lavorino per sviluppare “alpha”, cioè previsioni generate su un particolare asset. Questi “alpha” sono spesso combinati in “alpha pesati” che vengono poi inseriti in un modello di costruzione del portafoglio, insieme alle logiche per la gestione del rischio e le stime dei costi di transazione per i ribilanciamenti.
In DataInvestor il concetto di Signal
è stato ampliato come sottoclasse di oggetti Forecast
, che sono generati da un’entità AlphaModel
. Questo permette un approccio multi-strategia al sistema, in cui vari AlphaModels
possono essere combinati per produrre combinazioni di Forecast
. Da notare che l’AlphaModel
non genera un’entità Order
. Questo lavoro è lasciato all’entità PortfolioConstructionModel
descritta nel paragrafo successivo.
Questo framework è estremamente flessibile poichè un’entità Forecast
è contrassegnata da un asset, un valore in virgola mobile (che potrebbe rappresentare quasi ogni tipo di “segnale”) e una data di validità della previsione. All’interno del codice sono presenti alcuni esempi per descrive come tale approccio implementa le tipiche strategie quant come il momentum delle serie temporali, il statistical-arbitrage, la costruzione di fattori e persino le strategie basate sui dati alternativi.
Costruzione del portafoglio
La costruzione del portafoglio è probabilmente il passo più importante nella creazione di un sofisticato modello quantitativo in contesti istituzionali.
DataInvestor prevede la nuova entità PortfolioConstructionModel
(PCM), progettata per sostituire gli oggetti PositionSizer
e RiskManager
, presenti in DataTrader, che agivano su un insieme di oggetti Order
generati da un oggetto Strategy
.
Il PCM di DataInvestor prevede di gestire un RiskModel
e un TransactionCostModel
, che forniscono “opinioni” sulle possibilità di modificare, annullare o aggiungere un insieme di istanze Order
. Ad esempio, il modello di rischio potrebbe voler introdurre una copertura o ridurre l’esposizione a un particolare settore di mercato. Il modello dei costi di transazione può stimare che il costo di un ribilanciamento sia troppo alto rispetto al rendimento atteso dal commercio, e quindi l’ordine verrà annullato.
Il compito del PCM è valutare le “opinioni” del modello alpha, del modello di rischio e dello modello dei costi di transazione al fine di costruire il portafoglio desiderato. Questo portafoglio è quindi confrontato con il portafoglio corrente presso il broker e sono generati una serie di ordini “delta” per aggiornare il portafoglio del broker al portafoglio desiderato.
Chiaramente ci sono molti modi in cui può avvenire la costruzione del portafoglio. Alcuni metodi specifici sono aggiunti a DataInvestor come esempi da modificare o usare come base a seconda dei diversi scopi. Questi metodi includono strutture di base come “pesi uguali”, “pesi con proporzione fissa” e “pesi con volume inverso” (la cosiddetta “risk parity”). Prevediamo anche di implementare sistemi più avanzati come l’ottimizzazione della varianza media (basata sulle idee della Modern Portfolio Theory), un approccio Black-Litterman e tecniche ancora più recenti come la Parità del rischio gerarchico di Marcos Lopez de Prado .
Aggiungendo e testando questi esempi, speriamo che altri utenti saranno in grado di modificarli in base alle proprie esigenze e ridurre al minimo il loro “time to market” per lo sviluppo della propria strategia.
Gestione del rischio e dei costi di transazione
In DataTrader le classi RiskManager
e PositionSizer
possono risultare confuse per alcuni, quindi in DataInvestor abbiamo rivisto questo processo per riflettere una costruzione del portafoglio in stile più istituzionale con un approccio al controllo del rischio più preciso.
La gerarchia delle classi RiskModel
consente il calcolo di varie metriche di rischio, appropriate alla strategia di trading utilizzata. Ad esempio, potrebbe essere progettato per tenere traccia della volatilità degli asset attraverso l’uso di deviazioni standard storiche o utilizzando un modello di volatilità stocastica. Potrebbe anche tenere traccia del rischio di allocazione settoriale e produrre avvisi se l’esposizione di un settore è troppo elevata.
Nelle grandi società di asset allocation i ribilanciamenti vengono spesso effettuati su base settimanale o mensile per ridurre al minimo il tracking error. Esiste un naturale equilibrio tra il tentativo di ridurre al minimo l’errore di tracciamento e al contempo ridurre i costi dovuti a frequenti ribilanciamenti. La gerarchia delle classi TransactionCostModel
è stata introdotta nel tentativo di ribilanciare la quantità dei costi e quindi suggerire che i portafogli siano ribilanciati quando i costi non incidono in modo troppo significativo sulla performance del portafoglio.
Entrambi questi casi forniscono una guida al PCM al fine di aiutare la costruzione del portafoglio ideale. Chiaramente ci sarà qualche sovrapposizione per alcuni modelli. Ad esempio, in un ottimizzatore della varianza media è compito del RiskManager
o del PCM calcolare la matrice di covarianza tra gli asset? Il framework DataInvestor offre una sufficiente flessibilità per consentire che questa decisione sia lasciata al PM o al trader retail che gestisce il conto/portafoglio.
Ciclo di eventi di backtest
La simulazione del backtest di DataTrader usa, all’interno della classe TradingSession
, un semplice ciclo while come gestore degli eventi, per inviare gli eventi a vari componenti all’interno del sistema.
La logica di DataInvestor disaccoppia gli eventi di mercato dai dati a barre OHLCV, in modo da poter gestire eventi “pre-mercato” e “post-mercato” per ogni giorno di trading. Questi eventi consentono di calcolare split di azioni, dividendi in contanti, flussi di cassa degli investitori, calcoli mark-to-market e altri vincoli relativi a broker/exchange al di fuori della principale sessione di negoziazione infragiornaliera.
Ogni entità simulata che deve tenere traccia del tempo ha un metodo update
che è usato per garantire che le informazioni non si propaghino dal futuro al passato, tramite il cosiddetto lookahead bias. Mantiene anche tutti i componenti “sincronizzati”.
Cosa abbiamo implementato finora
Ad oggi abbiamo già implementato la maggior parte della gerarchia Broker
, ad esclusione della gestione dei margini, future e f/x. In particolare sono disponibili i metodi per gestire i flussi di cassa, le piani di commissioni per alcuni broker, la gestione di base dei dividendi in contanti e il monitoraggio generale della posizione.
È stata anche sviluppata una semplice gerarchia Exchange
, sebbene non siano state ancora implementate le specifiche entità di calendario per le principali borse come il NYSE e l’LSE. Inoltre sono gestiti l’acquisizione e l distribuzione dei dati delle barra OHLCV.
La gerarchia PortfolioConstructionModel
è stata parzialmente sviluppata, incluso i metodi con EqualWeightPCM
e FixedWeightPCM.
Fondamentalmente, tutto il codice attualmente impegnato nei rami di refactoring ha ora una copertura del codice del 100%.
Come procederà lo sviluppo
Il processo di sviluppo di DataInvestor è stato radicalmente rivisto. Abbiamo adottato il più avanzato Gitflow Workflow per il controllo delle versioni e l’integrazione continua . Ciò significa che lo sviluppo di tutte le funzionalità avverrà in rami indipendenti, separati dal ramo principale develop
. Periodicamente, queste funzionalità verranno unite develop
e un ramo release-*.*.*
verrà creato con uno specifico numero di versione. Questo ramo release sarà un ramo “fisso nel tempo” completro di test e documentazione, e non consentirà l’aggiunta di nuove funzionalità per quella versione .
Quando una versione è pronta per essere rilasciata, sarà unita al ramo master
, insieme al ramo develop
. Questa versione verrà quindi contrassegnata con un numero di versione specifico per garantire un corretto controllo delle versioni. In questa fase verranno aggiunte nuove funzionalità develop
e il processo continuerà.
Una delle modifiche più significative al flusso di lavoro di sviluppo è il supporto garantito alle versioni di Python maggiori o uguali alla 3.7. È anche probabile che il supporto per alla versione 3.7 venga abbandonato in futuro se alcune funzionalità del codice lo giustificano. Questo è meno preoccupante rispetto a prima data l’ampia accettazione della distribuzione Anaconda di Continuum Analytics , che consente un’installazione semplice di uno stack scientifico Python 3.7 su Windows, Mac e Linux.
Un’altra importante modifica sono la gestione dei test, che ora richiede una copertura del codice del 100% affinché un ramo di rilascio venga unito in master
. Può sembrare un compito arduo, ma data la “criticità della missione” del sistema, sarà fondamentale che ogni riga di codice sia coperta da almeno uno unit test. Abbiamo lavorato duramente per garantire che questo sia il caso della nuova versione e continueremo a farlo con il progredire dello sviluppo.
Le richieste pull della community sono sicuramente benvenute, ma è indispensabile che siano confrontate con il ramo develop
piuttosto che con il ramo master
per mantenere un flusso di lavoro Gitflow.
Elencheremo anche una serie di funzionalità desiderate e forniremo linee guida per gli sviluppatori in modo che i contributi possano essere più diretti in futuro.
Quando sarà disponibile
In questa fase la maggior parte del lavoro è stata aggiunta al nostro repository privato interno, che è separato dal repository pubblico che si trova qui . Nelle prossime settimane il codice sarà reso disponibile sui rami di sviluppo per coloro che sono interessati all’alpha testing in fase iniziale.
Il nostro obiettivo è quello di avere un sistema ben testato pronto per il beta test entro la fine di quest’anno. Forniremo anche aggiornamenti più regolari sull’avanzamento dello sviluppo del sistema mentre continuiamo a codificare nuove funzionalità.
Prossimi Passi
DataInvestor è e sarà sempre un progetto open source, disponibile, liberamente e guidato dalla comunità.
Se desideri essere coinvolto nello sviluppo di DataInvestor e contribuire a plasmare il futuro del progetto, contatta .
Grazie ancora!