gestire i dividendi azionari con QuantConnect

Gestire gli Split e i Dividendi con QuantConnect

In questo articolo descriviamo come gestire gli split e i dividendi con QuantConnect. I dividendi sono una parte fondamentale degli investimenti, eppure sono spesso trascurati nel mondo del backtesting. Questo può essere causato dai framework che generalmente non forniscono i dati o gli strumenti specifici necessari per gestire un dividendo. Di conseguenza, gli utenti finali  devono trovare dati rettificati da terze parti come Alpha VantageFortunatamente per gli utenti di QuantConnect, la piattaforma rende disponibili i dati sui dividendi e gli strumenti per gestirli, in modo semplice come impostare una singola opzione di inizializzazione.

Obiettivo

Con questo articolo esaminiamo come accedere alle informazioni sui dividendi e alle varie opzioni per gestirli all’interno di una strategia Buy & Hold. Nota: sebbene rivolto ai principianti, questo post presuppone che il lettore abbia familiarità con il funzionamento dei meccanismi di base di uno script su QuantConnect. Se arrivi da un’altra piattaforma o sei un principiante assoluto, dai un’occhiata agli altri articoli della serie introduttiva .

Accesso ai dividendi

Su QuantConnect non è necessario aggiungere uno specifico feed di dati per i dividendi. Quando si verificano, gli “eventi” dei dividendi sono inviati alle strategie allo stesso modo dei dati OHLCV. Gli eventi sono contenuti all’interno della “fetta” di dati che viene passata alla funzione OnData(). La documentazione ufficiale fornisce una panoramica dei diversi tipi di dati che vengono inviate ai nostri algoritmi: https://www.quantconnect.com/docs/algorithm-reference/handling-data.

Personalmente penso che l’esempio, DividendAlgorithm.py di QuantConnect lo rende il concetto molto più chiaro. L’esempio vale più di mille parole ed è così ben fatto che lo usiamo come base per creare il nostro esempio di codice. Per riassumere, possiamo accedere al dividendo (se presente) tramite uno speciale oggetto/tipo di dati contenuto nella nostra slice data. Per essere più specifici, vi accediamo utilizzando  data.Dividends. Da notare che Dividends può essere iterato (in loop) per accedere alle informazioni sui dividendi. Se non è disponibile alcun dividendo (nei giorni in cui non è disponibile), il codice all’interno del ciclo non verrà eseguito o causerà un errore. L’esempio ufficiale implementa questa logica con l’istruzione for kvp in data.Dividends.

Gestione dei dividendi

Ora che sappiamo come accedere alle informazioni sui dividendi, dobbiamo capire come gestire gli split e i dividendi con QuantConnect. Come accennato in precedenza, QuantConnect ci fornisce alcune opzioni su come gestire i dividendi. Non ci limitiamo semplicemente ad aggiustare i dati come nelle altre piattaforme (anche se possiamo farlo se vogliamo!), ma possiamo decidere di ricevere i dividendi in contanti sul nostro conto. Queste opzioni non sono trattate nella documentazione online del link precedente o nell’esempio DividendAlgorithm.py, ma possono essere trovate con un po’ di paziente ricerca. Le opzioni rientrano in una categoria denominata “Modalità di normalizzazione dei dati” e l’impostazione di modalità  diverse influisce sulla  gestione degli aggiornamenti del saldo di liquidità o sulla gestione dell’aggiustamento dei prezzi. Nota: durante la mia ricerca, non sono riuscito a trovare le modalità di normalizzazione dei dati nella documentazione ufficiale ma li ho scoperti attraverso i forum. Di seguito la citazione completa di un post sul forum:

Vuoi i prezzi grezzi degli asset, con  i dividendi pagati in contanti e gli adeguamenti agli split della quantità delle tue partecipazioni? Questo è abbastanza vicino alla realtà e può essere ottenuto con la nuova impostazione:  DataNormalizationMode.Raw.
Preferiresti split adeguati al prezzo, ma  i dividendi pagati in contanti? Questo è l’ideale per la creazione di grafici poiché il prezzo è continuo, ma i dividendi vengono comunque pagati in contanti. Puoi utilizzare questa modalità con:  DataNormalizationMode.SplitAdjusted.
Che ne dici dei grafici Total Return? Dove i dividendi vengono aggiunti al prezzo dell’asset, quindi il prezzo totale dell’asset include la somma dei dividendi? Questa è una tecnica popolare per tenere conto della ricezione e del reinvestimento dei dividendi. Puoi accedere a questa modalità con:  DataNormalizationMode.TotalReturn

Fonte:  https://www.quantconnect.com/forum/discussion/508/update-dividends-splits-and-custom-price-normalization/p1.

