La strategia smash day รจ stata ideata da Larry R. Williams, un trader professionista che ha guadagnato 11.300% nell’arco di un anno durante una gara. Sul sito di Oxford Capital Strategies Ltd ho trovato, i dettagli della strategia e una simulazione su 48 future nell’arco di 32 anni, i risultati delle simulazioni sono stimolanti. Le simulazioni che farรฒ io saranno sul solito set di azioni FTSEMIB nel decennio 2010-2020.
Trovo la strategia interessante, non solo perchรฉ ideata da un trader in grado di guadagnare cosรฌ tanto in cosรฌ poco tempo, ma anche perchรฉ รจ una strategia basata su pattern e quindi non trend following. La stragia รจ ben descritta sul sito Oxfordstrat, e mi limito a provare a descriverne la logica. La strategia รจ simmetrica, ossia prevede ingressi long e short, in modo completamente simmetrico (basta sostituire massimi con minimi e segni). Qui di seguito una simulazione con A2A.
Nel caso di entrate long la condizione di ingresso รจ Long Trades: Close[i โ 1] < Low[i โ 2], ossia la barra chiude sotto il minimo della barra precedente, se si verifica questa condizione significa c’รจ stata una accelerazione del movimento verso il basse. Se questo succede possono succedere due cose, che poi sono le due situazioni che si verificano sempre. O il mercato sale o il mercato scende. Se sale il mercato, l’ipotesi sottostante la strategia, รจ che ci sia un’inversione e che lโaccelerazione sia il preludio del cambio di direzione. Per capire se si verifica un cambio di direzione l’approccio usato รจ di inserire un buy stop sul massimo della candela “smash” . Il grafico qui riportato mostra come lo scenario di applicazione. La strategia prevede anche un filtro in ingresso, il Close[i โ 1] > Close[i โ Trend_Index], questo, in modo semplificato, significa che il marcato, rispetto al tempo trend_index, si รจ spostato verso l’alto. Possiamo vedere lo smash day come il momento di rintracciamento, ossia un minimo relativo al periodo in oggetto, incluso tra il tempo i-1 e i-trend_index, all’interno di un ampio movimento crescita.
La strategia smash day scommette sul proseguimento del trend dato da Close[i โ 1] > Close[i โ Trend_Index], es entra quando c’รจ un rintracciamento che si ipotizza stia terminando perchรฉ c’รจ stata un’accelerazione di movimento in discesa dato da Close[i โ 1] < Low[i โ 2]. In questo scenario lo stop subito sotto il Low[i-1] รจ quasi doveroso, e in effeti fa parte delle strategia. Sia Williams che Oxford Capital Strategies Ltd hanno applicato la strategia al mercato dei future, in questo caso lo stop si posiziona un tick sotto il minimo, nel caso delle azioni questa possibilitร non c’รจ, quindi posiziono il minimo -1% sotto il Low[i-1] nel caso di long e +1% sopra high[i-1] nel caso posizione short.
Nelle diverse simulazioni che ho fatto trovo coerenza con i dati di Oxfordstart, ossia che la strategia performa meglio con trend_index=80 e time_index=40. Il risultato non รจ perรฒ quello atteso, anche togliendo le commissioni il risultato รจ deludente. Dopo un po’ di prove mi sono accorto che la condizione di uscita veloce +-1% รจ troppo stretta e la strategia rimane soffocata.
Anche provando diverse combinazioni il risultato, in assenza di commissioni, รจ deludente con uno sharpe <0.2 (da panico). Risultati simili sono stati ottenuti da Wpatte15 su tradingview. I dati non sono paragonabili con quelli di Oxfordstart per le evidenti differenze nella simulazione (10Y vs 32Y, 40 azioni vs 42 future). Qui di seguito il codice usato, come sempre la piattaforma du backtesting che uso รจ backtrader, opportunamente personalizzata.
class SmashDay(mts.MultiTickerStrategy):
'''Trade Setup: Long trades: Close[i โ 1] < Low[i โ 2]
Short Trades: Close[i โ 1] > High[i โ 2].
Filter: Long Trades: Close[i โ 1] > Close[i โ Trend_Index]. Trend_Index
Short Trades: Close[i โ 1] < Close[i โ Trend_Index].
Trade Entry: Long Trades: A buy stop is placed one tick above the High[i โ 1]
Short Trades: A sell stop is placed one tick below the Low[i โ 1]
Time Exit: nth day at the close, n = Time_Index. n=40
Quick Exit: Long Trades: A sell stop is placed one tick below the min(Low[k โ 1], Low[k]). Index: k ~ Entry Bar.
Stop Loss Exit: ATR_Length = 20; ATR_Stop = 6;
'''
params = dict(
trend_index=80, #Trend_Index = [4, 80], Step = 2;
time_index=40, #Time_Index = [1, 40], Step = 1;
atr_lenght=20, #ATR_Length = 20;
atr_stop=6, #ATR_Stop = 6;
)
def __init__(self):
super().__init__()
self.dts = dict()
self.stops = dict()
self.exits = dict()
self.inds = dict()
#Carico i dati sharpe
for i, d in enumerate(self.stocks):
self.inds[d] = dict()
self.inds[d]['atr'] = bt.indicators.ATR(d,period=self.p.atr_lenght)
self.inds[d]['high'] = bt.indicators.Highest(d,period=self.p.trend_index)
self.inds[d]['low'] = bt.indicators.Lowest(d,period=self.p.trend_index)
def next(self):
for i, d in enumerate(self.stocks):
dt, dn = self.datetime.date(), d._name
if dn in self.dts:
dat = self.dts[dn]
else:
dat = 0
dt, dn = self.datetime.date(), d._name
pos = self.getposition(d)
if len(d)<self.p.time_index+1+self.p.trend_index:
continue
# prima gestisco il setup long/short se non sono giร in posizione
if not pos:
#imposto la data operazione
if d.close[0]<d.low[-1]: #setup long
if d.close[0] > d.close[-self.p.trend_index]: #filtro long
mainorder = self.buy(d,exectype=bt.Order.Stop,price=d.high[0],valid=datetime.timedelta(days=1), transmit=False)
if not mainorder == None:
sexit = self.sell(d,price=d.low[0]-self.inds[d]['atr']*2,
size=mainorder.size, exectype=bt.Order.Stop,transmit=False, parent=mainorder, info={"mainorder":""})
stoploss = self.sell(d,price=d.high[0]-self.inds[d]['atr']*self.p.atr_stop,
size=mainorder.size, exectype=bt.Order.Stop,transmit=True, parent=mainorder, info={"mainorder":""})
self.stops[d]=stoploss
self.exits[d]=sexit
self.dts[d._name]=d.datetime[0]
elif d.close[0]>d.high[-1]: #setup short
if d.close[0] < d.close[-self.p.trend_index]: #filtro long
mainorder = self.sell(d,exectype=bt.Order.Stop,price=d.low[0],valid=datetime.timedelta(days=1), transmit=False)
if not mainorder == None:
sexit = self.buy(d,price=d.high[0]+self.inds[d]['atr']*2,
size=mainorder.size, exectype=bt.Order.Stop,transmit=False, parent=mainorder, info={"mainorder":""})
stoploss = self.buy(d,price=d.low[0]+self.inds[d]['atr']*self.p.atr_stop,
size=mainorder.size, exectype=bt.Order.Stop,transmit=True, parent=mainorder)
self.stops[d]=stoploss
self.exits[d]=sexit
self.dts[d._name]=d.datetime[0]
else:
if d.datetime[-self.p.time_index]>dat:
self.close(d)
if d in self.stops:
self.cancel(self.stops[d])
del self.stops[d]
if d in self.exits:
self.cancel(self.exits[d])
del self.exits[d]
Lascia un commento