In questo articolo descriviamo come implementare il backtest di una strategia con l’Ichimoku in Python. Il sistema Ichimoku Kinko Hyo è un metodo giapponese per la creazione di grafici e l’analisi tecnica. E’ stato pubblicato nel 1969 da un giornalista in Giappone.
In particolare ci concentriamo nel descrivere come creare gli elementi per calcolare l’indicatore Ichimoku, insieme a un paio di esempi di grafici tramite le librerie Matplotlib e Plotly.
L’indicatore Ichimoku
Il “setup” dell’Ichimoku è un indicatore tecnico usato per valutare il momentum di asset e prevedere possibili aree di supporto e resistenza future. L’indicatore Ichimoku è composto da cinque principali linee.
- La linea Tenkan-Sen, chiamata anche Conversion Line, rappresenta il punto medio delle ultime 9 candele. E’ calcolata sommando il massimo più alto e il minimo più basso degli ultimi nove periodi e poi dividendo il risultato per due.
- La linea Kijun-Sen, chiamata anche Base Line, rappresenta il punto medio delle ultime 26 candele. È calcolata in modo simile alla linea Tenkan-Sen, usiamo le ultime 26 candele invece che le ultime 9. Si somma il massimo più alto e il minimo più basso degli ultimi 26 periodi e poi si divide il risultato per due.
- La linea Chikou Span, chiamata anche Lagging Span, è in ritardo rispetto al prezzo (come suggerisce il nome). Il Lagging Span mostra il movimento attuale dei prezzi proiettato indietro di 26 periodi.
- La linea Senkou Span A, detta anche Leading Span A, rappresenta uno dei due confini della Nuvola ed la media tra la Conversion Line (Tenkan-Sen) e la Base Line (Kijun-Sen). E’ calcolata sommando la linea Tenkan-Sen e la linea Kijun-Sen e dividendo per 2. Questo valore è proiettato in avanti di 26 periodi e rappresenta il confine più veloce della nuvola.
- La linea Senkou Span B, o Leading Span B, rappresenta il secondo confine della nuvola ed è la media delle ultime 52 barre di prezzo. Si calcola sommando il massimo più alto e il minimo più basso degli ultimi 52 periodi e si divide il risultato per due. Questo valore è proiettato in avanti di 26 periodi nel futuro ed è il confine più lento della nuvola.
Ora che conosciamo come calcolare gli elementi dell’indicatore, vediamo come implementarli per testare la strategia con l’Ichimoku in python.
Iniziamo con importare le librerie necessarie.
import pandas as pd
from yfinance import yf
import matplotlib as mpl
from mplfinance.original_flavor import candlestick_ohlc
import matplotlib.dates as dates
import datetime
import matplotlib.pyplot as plt
Scarica i dati di alcuni titoli azionari da Yahoo. In questo esempio usiamo i prezzi di Apple ma potete usare qualsiasi altro titolo.
start = '2017-01-01'
end = '2019-01-27'
d = yf.download("AAPL", start, end)
# converte le date in valori interi da usare per le
# funzioni dei grafici a candele di matplotlib
d['Dates'] = dates.date2num(d.index)
# Tenkan-sen (Conversion Line): (massimo di 9 periodi + minimo di 9 periodi) / 2
nine_period_high = d['High'].rolling(window= 9).max()
nine_period_low = d['Low'].rolling(window= 9).min()
d['tenkan_sen'] = (nine_period_high + nine_period_low) /2
# Kijun-sen (Base Line): (massimo di 26 periodi + minimo di 26 periodi) / 2
period26_high = d['High'].rolling(window=26).max()
period26_low = d['Low'].rolling(window=26).min()
d['kijun_sen'] = (period26_high + period26_low) / 2
# Senkou Span A (Leading Span A): (Conversion Line + Base Line) / 2
d['senkou_span_a'] = ((d['tenkan_sen'] + d['kijun_sen']) / 2).shift(26)
# Senkou Span B (Leading Span B): (massimo di 52 periodi + minimo di 52 periodi low) / 2
period52_high = d['High'].rolling(window=52).max()
period52_low = d['Low'].rolling(window=52).min()
d['senkou_span_b'] = ((period52_high + period52_low) / 2).shift(26)
# Proiezione dei prezzi di chiusura indietro di 26 periodo
d['chikou_span'] = d['Close'].shift(-26)
# Crea un grafico dei risultati per verificare cosa abbiamo calcolato
d.drop(['Dates', 'Volume'], axis=1).plot(figsize=(15,8))
plt.show()
Questo grafico è un pò impegnativo da capire. Non abbiamo ancora creato il grafico a candele. Abbiamo semplicemente tracciato le linee di tutte le serie di dati presenti nel DataFrame, inclusi i prezzi “Open, High, Low, Close”.
Grafico con Matplotlib
Vediamo ora come ripulire il grafico, condensando i 4 punti della serie dei prezzi in candele e visualizzarle nel grafico.
# Riordina i dati in modo che ogni riga contenga i valori di un giorno: 'Date','Open','High','Low','Close'.
# Il 'Date' non può essere un oggetto "datetime" in quanto la funzione non li accetterà. Ecco perché abbiamo
# convertito la nostra colonna "Data" in valori interi utilizzando la funzione "date2num".
quotes = [tuple(x) for x in d[['Dates','Open','High','Low','Close']].values]
# Grafico a candele insieme alle linee Ichimoku
fig, ax = plt.subplots(figsize=(15,8))
d[['tenkan_sen','kijun_sen','senkou_span_a','senkou_span_b','chikou_span']].plot(ax=ax, linewidth=0.5)
candlestick_ohlc(ax, quotes, width=1.0, colorup='g', colordown='r')
plt.show()
Sembra un po’ meglio, ma dobbiamo ancora colorare/ombreggiare correttamente l’area della nuvola Ichimoku nel grafico. Inoltre è difficile visualizzare il dettaglio di alcune aree poiché la scala temporale è piuttosto ampia, causando un “raggruppamento” della serie.
Grafico con Plotly
Il modo migliore per aggirare questo problema è non usare la libreria Matplotlib e sostituirlo con il modulo Plotly. Con Plotly possiamo creare grafici basati su HTML con un certo livello di interattività, permettendoci di selezionare aree o periodi specifiche, effettuare panoramiche in avanti o indietro, ecc. Quindi, se ci sono aree del grafico dove è difficile capire l’andamento dei dati, possiamo semplicemente concentrarci su quell’area ed espanderla per una visione migliore.
Di seguito è riportato uno script di base per visualizzare un semplice grafico a candele con Plotly, usando i dati dei prezzi storici delle azioni Apple come input. Eseguendo il codice, Plotly crea un nuovo documento HTML e lo visualizza aprendo automaticamente una nuova finestra del browser. La funzione update_layout
permette di specificare un nome al nostro grafico.
import plotly.graph_objs as go
from plotly.subplots import make_subplots
trace = go.Candlestick(x=d.index, open=d['Open'], high=d['High'], low=d['Low'], close=d['Close'])
fig = go.Figure()
fig = make_subplots(rows=1, cols=1)
# candlestick
fig.append_trace(trace, row=1, col=1)
fig.update_layout(title="Semplice Grafico a candele")\
fig.show()
Per verificare il funzionamento interrativo della pagina HTML di Plotly è possibile scaricare il seguente file che contiene il risultato prodotto dal precedente codice:
Potete scaricare il file, aprirlo nel browser e vedere qualcosa di simile al grafico precedente. Un grafico a candele con un “cursore” in basso che permette di entrare e uscire da diversi periodi temporali. Questo è un buon punto di partenza. Vogliamo ora aggiungere alcune funzionalità, insieme al resto degli indicatori Ichimoku che abbiamo calcolato in precedenza.
Da notare che il codice seguente ha un aspetto notevolmente diverso dal codice usato per il primo grafico. La libreria Plotly permette di usare e implementare diversi approcci per la creazione dei grafici. Nel codice precedente abbiamo creato un oggetto plotly.graph_objs
e usato il metodo Candlestick
per creare il grafico desiderato.
Dobbiamo ora creare una lista chiamata data
contenere un dizionario con tutte le informazioni rilevanti che dobbiamo fornire. Il dizionario contiene la il primo “grafico” o “la prima serie da tracciare”.
Successivamente creiamo un dizionario vuoto che, insieme al dizionario “grafico”, e passato ad un altro dizionario che rappresenta il grafico “Figura”. Il dizionario vuoto conterrà le informazioni relative al design del layout del grafico. La “Figura” richiede informazioni sia dalla lista zcode>data (elenco di dizionari contenenti informazioni relative ai valori della serie da tracciare), sia dal dizionario layout
contenente le impostazioni per il design e layout.
Dopo aver creato l’oggetto fig
, possiamo iniziare a impostare i valori per entrambe variabili di layout e aggiungere nuovi “grafici” alla lista dei dati, se vogliamo tracciare ulteriori serie di dati.
# Imposta i colori per le candere up e down
INCREASING_COLOR = '#00ff00'
DECREASING_COLOR = '#ff0000'
# Crea la lista che contiene i dizionari con i dati
# della prima serie di dati da visualizzare
data = [dict(type='candlestick',
open=d.Open,
high=d.High,
low=d.Low,
close=d.Close,
x=d.index,
yaxis='y2',
name='AAPL',
increasing=dict(line=dict(color=INCREASING_COLOR)),
decreasing=dict(line=dict(color=DECREASING_COLOR)),
)]
# Crea un dizionario vuoto per contentere le impostazioni e il layout
layout = dict()
# Crea l'oggetto principale "Figure" che contiene i dati da visualizzare e le impostazioni
fig = dict(data=data, layout=layout)
# Assegna vari valori di impoestazioni - colore di sfondo, range di selezione, ecc
fig['layout']['plot_bgcolor'] = 'rgb(250, 250, 250)'
fig['layout']['xaxis'] = dict(rangeselector=dict(visible=True))
fig['layout']['yaxis'] = dict(domain=[0, 0.2], showticklabels=False)
fig['layout']['yaxis2'] = dict(domain=[0.2, 0.8])
fig['layout']['legend'] = dict(orientation='h', y=0.9, x=0.3, yanchor='bottom')
fig['layout']['margin'] = dict(t=40, b=40, r=40, l=40)
# Popola l'oggetto "rangeselector" con le impostazioni necessarie
rangeselector = dict(
visible=True,
x=0, y=0.9,
bgcolor='rgba(150, 200, 250, 0.4)',
font=dict(size=13),
buttons=list([
dict(count=1,
label='reset',
step='all'),
dict(count=1,
label='1yr',
step='year',
stepmode='backward'),
dict(count=3,
label='3 mo',
step='month',
stepmode='backward'),
dict(count=1,
label='1 mo',
step='month',
stepmode='backward'),
dict(step='all')
]))
fig['layout']['xaxis']['rangeselector'] = rangeselector
# Aggiunge gli elementi Ichimoku nel grafico
fig['data'].append(dict(x=d['tenkan_sen'].index, y=d['tenkan_sen'], type='scatter', mode='lines',
line=dict(width=1),
marker=dict(color='#33BDFF'),
yaxis='y2', name='tenkan_sen'))
fig['data'].append(dict(x=d['kijun_sen'].index, y=d['kijun_sen'], type='scatter', mode='lines',
line=dict(width=1),
marker=dict(color='#F1F316'),
yaxis='y2', name='kijun_sen'))
fig['data'].append(dict(x=d['senkou_span_a'].index, y=d['senkou_span_a'], type='scatter', mode='lines',
line=dict(width=1),
marker=dict(color='#228B22'),
yaxis='y2', name='senkou_span_a'))
fig['data'].append(dict(x=d['senkou_span_b'].index, y=d['senkou_span_b'], type='scatter', mode='lines',
line=dict(width=1), fill='tonexty',
marker=dict(color='#e99653'),
yaxis='y2', name='senkou_span_b'))
fig['data'].append(dict(x=d['chikou_span'].index, y=d['chikou_span'], type='scatter', mode='lines',
line=dict(width=1),
marker=dict(color='#D105F5'),
yaxis='y2', name='chikou_span'))
# Imposta la lista dei colori per le candele
colors = []
for i in range(len(d.Close)):
if i != 0:
if d.Close[i] > d.Close[i - 1]:
colors.append(INCREASING_COLOR)
else:
colors.append(DECREASING_COLOR)
else:
colors.append(DECREASING_COLOR)
grafico = go.Figure(fig)
grafico.show()
Vediamo che abbiamo ottenuto un grafico interattivo che mostra le candele, permette di ingrandire e rimpicciolire, concentrarci su singole aree se necessario. L’unica cosa rimasta sta fare è l’ombreggiatura della “nuvola” di Ichimoku. Dovrebbe alternarsi tra verde e rosso, a seconda di quale “Senkou Span” (A o B) è sopra o sotto l’altro.
Odio ammetterlo, ma dopo aver cercato nell’ultimo periodo una soluzione al problema del colore dell’ombreggiatura delle nuvole, al momento non ho trovato una soluzione. Sicuramente esiste un modo per farlo tramite Plotly usando una combinazione di filltonextx
e/o filltonexty
, ecc. ma non sono ancora riuscito ad arrivarci.
Per non ritardare l’intero articolo solo a causa del problema dell’ombreggiatura, lo pubblico comunque e poi vedremo di aggiornarlo.
Il prossimo articolo descrive come formalizzare un insieme di regole sistemiche usando i segnali Ichimoku. Vediamo quindi come codificare la strategia strategia con l’Ichimoku in Python per effettuare il backtest.
Codice completo
In questo articolo abbiamo descritto come implementare il backtest di una strategia con l’Ichimoku 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