Le modalità di normalizzazione dei dati vengono impostate durante l’inizializzazione del nostro algoritmo, come descritto nel seguente esempio.

Gestire gli Split e i Dividendi con QuantConnect

				
					### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
# region imports
from AlgorithmImports import *
import numpy as np
# endregion

class BasicTemplateAlgorithm(QCAlgorithm):
    '''Basic template algorithm simply initializes the date range and cash'''

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        
        self.ticker = 'MSFT'
        self.raw_handling = True
        
        self.SetStartDate(2018,5,11)   #Data inizio
        self.SetEndDate(2018,5,22)    #Data Fine
        self.SetCash(10000)           #Capitale iniziale

        # Altri simboli qui: https://www.quantconnect.com/datasets/
        self.AddEquity(self.ticker, Resolution.Daily)
        
        # Impostazione del metodo per gestire i dividendi
        # https://www.quantconnect.com/forum/discussion/508/update-dividends-splits-and-custom-price-normalization/p1
        if self.raw_handling:
            self.Securities[self.ticker].SetDataNormalizationMode(DataNormalizationMode.Raw)
        else:
            self.Securities[self.ticker].SetDataNormalizationMode(DataNormalizationMode.TotalReturn)

    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        if not self.Portfolio.Invested:
            self.SetHoldings(self.ticker, 1)
            
        for kvp in data.Dividends: # aggiornare il dizionario degli eventi
            div_ticker = kvp.Key
            div_distribution = kvp.Value.Distribution
            div_total_value = div_distribution * self.Portfolio[self.ticker].Quantity
            self.Log("{0} >> DIVIDEND >> {1} - ${2} - ${3}".format(self.Time, div_ticker, div_distribution, div_total_value))

        self.Log("{0} >> SUMMARY >> {1} | Port Cash: {2} | Port Value: {3} | Holdings: {4} | Price {5}".format(self.Time, 
            self.ticker, self.Portfolio.Cash, self.Portfolio.TotalPortfolioValue, self.Portfolio[self.ticker].Quantity, self.Portfolio[self.ticker].Price))
				
			

Poiché questo articolo è incentrato sui dividendi e non sugli split, il codice dell’esempio i concentra sul test  delle modalità di normalizzazione dei dati  grezzi (raw)  e dei rendimenti totali (total returns). Impostiamo la modalità di normalizzazione durante Initialize() con una semplice istruzione: self.Securities[self.ticker].SetDataNormalizationMode(DataNormalizationMode.XYZ). Naturalmente, nel codice di esempio, abbiamo due versioni di questa riga. Sono racchiusi in un’istruzione ifelse per consentire un facile passaggio da una modalità all’altra. Sostituiamo anche XYZ con i nomi delle modalità (Raw e TotalReturns). Tecnicamente, questo è tutto ciò che dobbiamo fare! Seleziona il metodo di normalizzazione preferito e i dividendi verranno gestiti automaticamente. I dividendi sono accreditati in contatti nel conto account o  si aggiusta automaticamente il prezzo. È molto semplice. Tuttavia, dal momento che stiamo imparando, esplorando e studiando come funzionano i dividendi in QuantConnect, sono state aggiunte alcune informazioni extra nel log del backtest in modo da poter esaminare i meccanismi. Questo ci permette di ottenere una migliore comprensione di come funziona il motore.

Verifica dell’output

Per vedere come le modalità di normalizzazione influenzano il backtest, possiamo dare un’occhiata ai log intorno alla data in cui si verifica il dividendo. Si noti che nel nostro esempio, l’intervallo di date utilizzato è abbastanza specifico per Microsoft. I dati iniziano alcuni giorni prima di un dividendo e terminano subito dopo.

Normalizzazione dei dati grezzi

L’output seguente è una copia del file di registro generato dall’esecuzione del codice come descritto in precedenza.

				
					2018-05-11 00:00:00 Launching analysis for 219e50fc60d127405081a29f5e1ded58 with LEAN Engine v2.5.0.0.15052
