In questo articolo descriviamo come aggiungere timeframe con QuantConnect per personalizzare un algoritmo, dato che QuantConnect fornisce solo feed di dati Tick, Second, Minute, Hourly e Daily. Quindi, come possiamo fare trading su un timeframe settimanale, di 15 minuti, 30 minuti o di 4 ore? Vediamo come fare!
Obiettivo
Vogliamo creare un timeframe “settimanale” personalizzato e aggiungerlo ad un algoritmo. Il timeframe settimanale è utilizzato nella strategia per confermare le entrate in posizione tramite un secondo indicatore RSI. Oltre a questo, vogliamo anche aggiungere la serie con timeframe settimanale al grafico RSI. Tuttavia, il “come e perché ” aggiungere una serie ad un grafico non sono descritti dato che tutti i dettagli sono stati condivisi nel precedente articolo. A prima vista, lo scopo di questo articolol può sembrare relativamente semplice. Tuttavia, ci sono alcuni specifici passaggi che dobbiamo compiere per creare un timeframe personalizzato e aggiungere un indicatore. Pertanto, l’articolo descrive dettagliatamente i seguenti argomenti:
- Consolidatori: cosa sono e come si usano.
- Uno sguardo alle differenze tra tradebar e quotebar.
- Registrazione di un indicatore con un timeframe personalizzato.
- Come evitare un errore di runtime “Forward Only Indicator”.
Consolidatori
I consolidatori rispondono alla domanda “come posso utilizzare il timeframe XYZ se QuantConnect non fornisce i dati per esso?”. Anche se è improbabile che “consolidator” sia la prima parola che verrebbe in mente quando si cerca documentazione su “come accedere ai feed di dati con timeframe di 30 minuti”, il nome è in realtà abbastanza appropriato. Un “consolidator” consoliderà i dati più piccoli in dati più grandi. Quindi, ad esempio, possiamo prendere dati di 1 minuto ed aggregare 30 barre di 1 minuto in un’unica barra di 30 minuti. Sebbene imparare ad usare i consolidatori possa richiedere un po’ più di tempo, utilizzarli per creare intervalli di tempo personalizzati presenta un paio di vantaggi chiave:
- Possiamo creare qualsiasi timeframe a cui possiamo pensare! Non abbiamo bisogno di attenerci ai soliti timeframe da 1 minuto, 5 minuti, 15 minuti ecc. Possiamo creare un data feed di 25 tick, 17 secondi o 12 minuti!
- Significa che QuantConnect non ha bisogno di archiviare o elaborare tutti questi dati per nostro conto.
Quindi, in generale, scambiamo un po’ di complessità con una maggiore flessibilità. Ad esempio, invece di richiedere semplicemente la risoluzione che desideriamo quando aggiungiamo lo strumento (come facciamo con i dati Tick, Second, Minute e Daily), dobbiamo eseguire i seguenti passaggi (che verranno trattati nel successivo esempio):
- Creare una classe “consolidator”.
- Creare un gestore. Questo è un metodo (funzione) che viene chiamato/eseguito ogni volta che viene creata una nuova barra di dati consolidati.
- Aggiungere il consolidatore tramite il
SubscriptionManager
.
Dopo questi passaggi, dobbiamo selezionare il tipo di consolidatore corretto in base alle nostre esigenze. In realtà ci sono quattro tipi di consolidatore tra cui puoi scegliere:
TickConsolidator
TickQuoteBarConsolidator
TradeBarConsolidator
QuoteBarConsolidator
I quattro consolidatori di cui sopra rientrano in due grandi categorie, consolidatori TradeBar e QuoteBar. Quindi qual è la differenza tra loro e come sappiamo quale usare?
Barre Trade Vs barre Quote
Le barre di tipo Trade contengono i dati Open
, high
, low
,close
e volume
. Questi sono i prezzi “medi”, dove il prezzo medio è la media tra i prezzi bid
e ask
. I prezzi medi sono quelli che ti vengono dati quando vedi che Stock XYZ è a $ 200. Al contrario, le Quote Bars contengono effettivamente i dati bid
e ask
. Con le informazioni bid
e ask
, possiamo effettivamente vedere lo spread (la differenza tra bid e ask) e ottenere risultati di backtesting più accurati. Per maggiori informazioni in merito ai prezzi bid
e ask
si può consultare il seguente link: https://www.investopedia.com/terms/b/bid-and-ask.asp
Selezione del corretto consolidatore
Quindi, ora che conosciamo la differenza tra i due gruppi, come facciamo a sapere quale utilizzare con i nostri dati? Fortunatamente la documentazione di QuantConnect ci può aiutare:
Per ogni classe di asset e di dati che forniamo, consultare la data library. È un po’ confusa, ma ecco il riepilogo dei dati forniti da QuantConnect:
- Azioni: solo dati Trade. Per Resolution.Tick usa TickConsolidator, per tutte le altre risoluzioni usa TradeBarConsolidator.
- Forex e CFD: solo dati Quote. Per Resolution.Tick usa TickQuoteBarConsolidator, per tutte le altre risoluzioni usa QuoteBarConsolidators.
- Opzioni: dati Trade e Quote, solo su Resolution.Minute. Per consolidare i dati delle opzioni usa TradeBarConsolidator o QuoteBarConsolidator (a seconda che tu stia consolidando operazioni o quotazioni).
- Futures: dati Trade e Quote, risoluzioni al tick, al secondo e al minuto.
Fonte: https://www.quantconnect.com/docs/v2/writing-algorithms/consolidating-data/getting-started.
Quindi, se vogliamo aggiungere un asset che dispone solo di dati Trade (come le azioni), allora dobbiamo usare il TradeBarConsolidator
. Allo stesso modo, per gli asset che hanno solo dati Quote (come FX) utilizziamo il formato QuoteBarConsolidator
.
Aggiungere timeframe con QuantConnect
Ora che abbiamo capito i concetti alla base dei consolidators, tradebar e quotebar, vediamo il codice per aggiungere timeframe con QuantConnect.
###
### Semplice strategia RSI che vuole fornire un esempio di un algoritmo
### usando un indicatore
###
#region imports
from AlgorithmImports import *
from datetime import timedelta
#endregion
class RSIAlgorithm(QCAlgorithm):
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(2012,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 = 60 # Livello overcomprato
self.RSI_OS = 40 # Livello overvenduto
self.Allocate = 0.25 # Percentuale di capitale allocato
# Altri ticker sono disponibili in https://www.quantconnect.com/datasets/
self.AddEquity("AAPL", Resolution.Daily)
# Creare i consolidatori
W1_Con = TradeBarConsolidator(timedelta(days=5))
# Registrare gli Handlers
W1_Con.DataConsolidated += self.On_W1
# Creare gli indicatori
self.RSI_Ind = self.RSI("AAPL", RSI_Period)
self.W1_RSI = RelativeStrengthIndex("AAPL", RSI_Period)
# Registrare gli indicatori per l'asset e il consolidatore
self.RegisterIndicator("AAPL", self.W1_RSI, W1_Con)
# Aggiungere i consolidatori al manager delle sottoscrizioni
# in modo da ricevere aggiornamente dal motore
self.SubscriptionManager.AddConsolidator("AAPL", W1_Con)
# Verifica che gli indicatori haano abbasta dati prima di iniziare il trading,
# x5 è sufficiente per i dati settimanali
self.SetWarmUp(RSI_Period*5)
# Grafico il RSI
RSIChart = Chart("RSI", ChartType.Stacked)
RSIChart.AddSeries(Series("D1", SeriesType.Line))
RSIChart.AddSeries(Series("W1", SeriesType.Line))
self.AddChart(RSIChart)
# Creazione di un grafico custom per i volumi
VolChart = Chart("Volume", ChartType.Stacked)
VolChart.AddSeries(Series('Buying Volume', SeriesType.Bar))
VolChart.AddSeries(Series('Selling Volume', SeriesType.Bar))
self.AddChart(VolChart)
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()
'''
self.Plot('RSI', 'W1', self.W1_RSI.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
'''
self.Plot('RSI', 'D1', self.RSI_Ind.Current.Value)
if data["AAPL"] is not None:
if data["AAPL"].Close >= data["AAPL"].Open:
self.Plot('Volume', 'Buying Volume', data["AAPL"].Volume)
else:
self.Plot('Volume', 'Selling Volume', data["AAPL"].Volume)
# Assicura che non siamo in warm up
if self.IsWarmingUp: return
# Determina le condizioni di entrata e uscita
long_cond1 = self.RSI_Ind.Current.Value < self.RSI_OS
long_cond2 = self.W1_RSI.Current.Value < self.RSI_OS
exit_cond1 = self.RSI_Ind.Current.Value > self.RSI_OB
exit_cond2 = self.W1_RSI.Current.Value > self.RSI_OB
# Verifica se siamo a mercato
if not self.Portfolio.Invested:
# Se siamo flat verifichiamo l'RSI
if all([long_cond1, long_cond2]):
# Compriamo Apple
self.SetHoldings("AAPL", self.Allocate)
else:
if all([exit_cond1, exit_cond2]):
# Vendiamo Apple
self.Liquidate("AAPL")
Rispetto al precedente articolo sulla visualizzazione dei grafici, il metodo initialize()
è cresciuto in modo significativo. È qui che implementiamo la maggior parte del lavoro per aggiungere il timeframe personalizzato e un secondo indicatore. Tuttavia, prima di tutto ciò, dobbiamo importare un modulo python all’inizio dello script: from datetime import timedelta
. Quindi utilizziamo la funzione importata timedelta
per impostare la quantità di dati che il consolidatore deve utilizzare nel comando W1_Con = TradeBarConsolidator(timedelta(days=5))
. Qui, stiamo creando il consolidatore W1_Con
utilizzando la classe TradeBarConsolidator
, dato che AAPL
è un’equity la documentazione di QuantConnect dice che sono disponibili solo i dati Trade). Successivamente, passiamo al TradeBarConsolidator
un delta temporale di 5 giorni (che è una settimana nei mercati azionari). Ad esempio, se vogliamo creare un timeframe di 30 minuti per FX, dobbiamo fare 2 cose:
- Importare i dati Forex MINUTE utilizzando il metodo
AddForex()
- Usare un consolidatore
QuotebarConsolidator
, con untimedelta(minutes=30)
.
Creazione e registrazione dei gestori
Come accennato nella sezione precedente sui consolidatori, dobbiamo creare un gestore che viene chiamato ogni volta che è pronta una nuova barra di dati. Pertanto abbiamo aggiunto:
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()
'''
self.Plot('RSI', 'W1', self.W1_RSI.Current.Value)
Possiamo dare a questo gestore qualsiasi nome desideriamo. Nel nostro codice di esempio, è stato denominato On_W1()
. Da notare che nel metodo non facciamo altro che visualizzare il grafico del valore RSI. La principale logica di ingresso/uscita è comunque eseguita nel timeframe inferiore all’interno del metodo On_Data()
. Dopo aver ottenuto il gestore, possiamo registrarlo nel metodo initialize()
con il comando: W1_Con.DataConsolidated += self.On_W1
. Coloro che conoscono il linguaggio Python avranno familiarità con l’uso dell’operatore +=
per aggiungere un numero a una variabile corrente, ad es x += 1
. Tuttavia, l’operatore +=
può fare altre cose. Un’ottima introduzione è l’ottima risposta presente su questo post su stack overflow: https://stackoverflow.com/questions/4841436/what-exactly-does-do-in-python. Infine, aggiungiamo il timeframe all’algoritmo tramite il Subscription Manager con il comando : self.SubscriptionManager.AddConsolidator("AAPL", W1_Con)
.
Nota: questi sono tutti i passaggi necessari per aggiungere un timeframe all’algoritmo. Potremmo fermarci qui se se non desideriamo aggiungere indicatori al timeframe.
Creazione e registrazione dell’indicatore RSI
Poiché il nostro obiettivo è utilizzare un secondo timeframe superiore per la conferma dell’operazione, dobbiamo registrare un indicatore RSI nel secondo timeframe. Questo viene fatto in un modo leggermente diverso da come abbiamo aggiunto l’indicatore RSI nel primo script e se non effettuato correttamente, possiamo avere risultati completamente errati.
# Creare gli indicatori
self.RSI_Ind = self.RSI("AAPL", RSI_Period)
self.W1_RSI = RelativeStrengthIndex("AAPL", RSI_Period)
# Registrare gli indicatori per l'asset e il consolidatore
self.RegisterIndicator("AAPL", self.W1_RSI, W1_Con)
Il primo indicatore self.RSI_Ind
viene creato esattamente nello stesso modo descritto nel primo script. Tuttavia, da notare la differenza tra self.W1_RSI
e self.RSI_Ind
usano chiamate API diverse. Se proviamo a creare l’indicatore RSI settimanale con l’istruzione self.RSI()
, otteniamo il seguente errore.
Runtime Error: This is a forward only indicator:
Quando ho iniziato ad utilizzare la piattaforma QuantConnect, questo errore mi ha lasciato perplesso per una o due ore. Stavo creando entrambi gli indicatori usando self.RSI()
. Ovviamente, ora so che questo NON è il modo corretto per farlo per i feed di dati consolidati. Diamo un’occhiata al motivo per cui viene visualizzato l’errore. Quando usiamo self.RSI()
, in realtà stiamo usando uno dei metodi “helper” di QuantConnect. È una scorciatoia che fa alcune cose dietro le quinte per risparmiare righe di codice. In questo caso, registra l’indicatore “automaticamente”, quindi se poi lo registriamo noi stessi nel timeframe settimanale, lo stesso indicatore sarà stato registrato due volte portando all’errore. Quindi riassumendo:
RSI("AAPL", RSI_Period)
: è un metodo di supporto.RelativeStrengthIndex("AAPL", RSI_Period)
: è quello che dovremmo usare. QuantConnect si riferisce a questo come al “costruttore”.
Per approfondimenti si pò far riferimento a questo post utile: https://www.quantconnect.com/forum/discussion/2217/consolidated-bar-indicators/p1. Pertanto, la soluzione per evitare questo errore è assicurarsi di creare solo indicatori utilizzando il costruttore. Lo stesso vale per gli altri indicatori EMA
, quindi è necessario fare attenzione!
Esecuzione dello script
Dopo aver eseguito lo script, otteniamo un grafico che assomiglia a questo:
E se diamo un’occhiata al grafico RSI possiamo vedere che entrambi i timeframe sono tracciati.
Codice completo
In questo articolo abbiamo descritto aggiungere timeframe con QuantConnect. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/QuantConnect