strategia con le bande di bollinger in Python

Backtest di una strategia con le bande di bollinger in Python

Sommario

In questo articolo descriviamo come implementare il backtest di una strategia con le bande di bollinger in Python ed eseguire alcune ottimizzazioni e analisi, come già effettuato negli articoli precedenti.

La strategia è abbastanza semplice e può essere scritta con poche righe di codice, motivo per cui usiamo Python. Questo linguaggio di programmazione permette di prototipate e testate rapidamente le strategie per verificare se ci sono edge da sfruttare senza passare giorni a digitare codice.

Il codice della strategia

				
					
import pandas as pd
import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')

# Download data del Dat dal 2015 in un dataframe Pandas
df = yf.download("^GDAXI", start="2015-01-01", end="2020-01-01")

				
			

Ora abbiamo un DataFrame Pandas con i dati giornalieri dell’indice Dax. Possiamo dare una rapida occhiata alla struttura dei dati stampando i primi dati del dataframe.

				
					print(df.head())

				
			
strategia con le bande di bollinger in Python

Calciamo quindi i valori delle bande di Bollinger:

				
					# Imposta il numero di giorni e la deviazione standard da usare per 
# il calcolo delle bande delle bollinger
window = 21
no_of_std = 2

# Calcolo della media mobile e deviazione standard
rolling_mean = df['Adj Close'].rolling(window).mean()
rolling_std = df['Adj Close'].rolling(window).std()

# Calcolo della banda superiore e inferiore di bollinger
df['Rolling Mean'] = rolling_mean
df['Bollinger High'] = rolling_mean + (rolling_std * no_of_std)
df['Bollinger Low'] = rolling_mean - (rolling_std * no_of_std)

				
			

Vediamo il grafico dei prezzi di chiusura con le bande di bollinger

				
					
df[['Adj Close', 'Bollinger High', 'Bollinger Low']].plot()
plt.show()
				
			
strategia con le bande di bollinger in Python

Implementiamo quindi la logica della strategia.

				
					
# Creo una colonna per memorizzare i segnali/posizioni
df['Position'] = None

# Impostazione la posizione a -1 (short( quando il prezzo raggiunge la banda 
# superiore e a +1 (buy) quando si raggiungere la banda inferiore
for row in range(len(df)):

    if (df['Adj Close'].iloc[row] > df['Bollinger High'].iloc[row]) and (
            df['Adj Close'].iloc[row - 1] < df['Bollinger High'].iloc[row - 1]):
        df['Position'].iloc[row] = -1

    if (df['Adj Close'].iloc[row] < df['Bollinger Low'].iloc[row]) and (
            df['Adj Close'].iloc[row - 1] > df['Bollinger Low'].iloc[row - 1]):
        df['Position'].iloc[row] = 1

# Riempimento in avanti delle posizioni per sostitu*ire i valori "None" con le posizioni 
# long/short che rappresentano il mantenimento delle posizioni aparte in precedenza 
df['Position'].fillna(method='ffill', inplace=True)

# Calcolo dei rendimenti giornalieri dei prezzi e moltiplicazione 
# con la posizione per determinare i rendimenti della strategia
df['Market Return'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1))
df['Strategy Return'] = df['Market Return'] * df['Position'].shift(1)

# Grafico dei rendimenti della strategia
df['Strategy Return'].cumsum().plot()
plt.show()
				
			
Backtest-Bollingers-Bands-DAX-Strategia

La strategia non offre  rendimenti interessanti, e sicuramente negativi se includiamo i costi delle commissioni.

Ottimizzazione della strategia

Proviamo ad aumentare la lunghezza del periodo per usare una finestra mobile di 50 giorni per i calcoli delle bande di Bollinger.

A tale scopo definiamo una funzione “Bollinger Band trading Strategy” che possiamo facilmente eseguire più volte modificando i parametri in input di volta in volta.

				
					

def bollinger_strat(df, window, std):
    # Calcolo della media mobile e deviazione standard
    rolling_mean = df['Adj Close'].rolling(window).mean()
    rolling_std = df['Adj Close'].rolling(window).std()

    df['Bollinger High'] = rolling_mean + (rolling_std * std)
    df['Bollinger Low'] = rolling_mean - (rolling_std * std)

    df['Short'] = None
    df['Long'] = None
    df['Position'] = None

    for row in range(len(df)):

        if (df['Adj Close'].iloc[row] > df['Bollinger High'].iloc[row]) and (
                df['Adj Close'].iloc[row - 1] < df['Bollinger High'].iloc[row - 1]):
            df['Position'].iloc[row] = -1

        if (df['Adj Close'].iloc[row] < df['Bollinger Low'].iloc[row]) and (
                df['Adj Close'].iloc[row - 1] > df['Bollinger Low'].iloc[row - 1]):
            df['Position'].iloc[row] = 1

    df['Position'].fillna(method='ffill', inplace=True)

    df['Market Return'] = np.log(df['Adj Close'] / df['Adj Close'].shift(1))
    df['Strategy Return'] = df['Market Return'] * df['Position'].shift(1)

    df['Strategy Return'].cumsum().plot()
				
			

Possiamo facilmente eseguire un nuovo backtest della strategia richiamando la funzione con una riga. Usiamo un periodo di 50 giorni come parametro della funzione.

				
					bollinger_strat(df,50,2)
plt.show()
				
			
Backtest-Bollingers-Bands-DAX-Ottimizzazione

In questo caso abbiamo ottenuto rendimenti migliori del precedente back-test, anche se sicuramente non ancora eccezionali.

Se vogliamo avere una rapida idea se esistono periodi per le bande di bollinger che offrono un rendimento positivo, possiamo semplicemente implementare un paio di vettori che contiene una serie di valori da applicare ai periodi giornalieri e  alle deviazioni standard, e quindi applicare un algoritmo di “forza bruta” per effettuare una serie di backtest che itera sui due vettori.

				
					bollinger_strat(df,50,2)# Imposta i vettori per "periodo di giorni" e "numero di deviazione standard".
# Ad esempio il primo crea un vettore di 20 valori interi equidistanti che vanno da 10 a 100
# Il secondo crea un vettore di 10 numeri in virgola mobile equidistanti da 1 a 3
windows = np.linspace(10,100,20,dtype=int)
stds = np.linspace(1,3,10)

# Ciclo su entrambi i vettore e esecuzione del backtest per ogni combinazione di valori
for window in windows:
    for std in stds:
        bollinger_strat(df,window,std)

plt.show()
				
			
Backtest-Bollingers-Bands-DAX-Rendimenti

Concesso che dal grafico non possiamo individuare esattamente quali combinazioni di deviazioni standard e periodi di riferimento producano i risultati mostrati, vediamo che ci sono solo 3 o 4 curve che possono offrire rendimenti interessanti. Questo suggerisce che non  sia una grande strategia da perseguire ed approfondire, almeno per il Dax. Questo non vuol dire che le bande di Bollinger non siano utili,  ma solamente che usate in questa logica e in questo mercato molto probabilmente non offrono alcun tipo di vero “vantaggio”.

Codice completo

In questo articolo abbiamo descritto come implementare il backtest di una strategia con le bande di bollinger in Python. Per il codice completo riportato in questo articolo, si può consultare il seguente repository di github:
https://github.com/datatrading-info/Backtest_Strategie

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...

Scroll to Top