2018-05-11 00:00:00 2018-05-11 00:00:00 >> SUMMARY >> MSFT | Port Cash: 10000.0 | Port Value: 10000.0 | Holdings: 0.0 | Price 97.91
2018-05-12 00:00:00 2018-05-12 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9994.96 | Holdings: 101.0 | Price 97.7
2018-05-15 00:00:00 2018-05-15 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 10028.29 | Holdings: 101.0 | Price 98.03
2018-05-16 00:00:00 2018-05-16 00:00:00 >> DIVIDEND >> MSFT - $0.42 - $42.42
2018-05-16 00:00:00 2018-05-16 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 9999.0 | Holdings: 101.0 | Price 97.32
2018-05-17 00:00:00 2018-05-17 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 9981.83 | Holdings: 101.0 | Price 97.15
2018-05-18 00:00:00 2018-05-18 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 9883.86 | Holdings: 101.0 | Price 96.18
2018-05-19 00:00:00 2018-05-19 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 9902.04 | Holdings: 101.0 | Price 96.36
2018-05-22 00:00:00 2018-05-22 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 10027.28 | Holdings: 101.0 | Price 97.6
2018-05-23 00:00:00 2018-05-23 00:00:00 >> SUMMARY >> MSFT | Port Cash: 169.68 | Port Value: 10017.18 | Holdings: 101.0 | Price 97.5
2018-05-23 00:00:00 Algorithm Id:(219e50fc60d127405081a29f5e1ded58) completed in 0.43 seconds at 0k data points per second. Processing total of 74 data points.

				
			

Se diamo un’occhiata da vicino ai log, possiamo vedere che il 2018-05-16 abbiamo ricevuto un dividendo di $ 42,42. Possiamo anche vedere che la liquidità sale a $ 174,73 da $ 132,31 del giorno prima (un aumento di $ 42,42). Quello facciamo con quei soldi dipende solo da noi. Potremmo reinvestirlo o forse simulare il pensionamento e presumere che dovremmo accumulare il x% e reinvestire solo il resto? Con la modalità di normalizzazione dei dati RAW, possiamo verificare questi scenari!

Normalizzazione dei dati di rendimento totale

Per testare la modalità di normalizzazione TotalReurn, dobbiamo modificare la riga seguente da self.raw_handling = Trueself.raw_handling = False in modo da attivare la modalità di normalizzazione TotalReturn e otteniamo il seguente output.

				
					2018-05-11 00:00:00 Launching analysis for 580f5feaaf9bf6e7937ded9666c80604 with LEAN Engine v2.5.0.0.15052
2018-05-11 00:00:00 2018-05-11 00:00:00 >> SUMMARY >> MSFT | Port Cash: 10000.0 | Port Value: 10000.0 | Holdings: 0.0 | Price 97.91
2018-05-12 00:00:00 2018-05-12 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9994.96 | Holdings: 101.0 | Price 97.7
2018-05-15 00:00:00 2018-05-15 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 10028.29 | Holdings: 101.0 | Price 98.03
2018-05-16 00:00:00 2018-05-16 00:00:00 >> DIVIDEND >> MSFT - $0.42 - $42.42
2018-05-16 00:00:00 2018-05-16 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9956.58 | Holdings: 101.0 | Price 97.32
2018-05-17 00:00:00 2018-05-17 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9981.83 | Holdings: 101.0 | Price 97.57
2018-05-18 00:00:00 2018-05-18 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9883.86 | Holdings: 101.0 | Price 96.6
2018-05-19 00:00:00 2018-05-19 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 9902.04 | Holdings: 101.0 | Price 96.78
2018-05-22 00:00:00 2018-05-22 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 10027.28 | Holdings: 101.0 | Price 98.02
2018-05-23 00:00:00 2018-05-23 00:00:00 >> SUMMARY >> MSFT | Port Cash: 127.26 | Port Value: 10017.18 | Holdings: 101.0 | Price 97.92
2018-05-23 00:00:00 Algorithm Id:(580f5feaaf9bf6e7937ded9666c80604) completed in 0.45 seconds at 0k data points per second. Processing total of 74 data points.

				
			

Possiamo vedere che il prezzo delle azioni e la liquidità del conto sono sincronizzati fino al  giorno del dividendo. Dopo il dividendo, i due esempi divergono. In questo caso, la nostra liquidità rimane la stessa di prima del dividendo e il prezzo viene quindi aggiustato dal 2018-05-17. $ 97,57 in modalità TotalReturn contro $ 97,15 in modalità Raw.

Date ex-div

Prima di concludere, vale la pena sottolineare che quando la modalità di normalizzazione dei dati è impostata su Raw, il contante viene versato sul conto alla data di stacco  della cedola e non alla data di pagamento. Possiamo verificarlo confrondando la distribuzione con le date ex dividendo riportate in altre  risorse onlineQuesto è qualcosa di cui essere consapevoli poiché normalmente non riceveresti i contanti per il dividendo alla data ex-div. I pagamenti sono generalmente circa 1 mese dopo la data ex-div. Se poi reinvesti immediatamente il denaro, quel denaro rimarrà sul mercato molto più a lungo di quanto potrebbe essere nel mondo reale. Questo, a sua volta, può influenzare il realismo dei risultati del backtesting.

Codice completo

In questo articolo abbiamo descritto come gestire gli split e i dividendi con QuantConnect. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/QuantConnect

Gli altri articoli di questa serie

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