QuantConnect-trading-multi-asset

Trading su più asset con QuantConnect

Nei nostri precedenti articoli per QuantConnect ci siamo concentrati solo sul trading di un singolo titolo. Quel titolo non è altro che la prima società al mondo da trilioni di dollari . Ma cosa succede se vogliamo fare trading su più asset contemporaneamente utilizzando la stessa strategia? In questo articolo descriviamo come fare trading su più asset con QuantConnect.

Obiettivo

Partiamo da quanto descritto nel precedente articolo, dove abbiamo esaminato come aggiungere un secondo timeframe ad una semplice strategia RSI. Tuttavia, dopo aver aggiunto il secondo timeframe, abbiamo scoperto che le opportunità sono diventate poche e lontane tra loro. Per affrontare questo problema mantenendo i nostri standard di qualità, possiamo semplicemente cercare opportunità altrove. Inizialmente, potrebbe sembrare un compito semplice. Tuttavia, ci sono alcune complessità che dobbiamo considerare per far funzionare le cose. Ad esempio, se stiamo lavorando con più timeframe, potrebbe non essere facile capire come lavorare con i consolidators o con i gestori di eventi che sono richiamati dai consolidatori. Pertanto, in questo articolo descriviamo i seguenti argomenti:

  • Utilizzo di dizionari e loop per creare gli indicatori, grafici e consolidatori per ciascun titolo.
  • Utilizzo di un’unica chiamata con più consolidatori.
  • Accesso a informazioni aggiuntive da una barra Trade.

Punti di attenzione

Sebbene in questo articolo non introduciamo nuovi concetti, ci sono alcuni potenziali ostacoli che potremmo incontrare quando vogliamo aggiungere più timeframe. Il più importante dei quali è decidere come aggiornare i nostri grafici RSI nel timeframe superiore. (se ti stai chiedendo “quale timeframe superiore?”, vedi l’articolo precedente) Dobbiamo fare attenzione perchè i gestori dei consolidatori lavorano con le tradebars invece che con i dati slice usati all’interno di onData(). Questo è evidente analizzando le dichiarazioni dei metodi (funzioni) del nostro algoritmo: La chiamata On Data – (Standard su ogni script) def OnData(self, data) e il nostro Gestore Consolidator def On_W1(self,sender,bar).

Per andare un po’ più a fondo, le slice dei dati contengono i dati per tutti i simboli che abbiamo aggiunto durante l’inizializzazione. È possibile accedere ai dati di uno specifico titolo fornendo il ticker/simbolo come key, ad es data["AAPL"].Close. Semplice e diretto. D’altra parte, una tradebar contiene solo i dati dello strumento che è stato consolidato. Pertanto, dobbiamo creare un gestore per ogni feed (il che sarebbe un po’ ingombrante) oppure possiamo utilizzare il metodo get_Symbol() per determinare da quale stock proviene la barra e quindi agire in modo appropriato. Nel seguente codice di esempio usiamo questa seconda opzione. Un altro grattacapo che potremmo avere è capire come aggiungere tutti gli strumenti e i rispettivi indicatori senza duplicare il codice. Abbiamo una situazione simile quando vogliamo gestire l’evento OnData().

Il seguente esempio affronta questo problema utilizzando una combinazione di for-loopsdictionaries.

Trading su più asset con QuantConnect

				
					### <summary>
### Semplice strategia RSI che vuole fornire un esempio di un algoritmo
### usando un indicatore
### </summary>
#region imports
from AlgorithmImports import *
from datetime import timedelta
#endregion

