Dopo aver creato il nostro ambiente di sviluppo, come descritto in questo articolo, è il tempo di scrivere il nostro primo script.

Obiettivo

Questo articolo ha lo scopo di creare una semplice strategia basata sugli indicatori, mantenendo il codice il più semplice possibile. Cercherò di evitare alcuni concetti più avanzati presenti nella documentazione e in Python in generale. Ad esempio le linee come:
if __name__ == '__main__': 

non saranno inclusi poiché ritengo che per imparare è necessario che i principianti dovrebbero cercare di reperire le informazioni su internet ed inoltre non voglio distrarre il lettore dalle funzionalità strettamente legate alla strategia che si vuole implementare (anche se alcuni programmatori professionisti potrebbero deridere la qualità del codice).

Ambito di backtesting: Per motivi di semplicità, il tutorial non include le commissioni, lo spread o altre considerazioni di backtesting più avanzate come benchmarking, l’ottimizzazione e l’analisi dei trade. Ho anche scelto di escludere la stampa / log per mantenere il codice il più semplicepossibile. (Anche se penso che la stampa / log sia importante per il debug quando aumenta la complessità del codice!)

La Strategia

Al momento della stesura di questo articolo siamo in presenza di un lungo mercato rialzista. Quando si negoziano azioni in un tale mercato, è ragionevolmente pensare di andare long. La ragione di ciò è che si trovano sul lato giusto del momentum long alla base della dinamica ascendente.

Con questo in mente, divertiamoci un po ‘a implementare una strategia “solo long” che andrà long quando un semplice indicatore RSI giornaliero è ipervenduto e si mantiene la posizione fino a quando l’RSI non raggiungerà il livello di ipercomprato.

Entry

  • Quando RSI <30

Exit

  • Quando RSI> 70

Gestione del trade e dimensionamento delle posizioni

  • Non si implementa nessuna gestione del trade. Non è previsto nessun ridimensionamento in / out. Solo semplici acquisti e vendite con un’unica posizione aperta alla volta.
  • Per quanto riguarda le dimensioni della posizione, si semplifica le cose comprando / vendendo 100 azioni alla volta senza fare calcoli per vedere se abbiamo abbastanza liquidità per le dimensioni della posizione (se non abbiamo abbastanza liquidità, backtrader è abbastanza intelligente da rifiutare l’ordine)

Settaggio dell’indicatore

  • Periodo = 21
    Consente di utilizzare una finestra mobile più lunga rispetto ai 14 periodo standard. In teoria ciò dovrebbe tradursi nell’avere meno falsi segnali falsi e il prezzo dovrebbe scendere / aumentare di più prima di essere considerato ipercomprato / ipervenduto.
 

Requisiti

Questo script estrae i dati online da Yahoo. Penso che questo semplifichi le cose per un primo script in quanto non sarà scaricare ed utilizzare i propri dati. Tuttavia, per questo motivo, lo script richiede laa versione backtrader 1.9.49.116 o successiva a causa delle recenti modifiche nell’API di Yahoo.
Per verificare la versione di backtrader che stai utilizzando hai alcune opzioni. Per prima cosa puoi controllare il pip semplicemente digitando:

pip3 list

(Nota per gli utenti di Windows: invece di “pip3” potrebbe essere “pip” se è installata solo una versione di python)

 

Quindi basta cercare la voce “backtrader” nell’output del precedente comando. Gli utenti Linux e Mac possono rendere questo processo un po ‘più veloce eseguendo il piping dell’output su grep.

pip3 list | grep backtrader

Ho notato che su una delle mie macchine Linux, pip3 riportava una versione inferiore rispetto a quella effettivamente installata (non ho ancora capito perché). Quindi, se la versione segnalata non sembra corretta, puoi anche controllarla aprendo una shell python, importando backtrader e stampare la versione.

import backtrader as bt
print(bt.__version__)

Se non si utilizza la versione più recente, avviare un terminale (o il prompt dei comandi) e digitare i seguenti comandi:

pip3 install --upgrade backtrader


I risultati

Per vedere i risultati del test in un grafico bidimensionale, si può usare la libreria Python (esterna all’installazione standard) chiamata “Matplotlib”. Questo modulo è la libreria grafica defacto per molti scienziati, analisti e ricercatori che usano Python.

Assicurati di averlo installato aprendo un terminale o un prompt dei comandi e digitando:

pip3 install matplotlib


Il Codice

Lo script è composto da due parti principali. La prima parte si crea una nuova classe dove implementare tutta la logica della strategia. Nella seconda parte si configura l’ambiente di esecuzione dello script (come aggiungere il framework, prevedere una fonte dati per i test, ecc.). Nota importante: in questo esempio si utilizza i dati disponibili con l’API di Quandl. Con questa API sei limitato al numero di chiamate che puoi effettuare al giorno. Per avere accesso illimitato ai loro dati è sufficiente registrarsi gratuitamente nel loro sito e richiedere una API key ed aggiungi la keyword apikey alla chiamata ai dati di quandl in questo modo (www.quandl.com):
​data = bt.feeds.Quandl(
    dataname='F',
    fromdate = datetime(2016,1,1),
    todate = datetime(2017,1,1),
    buffered= True,
    apikey="INSERT YOUR API KEY"
    )


Imports

​import backtrader as bt
from datetime import datetime

