In questo articolo descriviamo come creare codice modulare con backtrader per le strategie di trading algoritmico. Questo articolo non è direttamente collegato a Backtrader, ma è sicuramente utile man mano procediamo nello studio del backtesting di strategie di trading algoritmico. Più sviluppiamo codice, più strumenti finiscono nella nostra cassetta degli attrezzi. Indicatori, strategie, report, ottimizzatori, e così via. Tuttavia, non va bene avere così tanti strumenti se non riusciamo a trovarli quando ne abbiamo bisogno. Peggio ancora è implementare il codice quando lo abbiamo già fatto altre 10 volte!
La nostra cartella del progetto è la nostra cassetta degli attrezzi e i file al suo interno sono i suoi scomparti. Se non organizziamo le cose in modo efficiente diventa difficile trovare quello specifico pezzo di codice che abbiamo sviluppato 6 mesi fa. Quindi, se riusciamo a trovarlo, dobbiamo semplicemente copiarlo e incollarlo in un nuovo script, man mano abbiamo sempre più attrezzi nella nostra cassetta. Il problema con questo approccio non è lo spreco di avere molte versioni dello stesso codice, è quando dobbiamo correggere un bug e quindi dobbiamo applicare la stessa correzione a tutti gli script. Può essere un vero problema.
Un approccio modulare
Un codice modulare permette di organizzare e riutilizzare in un modo molto più ordinato il codice che abbiamo già sviluppato. Inoltre, quando dobbiamo fare una correzione, è sufficiente farla solo una volta. In Python, abbiamo utilizzato i moduli sin dal primo giorno. Soprattutto in questi articoli. Ogni volta che usiamo l’istruzione import
, stiamo usando un modulo. Fortunatamente, la creazione di un modulo in Python è molto semplice e non è limitata ai pacchetti installati tramite pip e quindi archiviati in una parte del file system del computer che raramente modifichiamo.
Creare un modulo
Per creare un modulo si prevede:
- Creare una cartella nella directory di lavoro e assegnarle un nome. Questo sarà il nome del modulo. L’esempio seguente utilizza “extensions” come nome del modulo/cartella.
- Creare un file vuoto nella cartella con il nome
__init__.py
. Questo segnala a Python che la directory è un modulo.
Nota: il nome del modulo non deve contenere un trattino, -
ad esempio my-module
. In tal caso, riceviamo un messaggio SyntaxError
quando proviamo ad importarlo.
__pycache__
Dopo aver importato il modulo, notiamo che è apparta una cartella__pycache__
all’interno della directory. Quando eseguiamo un programma Python, l’interprete deve convertire lo script in qualcosa chiamato bytecode prima che venga eseguito. La pycache memorizza una versione cache del modulo in bytecode. Questo permette di eseguire lo script in modo più veloce in futuro perché è già stato convertito e memorizzato nella cache. Possiamo generalmente ignorare questa cartella. Non dobbiamo preoccuparci se la eliminiamo perchè sarà ricreata nella successiva esecuzione del modulo.
Creare codice modulare con Backtrader
Dopo aver creato un modulo, è tempo di fare qualcosa di utile con esso. Per creare codice modulare con backtrader mettiamo un indicatore all’interno della cartella ‘estentions’ in modo da poter riutilizzare lo stesso indicatore in più script. Per questo esempio consideriamo l’indicatore pivot/swing implementato nel frammento di codice descritto nell’articolo Indicatore di Swing. Quando aggiungiamo questo codice al modulo abbiamo un paio di opzioni (che dipendono dalle preferenze personali):
- Creare un file indicator.py che contenga tutti gli indicatori.
- Creare un sottomodulo degli indicatori che contenga quindi un file python per ciascun indicatore
Per prima cosa prendiamo il codice dell’indicatore di Swing e lo incolliamo in un file chiamato indicators.py:
import backtrader as bt
class SwingInd(bt.Indicator):
'''
Un semplice indicatore di swing che misura le oscillazioni (il valore più basso/più alto)
in un determinato periodo di tempo.
'''
lines = ('swings', 'signal')
params = (('period', 7),)
def __init__(self):
# Imposta l'intervallo dello swing: il numero di barre prima e dopo lo swing
# necessarie per identificare uno swing
self.swing_range = (self.p.period * 2) + 1
self.addminperiod(self.swing_range)
def next(self):
# Calcolo gli highs/lows nel periodo
highs = self.data.high.get(size=self.swing_range)
lows = self.data.low.get(size=self.swing_range)
# Controllo se la barra nel centro del ragne è più grande delle alte
if highs.pop(self.p.period) > max(highs):
self.lines.swings[-self.p.period] = 1 # aggiunge un nuovo swing
self.lines.signal[0] = 1 # crea il segnale
elif lows.pop(self.p.period) < min(lows):
self.lines.swings[-self.p.period] = -1 # aggiunge un nuovo swing
self.lines.signal[0] = -1 # crea il segnale
else:
self.lines.swings[-self.p.period] = 0
self.lines.signal[0] = 0
Da notare che effettuiamo una chiamata di importazione di un altro modulo all’interno del nuovo modulo (import backtrader as bt
) perchè il codice al suo interno richiede il modulo Backtrader. Non importa se abbiamo importato Backtrader nello script che importa l’indicatore. Deve essere importato anche in questo codice. Ora dovremmo avere una directory simile alla seguente:
Importazione dell’indicatore
Infine, dobbiamo creare un semplice script che importa l’indicatore.
import backtrader as bt
from datetime import datetime
from extensions.indicators import SwingInd
class simpleStrategy(bt.Strategy):
def __init__(self):
self.piv = SwingInd(period=7)
# Crea un'istanza di cerebro
cerebro = bt.Cerebro(stdstats=False)
# Aggiuge la strategia
cerebro.addstrategy(simpleStrategy)
# Download dati di Apple da Yahoo Finance.
data = bt.feeds.YahooFinanceData(
dataname='AAPL',
fromdate = datetime(2016,1,1),
todate = datetime(2017,1,1),
buffered= True
)
# Aggiunge i dat a Cerebro
cerebro.adddata(data)
# Esecuzione della strategia
cerebro.run()
# Stampa del grefico dei risultati
cerebro.plot(style='candlestick')
Possiamo notare che la riga from extensions.indicators import SwingInd
permette l’accesso all’indicatore di swing senza dover aggiungere tutto il codice degli indicatori all’interno del nostro script. L’esecuzione dello script restituisce in output la seugente figura. Possiamo notare che l’indicatore di swing è stato aggiunto nella parte inferiore del grafico.
Per ulteriori letture sulla creazione di moduli e l’importazione, possiamo far riferimento alla seguente documentazione:
- La documentazione ufficiale: https://docs.python.org/3/tutorial/modules.html
- Un altro tutorial dettagliato sui moduli: https://www.digitalocean.com/community/tutorials/how-to-write-modules-in-python-3
Codice completo
In questo articolo abbiamo descritto come creare codice modulare con backtrader per le strategie di trading algoritmico. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/BackTrader