class RSIAlgorithm(QCAlgorithm):

    # 1 - Aggiungere le FANG stocks (Facebook, Amazon, , Netflix, Google)
    # 2 - Ciclo attraverso le stocks
    # 3 - Aggiungere una equity per ogni stock
    # 3 - Creare un dizionario di indicatori

    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.'''
        
        # Impostazione parametri strategia
        self.SetStartDate(2016,1, 1)   # Data inizio
        self.SetEndDate(2020,1,1)      # Data Fine
        self.SetCash(10000)            # Capitale iniziale
        
        RSI_Period    = 14                # periodo del RSI
        self.RSI_OB   = 75                # Livello overcomprato
        self.RSI_OS   = 50                # Livello overvenduto
        self.Allocate = 0.20              # Percentuale di capitale allocato
        
        self.Equities = ["AAPL", "FB", "AMZN", "NFLX", "GOOG"]
        
        self.Indicators = dict()
        self.Charts = dict()
        self.Consolidators = dict()

        # Altri ticker sono disponibili in https://www.quantconnect.com/datasets/
        for Symbol in self.Equities:
            self.Consolidators[Symbol] = dict()
            self.AddEquity(Symbol, Resolution.Daily)
                 
            # Ogni Equity richiede il proprio consolidatore! Vedere:
            # https://www.quantconnect.com/forum/discussion/1936/multiple-consolidators/p1
            # https://www.quantconnect.com/forum/discussion/1587/multiple-symbol-indicator-values-in-consolidated-bar-handler/p1
            # ------------------------
            # Creare i consolidatori
            self.Consolidators[Symbol]['W1 Con'] = TradeBarConsolidator(timedelta(days=5))
            
            # Registrare gli Handlers
            self.Consolidators[Symbol]['W1 Con'].DataConsolidated += self.On_W1
        
            self.Indicators[Symbol] = dict()
            self.Indicators[Symbol]['RSI'] = dict()
            
            self.Indicators[Symbol]['RSI']['D'] = self.RSI(Symbol, RSI_Period)
            self.Indicators[Symbol]['RSI']['W'] = RelativeStrengthIndex(Symbol, RSI_Period)

            # Registrare gli indicatori con il titolo e il consolidatore
            self.RegisterIndicator(Symbol, self.Indicators[Symbol]['RSI']['W'], self.Consolidators[Symbol]['W1 Con'])
        
            # Aggiungere i consolidatori al subscription manager in modo 
            # da ricevere gli aggiornamenti dal motore
            self.SubscriptionManager.AddConsolidator(Symbol, self.Consolidators[Symbol]['W1 Con'])
        
            self.Charts[Symbol] = dict()
            # Grafico RSI
            RSIChartName = Symbol+" RSI"
            self.Charts[Symbol]['RSI'] = Chart(RSIChartName, ChartType.Stacked)
            self.Charts[Symbol]['RSI'].AddSeries(Series("D1", SeriesType.Line))
            self.Charts[Symbol]['RSI'].AddSeries(Series("W1", SeriesType.Line))
            self.AddChart(self.Charts[Symbol]['RSI'])
            
            # Creare un grafico custom per il volume
            VolChartName = Symbol+" Volume"
            self.Charts[Symbol]['VOL'] = Chart(VolChartName, ChartType.Stacked)
            self.Charts[Symbol]['VOL'].AddSeries(Series('Buying Volume', SeriesType.Bar))
            self.Charts[Symbol]['VOL'].AddSeries(Series('Selling Volume', SeriesType.Bar))
            self.AddChart(self.Charts[Symbol]['VOL'])
        
        # Verifica che gli indicatori haano abbasta dati prima di iniziare il trading,
        # x5 è sufficiente per i dati settimanali
        self.SetWarmUp(RSI_Period*5)


    def On_W1(self,sender,bar):
        '''
        This method will be called every time a new 30 minute bar is ready. 
   
        bar = The incoming Tradebar. This is different to the data object in OnData()
        '''
        if self.IsWarmingUp: return
    
        Symbol = str(bar.get_Symbol())
        self.Plot(Symbol+' RSI', 'W1', self.Indicators[Symbol]['RSI']['W'].Current.Value)
        
        
    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 self.IsWarmingUp: return
        
        # Ciclo attraverso i simboli
        for Symbol in self.Equities:
            
            # aggiungere alias per facile lettura
            Close = data[Symbol].Close
            Volume = data[Symbol].Volume
            D1_RSI = self.Indicators[Symbol]['RSI']['D'].Current.Value
            W1_RSI = self.Indicators[Symbol]['RSI']['W'].Current.Value
            
            self.Debug("{}: Close: {} RSI: {}".format(Symbol, Close, D1_RSI))
            
            if data[Symbol].Close >= data[Symbol].Open:
                self.Plot(Symbol+" Volume", 'Buying Volume', Volume)
            else:
                self.Plot(Symbol+" Volume", 'Selling Volume', Volume)
                
            self.Plot(Symbol +' RSI', 'D1', D1_RSI)
        
            # Determinare le condizioni di entrata e uscita
            Long_Cond1 = D1_RSI < self.RSI_OS
            Long_Cond2 = W1_RSI < self.RSI_OS
            Exit_Cond1 = D1_RSI > self.RSI_OB
            Exit_Cond2 = W1_RSI > self.RSI_OB  
        
            if not self.Securities[Symbol].Invested:
                # Condizione Long
                if all([Long_Cond1, Long_Cond2]):
                    # Compra
                    self.SetHoldings(Symbol, self.Allocate)
            else:
            
                if all([Exit_Cond1, Exit_Cond2]):
                    # Vendi
                    self.Liquidate(Symbol)
				
			

La prima modifica che abbiamo effettuato per fare trading su più asset con QuantConnect è semplicemente quello di aggiungere un elenco di azioni FANG da aggiungere a AAPL all’interno dell’algoritmo. Questo elenco di azioni viene utilizzato ogni volta che si genera un ciclo for. Successivamente, creiamo una serie di dizionari, questi dizionari sono usati per memorizzare i dati specifici per ogni simbolo dell’elenco. I dati sono aggiunti nel primo ciclo for dove scorriamo l’elenco aggiungendo consolidatori, indicatori e grafici ai dizionari usando il simbolo come chiave. L’utilizzo dei simboli come chiave ci consente di recuperare o aggiornare facilmente l’indicatore o il grafico corretto in qualsiasi momento, quando iniziamo a ricevere i dati. Ad esempio con ‘istruzione self.Indicators[Symbol]['RSI']['D'] = self.RSI(Symbol, RSI_Period) stiamo creando un indicatore RSI giornaliero che può essere facilmente recuperato successivamente estraendo  il valore dal dizionario  tramite le chiavi self.Indicators['AAPL']['RSI']['D'] In realtà non specifichiamo il nome del simbolo AAPL, ma usiamo sempre la variabile Symbol del ciclo for. Tuttavia, a scopo illustrativo abbiamo ho scritto AAPL dato che è un altro valido modo per accedervi e aiuta anche a capire il concetto.

Metodo On_W1()

Nel codice abbiamo assegnato lo stesso gestore a tutti i singoli consolidatori. Determinare cosa fare con i dati è in realtà più facile di quanto possa sembrare a prima vista. Nell’esempio, utilizziamo solo il metodo bar.get_Symbol() per ottenere il simbolo/ticker dell’asset a cui appartiene la barra. Quindi è facile aggiornare il grafico corretto.

				
					Symbol = str(bar.get_Symbol())
self.Plot(Symbol+' RSI', 'W1', self.Indicators[Symbol]['RSI']['W'].Current.Value)
				
			

Metodo OnData()

Come accennato in precedenza, il parametro data passata alla chiamata OnData() contiene un’istantanea dei dati per tutti i simboli contemporaneamente. Pertanto, proprio come durante Initialize(), possiamo semplicemente scorrere il nostro elenco self.equtities per valutare le informazioni di cui abbiamo bisogno, aggiornare i grafici e prendere una decisione operativa. Da notare che non usiamo più self.portfolio.invested per determinare se abbiamo una posizione aperta. Invece, usiamo self.Securities[Symbol].Invested poiché ci consente di verificare una posizione aperta alla volta. Vogliamo solo verificare che non stiamo effettuando un secondo ordine sullo stesso titolo.

Esecuzione del codice

Dopo aver eseguito il codice per fare trading su più asset con QuantConnect otteniamo qualcosa di simile a quando segue:

QuantConnect-Multiple-Instruments-Chart

Come puoi vedere, abbiamo un grafico separato sul lato destro per ciascuno dei grafici RSI e Volume. Complessivamente abbiamo effettuato 20 operazioni durante il periodo di prova. Nella scheda “Orders” possiamo vedere che abbiamo effettuato operazioni su ciascuno degli asset in elenco.

QuantConnect-Trades-List

Codice completo

In questo articolo abbiamo descritto come fare trading su più asset 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