Il primo import dovrebbe essere abbastanza ovvia. Stiamo importando il framework backtrader. Inoltre, si importa il modulo datetime dalla libreria standard di Python. Questo è usato per impostare le date di inizio e fine del periodo di backtesting. Backtrader prevede di ricevere oggetti datetime durante la creazione di feed di dati. Per ulteriori informazioni sul modulo datetime, consultare la documentazione disponibile su:

docs.python.org/3/library/datetime.html

La strategia

class firstStrategy(bt.Strategy):

    def __init__(self):
        self.rsi = bt.indicators.RSI_SMA(self.data.close, period=21)

    def next(self):
        if not self.position:
            if self.rsi < 30:
                self.buy(size=100)
        else:
            if self.rsi > 70:
                self.sell(size=100)
​Quando si crea una strategia in backtrader, si eredita molti metodi e attributi dalla classe base `bt.Strategy`. In parole più semplici, si sta fondamentalmente prendendo il template di una strategia che è stata scritta nel framework di backtest e aggiungendo la nostra logica sopra ad essa. Quando nella programmazione si usa l’ereditarietà, possiamo usare tutto il codice che è stato scritto nella strategia di base e sovrascrivere le parti che vogliamo cambiare. Ciò significa che non è necessario preoccuparsi di tutto il codice, dietro le quinte, che consente di interagire con i dati, gestire gli ordini, le notifiche dei broker e così via. E’ Il framework BackTrader che se ne occupa! La nuova classe della strategia può essere breve, pulita e di facile lettura. Tuttavia, se lo desideri, puoi scavare più a fondo e modificare il contenuto del nucleo della classe base. La nostra classe si chiama firstStrategy (piuttosto originale) e contiene il codice per l’inizializzazione della strategia e il metodo “next”. L’inizializzazione è solo una riga, vogliamo solo inizializzare un indicatore RSI dalla libreria di backtrader. Per fare ciò si aggiunge l’indicatore durante l’inizializzazione della strategia (__init__). Una volta impostato, backtrader si occupa di tenere traccia dei dati, calcolare i risultati e aggiungerli al grafico finale. Se non conosci la programmazione, è importante notare che puoi chiamare il tuo indicatore RSI come preferisci, ma devi prefissarlo con “self”. Ciò ti consentirà di accedervi da altri metodi (chiamati anche “funzioni” quando non stiamo parlando di una classe). In questo caso, abbiamo semplificato la lettura del codice e inizializzato l’indicatore come “self.rsi”. Il metodo next (funzione) viene chiamato ad ogni nuova barra o, in altre parole, ogni volta che viene ricevuta una nuova candela. È in questo metodo che si deve scrivere la logica “if this then that“. In questo esempio si controlla se siamo in posizione, dato che come prerequisito si prevede di effettuare un solo trade alla volta. Se non siamo in una posizione, allora si verifica il livello dell’indicatore RSI. Se è inferiore a 30, si acquista 100 azioni. Se è superiore non si fa nulla (Perché non abbiamo scritto alcun codice per ciò che accade quando l’RSI è sopra i 30 e non siamo in una posizione). Il secondo step della logica prevede le azioni da fare quando SIAMO già in una posizione. In questo caso si cerca un’opportunità di vendita. Se l’RSI supera i 70, si vende tutte le 100 azioni. Altrimenti, di nuovo non si fa nulla. Questo si ripete ogni volta che arriva una nuova candela (ogni giorno) fino a quando tutti i dati sono stati controllati.

Il Setup

#Variable for starting cash
startcash = 10000

#Create instance of cerebro
cerebro = bt.Cerebro()

#Add strategy
cerebro.addstrategy(firstStrategy)

#Get Apple data from Yahoo Finance.
data = bt.feeds.Quandl(
    dataname='AAPL',
    fromdate = datetime(2016,1,1),
    todate = datetime(2017,1,1),
    buffered= True
    )

#Add the data to Cerebro
cerebro.adddata(data)

# Set desired cash start
cerebro.broker.setcash(startcash)

Dopo aver scritto la strategia, è necessario implementare il setup e all’esecuzione. Questo in sostanza si riduce a:

  • Chiamare il motore backtrader (cerebro)
  • Ottenere i dati storici e caricarli nel motore.
  • Impostazione della quantità di denaro che dobbiamo negoziare (startcash)
  • Caricare la strategia nel motore
  • Esecuzione del test
  • Monitorare i risultati

Alcune cose da sottolineare:

  • Durante la stampa, si utilizza l’argomento con keyword style = candlestick, se non lo si utilizza si ottiene un grafico a linee del prezzo di chiusura.
  • Durante l’inizializzazione del feed dei dati si richiama il modulo datetime, come sottolineato in precedenza. Stiamo passando un oggetto datetime agli argomenti della keyword fromdate e todate. Infine la keyword buffer indica che backtrader eseguirà il buffer di tutti i dati richiesti prima dell’inizio dell’analisi.

Eseguire lo script

Presumo che tu abbia svolto le lezioni di base su Python, come menzionato nel mio precedente post. Quindi copia il codice, aggiungi le parti basi del linguaggio, avvia lo script e controlla i risultati.

I Risultati

2 operazioni in profitto. Tasso di vincita del 100%. Saremo ricchi!

 

Tornando ad un tono più serio, prendi questi risultati con le pinze. Non abbiamo confrontato i risultati con un benchmark o una semplice strategia di “buy & hold”. Non abbiamo aggiunto commissioni e slippage, non disponiamo di dati di test a lungo termine sufficienti per convalidare la strategia. Un test per un titolo azionario in solo anno non dovrebbe riempirci di fiducia, ma almeno abbiamo creato una base per fare ricerche ulteriori.