Creare codice modulare con Backtrader

Creare Codice Modulare con Backtrader

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:

  1. 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.
  2. Creare un file vuoto nella cartella con il nome __init__.py. Questo segnala a Python che la directory è un modulo.
Backtrader-moduli-extensions
Creare codice modulare con Backtrader

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):

  1. Creare un file indicator.py che contenga tutti gli indicatori.
  2. 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:

Creare codice modulare con Backtrader

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.

Backtrader-ImportedSwingInd

Per ulteriori letture sulla creazione di moduli e l’importazione, possiamo far riferimento alla seguente documentazione:

  1. La documentazione ufficiale:  https://docs.python.org/3/tutorial/modules.html
  2. 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

Scroll to Top