Sei sulla pagina 1di 61

Daniele Livio Dainesi

Strategie di trading basate sulla Lateralità

Milano, Settembre 2014


"Dedicato a mio padre, che sempre mi spronò di
fronte a tutte le difficoltà della vita."
Strategie di trading basate sulla Lateralità
Milano, Settembre 2014

I mercati finanziari sono delle entità particolari che, sebbene frutto della volontà degli uomini nel
comprare o vendere, sembrano animati da una vita propria. Se analizziamo i grafici delle quotazioni
possiamo notare come certi comportamenti siano ciclici, ovvero spesso a seguito di un determinato
comportamento ne segue sempre un altro, sempre lo stesso.
Quando i prezzi salgono molto è normale aspettarsi una presa di posizione e quindi un riassestamento
verso il basso delle quotazioni. Quando poi i prezzi attraversano un momento di incertezza e i livelli
di prezzo più scambiati sono sensibilmente differenti ecco che si formano dei livelli entro i quali le
quotazioni "rimbalzano".
Un mercato laterale è uno dei tre scenari tipici nei quali ci si ritrova tutti i giorni ad operare sulle
Borse valori e mercati interbancari.
In una visione semplicistica i mercati tendono a riflettere lo stato di salute di un azienda, un comparto
o di un economia: quando lo stato di salute è buono il prezzo si rafforzerà sempre di più e
teoricamente il grafico delle sue quotazioni dovrebbe assomigliare ad una linea inclinata
positivamente. Il limite alla sua ascesa è dettato dalle aspettative e dalla lenta modificazione del
potere di acquisto e quindi dell'inflazione. Se un bene è costantemente apprezzato e l'inflazione è pari
al 5% allora è lecito aspettarsi un'analoga rivalutazione delle sue quotazioni.
Ma siccome la realtà è più complessa della teoria, i prezzi tenderanno ad aumentare e
periodicamente riassestarsi a causa delle prese di beneficio. Aspettative e rumors amplificheranno
l'importanza dei fattori che sono alla base del processo di formazione del prezzo e di conseguenza il
grafico non sarà più una linea ma una sorta di elettrocardiogramma con tendenza a spostare la linea
di base in alto o in basso. Prima e dopo questi spostamenti potremo notare che il prezzo stazionerà
per tempi più o meno lunghi in un intervallo di prezzo che prenderà il nome di "canale laterale".
Il presente testo prende in esame questi "canali laterali" e cerca di analizzarli sono molteplici aspetti,
tutti destinati a dare indicazioni operative per l'attività di trading.
Gli scenari in cui ci troviamo ad operare quotidianamente possono essere ridotti a tre fattispecie:
mercato direzionale, mercato laterale e mercato volatile.
Questo libro vuole affrontare proprio lo scenario centrale, la Lateralità, e cercare di capirne le
caratteristiche, le peculiarità, i parametri di rischio e proporre più metodi per impostare una strategia
di trading efficace.
Al lettore verrà presentata una visione classica del mercato ed una definizione di lateralità. Vedremo
i canali orizzontali ma anche i canali obliqui. L'approccio partirà da una visione classica per poi
passare ad approcci più evoluti ed in grado di dare un grado di affidabilità più elevato.
A corollario della parte teorica si spiega come costruire un trading system che implementi quanto
spiegato nel testo. Al tempo in cui si scrive la piattaforma di trading automatico più diffusa è
MetaTrader4 della russa MetaQuotes, il cui linguaggio di programmazione è MQL, un linguaggio
basato sul diffusissimo ma non troppo semplice C.
Parte prima
La lateralità

I teorici definiscono la lateralità come un intervallo di prezzi entro i quali stazionano per un certo
tempo le quotazioni degli scambi .

Gli estremi di questo intervallo di prezzo saranno rappresentati da una resistenza (livello superiore)
ed un supporto (livello inferiore).
Affinché ci sia reale lateralità occorre che le quotazioni abbiano testato più volte i suddetti livelli.

Figura 1 - Canale laterale delimitato da Supporto e Resistenza

I due livelli di supporto e resistenza sono spesso coincidenti con livelli di prezzo nei quali sono
avvenuti molti scambi e quindi denota un interesse particolare la loro "inviolabilità" (stop loss, take
profit o ragioni esogene al titolo ma strumentali per il dissesto/riassesto di un economia (micro o
[1]
macro che sia) .

Il concetto di lateralità è anche legato al riconoscimento dei massimi e minimi di periodo i quali sono
delle alternative ai supporti e resistenze.
Figura 2 - Canale laterale costruito intorno ai massimi e minimi di periodo

I massimi ed i minimi di periodo evidenziano i livelli di forza del mercato, ovvero sino a che livello
la forza dei compratori è riuscita a spingersi prima di trovare una barriera insormontabile che li ha
fatti desistere.
Caratteristiche della lateralità

Uno dei passi più importanti in ogni strategia di trading consiste nel riconoscimento dello scenario di
mercato. Non è sufficiente ottenere un massimo ed un minimo di periodo per affermare di essere in un
canale laterale.
Le condizioni minime e necessarie per poter affermare di trovarsi in lateralità sono le seguenti:

· Presenza di almeno due massimi, separati da altrettanti minimi, posizionati su livelli simili di
prezzo
· Momentum calanti nelle fasi di inversione, ovvero nell'intorno dei massimi e dei minimi
· La distanza tra il livello massimo ed il livello minimo deve essere superiore ad un multiplo
della volatilità

Il primo punto è stato già spiegato mentre sul secondo occorre fare dare qualche spiegazione in più.
Quando il mercato è prossimo all'inversione le forze degli investitori tendono a riequilibrarsi per poi
invertirsi. Questo momento di "stallo" che precede l'inversione viene catturato sia dagli oscillatori
(RSI, CCI, %r di Williams e Stocastico) sia graficamente dall'inclinazione delle medie esponenziali.
Il valore degli oscillatori tenderà a "girare" mentre si trova in una delle due fasce denominate "di
ipercomprato" e "di ipervenduto".
La media tenderà a smorzare la sua inclinazione passando per una fase orizzontale che precede
l'inversione.

Figura 3 - Le medie e gli oscillatori evidenziano le inversioni del mercato all'interno di un canale laterale

Uno dei difetti degli indicatori consiste nel loro ritardo cronico nella fornitura di un segnale
operativo. In pratica il segnale da loro generato, secondo la dottrina comune, appare in ritardo e
questo produce entrate destinate a produrre profitti teorici troppo contenuti.
La descrizione che gli indicatori danno del mercato è via via più precisa come si allunga l'intervallo
di valori analizzato dall'indicatore. Tuttavia, proprio per colpa della "lunghezza" dell'indicatore il
segnale operativo avviene tardi, a volte addirittura in corrispondenza della successiva inversione
opposta al segnale generato!
Per ovviare a questo inconveniente si percorre la strada dell'osservazione del calo di momentum,
ovvero si genera un segnale quando si assiste ad un calo della progressione
nell'incremento/decremento di valore dell'oscillatore.

Naturalmente a fronte di una simile strategia emergono subito dei limiti con i quali occorre trovare
una soluzione: come si fa a sapere che il limite esterno raggiunto sia quello più estremo? In fasi di
trend la chiusura di un operazione su eccesso opposto potrebbe verificarsi troppo tardi e generare
perdite anche ingenti.
Proprio per poter leggere meglio i grafici è bene servirsi di ulteriori indicatori: le Bande di
Bollinger sono un ottimo aiuto. Questo indicatore disegna delle bande sopra e sotto la media. La
distanza tra la media e ogni banda è calcolata con una misura di volatilità, ovvero con la deviazione
standard.

Secondo il suo teorico, John Bollinger che le teorizzò nei primi anni '80, applicando, sopra e sotto la
media dei prezzi, una misura pari al doppio della sua deviazione standard si ottengono due bande al
cui interno ricadono oltre l'85% delle quotazioni, come dire che le bande riescono a descrivere
abbastanza bene una predizione di esistenza a breve termine e che ogni prezzo che ricade al di fuori
delle bande è statisticamente destinato a rientrarvi.
Sulla base di queste considerazioni è possibile rielaborare la tecnica operativa precedente abilitando
le operazioni di compravendita solo quando i prezzi ricadono al di fuori delle bande di Bollinger.

Figura 4 - Rispetto alla prima tecnica, il vincolo delle bande permette di migliorare il timing operativo

Nonostante i miglioramenti qualitativi dei segnali di ingresso dovuti all'introduzione delle bande di
Bollinger resta evidente come alcune operazioni sono negative in quanto non si è saputo interpretare
l'inizio di un trend (si veda l'operazione del 2 dicembre 2012 in figura).
Introduciamo allora un indicatore di volatilità più specifico, denominato Average True Range, ideato
da J. Welles Wilder Jr. nel 1978.
L’ATR (Average True Range) misura la media della distanza massima tra gli estremi della barra
precedente e quella successiva.

Dove TR identifica il True Range, ovvero il massimo della distanza tra il massimo degli estremi
delle ultime due barre.
I trend sono solitamente accompagnati da una notevole momentum che si traduce in una volatilità
sempre più intensa ed è quindi doveroso aspettare una sua diminuzione prima di aprire una posizione
in contrapposizione al movimento finora compiuto. Anche se i prezzi avranno superato la banda
superiore di Bollinger dovremo aspettare una calo, anche momentaneo, dell'Average True Range
prima di aprire una posizione ribassista. In figura 4 si può notare come questo accorgimento permetta
di risolvere le anomalie delle tecniche precedenti.

Figura 5 - Avendo l'accortezza di abilitare l'operatività solo in caso di ATR stabile o decrescente, la predizione migliora sensibilmente
Parte seconda

La volatilità direzionale: ATRD

Volatilità buona e volatilità cattiva: una valutazione qualitativa


Abbiamo visto come la volatilità sia una misura della distanza dei prezzi dalla loro media. La misura
è un valore assoluto e questo non ci permette di capire, quando i valori aumentano, se siamo di fronte
alla nascita di un trend o all'inizio di un periodo molto instabile con prezzi che velocemente passano
da sopra a sotto la media con eccezionale velocità. E'questo il caso delle crisi economiche dove gli
investitori non sanno cosa fare e il panico prende il sopravvento sulle strategie. La volatilità è quindi
inadatta a definire qualitativamente lo scenario che ci si presenta e possiamo solo definire come
volatilità "buona" quella che si manifesta durante i trend (anche molto brevi) da quella "cattiva" che
si presenta durante le fasi concitate di un mercato turbato.
Generalmente le fasi di volatilità "buona" sono accompagnate da volumi degli scambi superiori alla
media, ma questa non è un assioma e durante le ultime crisi del quinquennio 2007 - 2012 lo si è
potuto constatare su molti mercati ove il panico ha smosso enormi quantità di scambi che non hanno
originato trend.
Sicuramente si può però affermare che la presenza di volumi molto bassi causa volatilità "cattiva" in
quanto gli scambi avvengono su posizioni (domanda e offerta) anche molto distanti generando grafici
molto frammentati e ondulatori. Queste fasi di mercato sono anche note come fasi "rarefatte" o
"sottili".

Figura 6 - I bassi volumi di scambio sul cambio EURDKK generano frequenti gap e sbalzi
Figura 7 - Osservando gli indicatori utilizzati in precedenza si può notare come appaia confusa l'operatività

ATRD, la direzionalità dell'ATR


Alla luce dei limiti informativi e qualitativi dell'Average True Range chi vi scrive ha pensato, nel
2008, di scomporre la volatilità misurata dall'ATR in volatilità positiva e volatilità negativa,
giungendo alla formula dell'Average True Range Directional (ATRD).
La volatilità positiva è data dalla media della somma del corpo delle candele positive con
[2]
l'eventuale distanza positiva tra il minimo delle candele adiacenti, e le ombre delle candele
negative.
La volatilità negativa è data dalla media della somma del corpo delle candele negative con
l'eventuale distanza negativa tra il massimo delle candele adiacenti, e le ombre delle candele
positive.
Nel caso di candele la cui chiusura coincida con l'apertura (Doji) il valore delle due componenti si
equivale ed è pari alla somma delle ombre.

L'ATRD, a differenza di altri indicatori di volatilità, nasce per evidenziare la direzione prevalente
del movimento in atto. Contrariamente ad altri indicatori qualitativi non è necessario definire livelli
soglia (si veda l'Average Directional Index o ADX) ma semplicemente osservare i valori delle due
componenti direzionali per poterne trarre informazioni operative.
Ricordando che l'ATRD è pur sempre un indicatore con una sua "lunghezza" e che quindi incapsula
geneticamente un suo ritardo informativo, occorre generare segnali operativi non all'incrocio delle
due componenti direzionali bensì al loro "punto di flesso", ovvero nel momento in cui la componente
specifica cambia inclinazione passando da crescente a piatta/decrescente o viceversa.

Figura 8 - A differenza dell'ATR, l'ATRD riesce a fornire indicazioni qualitative della volatilità in atto
Se riassumiamo la tecnica operativa sin qui elaborata possiamo enunciare quanto segue:
· Si entra in contrapposizione alle posizioni di eccesso rispetto alle bande di Bollinger
· Il segnale è valido solo se la volatilità è stabile o in diminuzione
· Utilizzando l'ATRD il segnale short è valido solo se la volatilità direzionale positiva è
stabile o in diminuzione, il segnale long è valido solo se la volatilità direzionale negativa è
stabile o in diminuzione.

Figura 9 - Con riferimento alle tecniche precedenti l'utilizzo come discriminante della sola componente di volatilità contraria la qualità dell'operatività migliora

Come per ogni scoperta, la creazione dell'ATRD nasce con il compito di risolvere i problemi
lasciati irrisolti circa l'interpretazione qualitativa della volatilità. Come abbiamo visto l'uso
dell'ATRD consente di ottenere maggiori segnali operativi e migliorarne la loro qualità e questo era
l'obiettivo che mi ero prefisso quando decisi di approfondire e migliorare le tecniche operative sui
mercati volatili tipici del 2008.
In appendice è possibile trovare il codice MQL per implementare l'indicatore ATRD.
Strategie operative in caso di volatilità "cattiva"

Quando i mercati sono particolarmente turbati è inutile adottare le tecniche classiche per cercare di
impostare una strategia di trading: risulterebbe fallimentare. Gli indicatori richiedono tempo e una
certa progressività dei movimenti di mercato per dare indicazioni attendibili e noi abbiamo definito i
mercati turbati come sequenze di rapidi ed estesi movimenti alterni intorno alla media, questo
significa che nessun indicatore tradizionale potrà essere d'aiuto. Sarebbe invece utile un indicatore di
[3]
frequenza ciclica come determinante tra le fasi di volatilità buona e quella cattiva: un'alta frequenza
farebbe risaltare una volatilità cattiva.
I mercati estremamente volatili ed instabili richiedono un'attenzione particolare per via di alcune
implicazioni non di poco conto:
· Il rischio per operazione è elevatissimo
· Lo spread operativo è generalmente molto elevato
· Lo slippage delle esecuzioni è solitamente ampio
· Le prezzi di apertura e chiusura (setup e stops) degli ordini condizionati sono spesso distanti
da quelli impostati.
Con queste premesse la gestione del rischio diviene elemento essenziale nelle strategie da adottare.
Se in scenari classici si era soliti aprire posizioni intere (es. 5 lotti), negli scenari instabili occorre
ridurre notevolmente per poter contenere perdite a più alta probabilità (es. 0,5 lotti). Per la stessa
ragione i profitti che si possono generare sono più ampi di quelli ipotizzabili in scenari più
tranquilli.
Come riconoscere i mercati instabili

In un mercato instabile generalmente si verificano una o più delle condizioni seguenti:


· Volumi più bassi della media
· Presenza di Spike, Gap, Lap e Isole
· Sequenza di più Doji consecutivi
· Presenza di barre Inside e Outside
· Alta frequenza ciclica intorno alla media dei prezzi

Analizziamo ora ogni condizione.


I volumi bassi riflettono condizioni di mercato in cui le quotazioni si muovono per opera di pochi
operatori che riescono a muovere di molto i livelli di prezzo degli scambi. Nel gergo dei mercati
regolamentati si è soliti definire questa condizione come fase di mercato "sottile" ove i book sono
pieni di "buchi", ovvero molti livelli delle quotazioni adiacenti sono vuoti creando così ampi spread
tra la miglior offerta con la miglior domanda (distanza tra Ask e Bid).

In condizioni di bassi volumi è molto probabile che un grosso ordine "aggredisca" il mercato,
ovvero non viene posizionato sul book ma venga mandato a mercato per l'esecuzione "al meglio".
Questo significa che in scenari rarefatti (poche proposte di negoziazione sui livelli contigui di
prezzo) è facile assistere alla scomparsa di molteplici livelli ad opera di un unico grande ordine (in
gergo si è soliti parlare di "spazzolamento" del book). Ora, siccome l'esecuzione dell'ordine ha
provocato un vuoto (i livelli eseguiti) senza che vi sia stato alcun spostamento delle proposte di
negoziazione tra Bid e Ask, è facile immaginare che in assenza di movimento generalizzato al ribasso
o al rialzo, i vuoti vengano riempiti da piccoli volumi e che lo scambio successivo ricucia il divario
tra domanda e offerta. Graficamente vedremo una barra la cui apertura è vicina alla chiusura ma il
minimo o il massimo è molto distante da loro e l'estensione di un ombra sarà decisamente grande
rispetto alla media delle ombre precedenti. Questa figura viene denominata Spike.

Figura 10 - Lo Spike

I Gap sono invece dei salti di prezzo dovuti ad improvvise accelerazioni, in un verso o nell'altro, del
prezzo. Le motivazioni solitamente risiedono in notizie macroeconomiche in grado di turbare il
mercato e procurare allarmismo. In questo caso i volumi tendono ad essere elevati poiché le
aspettative degli investitori subiscono dei forti condizionamenti.

Figura 11 - I Gap

I Lap sono invece figure di accelerazione continuata nel tempo, dove il movimento non dura una sola
barra ma prosegue sulla successiva/e e lo si può notare dal fatto che le chiusure coincidono con i
minimi o i massimi di barra e lo sviluppo della barra successiva ha direzione in coerenza con la
precedente.
Si chiamano invece "Isole" quei pattern formati da parecchie barre che iniziano con un gap e si
concludono con un gap in direzione contraria che ritorna sui livelli di prezzo precedenti al primo gap.

Figura 12 - Sequenza di Gap e Isole

Un mercato "fermo", indeciso, è caratterizzato da scambi intorno al medesimo prezzo. Questo si


traduce graficamente in sequenze di barre la cui apertura e chiusura coincidono. L'estensione delle
ombre può variare a seconda di quanto sia sottile il mercato. La pericolosità è dovuta al fatto che lo
scenario rappresenta un momento di grande indecisione con oscillazioni potenzialmente deleterie
(l'estensione delle ombre).
Figura 13 - Scenario "Sottile"

La figura delle barre "Inside" (barra successiva contenuta nella precedente) e "Outside" (bassa
successiva che supera da ambo i versi la precedente) è anch'essa sinonimo di indecisione ma, a
differenza delle Doji, annuncia una più elevata capacità di breakout futura e quindi la possibilità di
escursioni molto estese.
Operatività nei mercati turbolenti

Negli scenari instabili e volatili sono possibili alcune tecniche di trading che prendono spunto dalla
prevedibilità di alcune reazioni a dei movimenti violenti. Di seguito si prenderanno in
considerazione i principali segni distintivi dei mercati instabili e si daranno delle indicazioni
operative sulle strategie da adottare.

Operare con gli Spike


Gli spike tendono a riassorbirsi ma d'altronde sappiamo che il riconoscimento dello spike avviene
solo al suo completamento e se dovessimo aspettare la sua chiusura per averne conferma non avremo
più la possibilità di attuare alcuna strategia speculativa. Quindi, l'unica strategia possibile è quella di
andare a mercato, in contrapposizione al movimento non appena il momentum rallenta o in prossimità
dei massimi/minimi di lungo periodo, con obiettivo la ricucitura parziale dell'escursione dal prezzo
di apertura di barra.

In sintesi, in presenza di mercato volatile e instabile, non appena i prezzi iniziano a crescere/calare
rapidamente e a formare una candela molto estesa in rapporto all'ampiezza media, si apre una
posizione short/long non appena la salita/discesa rallenta (calo di momentum). L'obiettivo di profitto
deve essere posto ad un terzo della barra ed eventualmente suddividere l'uscita per parti: una metà o
più al recupero del terzo di barra e la rimanenza sottoposta a trailing stop.

Figura 14 - Operare con gli Spike

Nell'esempio in figura si vede la Spike e il successivo riassorbimento. Un eventuale entrata in


prossimità del minimo avrebbe permesso di raggiungere un profitto superiore al terzo di estensione
di barra. Si noti come nell'immagine a sinistra ci siano state in precedenza due barre estese che non si
sono concluse con la formazione di una spike. Questa osservazione vuole mettere in allerta il lettore
affinché capisca che la speculazione sulle spike è un attività ad alto rischio. L'uscita dalla posizione
deve essere posta in prossimità del minimo, tenendo peraltro conto della volatilità dei prezzi causata
dal momentum (ovvero un valore multiplo dello spread).
Come riconoscere di essere al culmine della Spike?
Un metodo efficace per capire quando un prezzo è prossimo a ritracciare è quello verificare la sua
posizione rispetto alle bande di Bollinger "espanse" al doppio del normale, ovvero applicando una
deviazione pari a 4. Quando il prezzo si posiziona fuori banda si aspetta un rallentamento del suo
momentun all'interno della barra e posizionare l'ordine speculativo. Un metodo per misurare il
momentum "intrabarra" è costituito dall'analisi delle barre sui timeframe inferiori.

Operare con i Gap


In presenza di Gap l'operatività consiste nell'aprire posizioni contrarie non appena il momentum
esplosivo rallenta (si riconosca il punto di flesso della volatilità direzionale ATRD) e avendo come
obiettivo la ricucitura del Gap. La chiusura in perdita deve avvenire alla ripresa del momentum
contrario alla posizione stessa.

Figura 15 - Analizzando il gap della figura 10 in un TF inferiore si può notare il punto di ingresso (freccia) e il punto di uscita coincidente con la ricopertura del gap down

L'operatività con le "Isole" è da considerare un "incidente di percorso" in quanto vale il discorso


operativo fatto per i gap, ovvero l'ingresso in contrapposizione ed in presenza di calo di momentum,
ma poi la ricucitura avviene tardivamente ed in modo violento.
Nella pratica si sarà aperta una posizione e successivamente i prezzi avranno ripreso in direzione del
gap smentendo l'operatività messa in atto. Se l'esposizione utilizzata sarà stata ridotta, come
consigliato, inizierà un periodo più o meno lungo in attesa della ricucitura che potrà avvenire in
modo graduale o violento (gap di formazione del pattern a isola).
Operatività in fase sottile

Qualora le contrattazioni siano particolarmente rarefatte e la rappresentazione grafica sia costituita


da una sequenza di barre i cui prezzi di apertura e chiusura coincidono, si raccomanda l'astensione
dall'operatività in quanto la direzione futura dei prezzi è imprevedibile, lo spread è generalmente
molto elevato e una volta aperta la posizione occorrerà aspettare molto tempo prima di poter
chiudere in seppur minimo profitto.
Si osservi la figura 12 e si immagini uno spread tra Bid e Ask di 10 pips (più che probabile con
questa coppia esotica) e di essere entrati long il 4 luglio alle 14. Significa avere un prezzo di
apertura di 7,4573 (si consideri che i grafici rappresentano i soli valori del Bid) e dover aspettare
che i prezzi salgano ad almeno 7,4574 prima di aver guadagnato un solo pip. Come si può notare, nel
grafico questa quotazione non viene raggiunta.

Operatività con barre Inside e Outside


In presenza di barre Inside (barre contenute nell'estensione di una barra precedente) l'operatività
suggerita è quella di aprire in direzione del breakout della barra di riferimento. Affinché il pattern
possa essere valido occorre che l'estensione della barra contenitore (la barra che contiene le
successive) sia di dimensioni superiori alla media e quindi superiore al valore espresso
dall'indicatore ATR.

Figura 16 - Entrata su barre Inside

Analogamente, quando siamo in presenza di una barra Outside, ovvero una barra che prima supera il
Minimo/Massimo della precedente e successivamente supera il Massimo/Minimo della precedente,
in corrispondenza dell'ultimo breakout si apre una posizione in direzione. Anche in questo caso
valgono le considerazioni riguardo le dimensioni superiori alla media della barra Outside.
Figura 17 - Entrata su Outside al breakout della precedente
Calcolo del rischio e gestione di portafoglio

In questo capitolo ci concentreremo sull'analisi di rischiosità di ogni singola posizione in modo da


stabilizzare quanto più è possibile l'esposizione, in uno scenario di volatilità dei mercati. Vedremo
come armonizzare le scelte operative all'interno di un portafoglio soggetto ad uno specifico profilo di
rischio e valuteremo, sia da parte del singolo investitore che dalla parte di un gestore, la bontà delle
scelte adottate.

Come calcolare gli Stop ed i rischi per operazione


Ogni segnale operativo deve la sua esistenza alla possibilità di generare profitto. Un operazione è
teoricamente vantaggiosa se le possibilità di generare profitto sono superiori a quelle di procurare
una perdita. Per tale motivo è necessario, a priori, conoscere gli obiettivi di prezzo sia per un
eventuale Take Profit che di Stop Loss, ovvero quando viene ufficialmente invalidato il segnale di
entrata e non ha più senso mantenere un operazione in sofferenza.
Molti traders alle prime armi suppongono che il rapporto tra Take Profit e StopLoss debba essere a
favore del primo e così facendo accumulano una quantità considerevole di perdite consecutive che
molto spesso li spingono a rimuovere del tutto lo Stop Loss generando danni ancor più gravi. Questi
aspiranti trader hanno probabilmente travisato il senso dell'affermazione che dice che in un
operazione occorre che il profitto potenziale sia superiore alla perdita potenziale. Molti pensano che
questa affermazione indichi una distanza da porre intorno al prezzo di apertura per delimitare profitto
e perdita. In realtà l'affermazione vuole comunicare all'investitore che ogni operazione deve avere
più probabilità di successo di quante ne ha l'insuccesso.
Non esistono solo operazioni che si gestiscono con uscite intere tramite Stop Loss e take Profit ma le
tecniche di money management permettono di porre degli obiettivi intermedi in grado di
salvaguardare parte dei profitti maturati. E'questo il caso delle tecniche di trailing, con o senza
chiusura parziale.
Grazie al trailing stop è possibile attivare la modifica dello Stop Loss man mano che le quotazioni si
discostano positivamente dal prezzo di apertura, variando di fatto l'esposizione originale.

Una tecnica abbastanza diffusa consiste nello spostare lo Stop Loss al prezzo di entrata non appena i
prezzi si discostano, di una misura maggiore della volatilità, dal setup di ingresso. In questo modo il
rischio operazione viene azzerato e si garantisce il margine per l'apertura di altre operazioni.
L'eventuale chiusura parziale della posizione diminuisce il profitto futuro sperato ma genera profitti
certi.
In scenari volatili la dimensione della volatilità a breve risulta determinante per il calcolo degli
Stops (Stop Loss e Take Profit). Considerando il timing estremamente ridotto legato alla validità dei
pattern in scenari volatili, generalmente da una a tre barre, si utilizza un multiplo della volatilità a
breve quale determinante per capire se validare il segnale e determinarne gli Stops: se l'obiettivo di
perdita è talmente prossimo al punto di ingresso da essere contenuto all'interno della volatilità, allora
il segnale di ingresso dovrebbe essere ignorato, lo stesso dicasi se l'obiettivo di profitto cade al di
fuori della volatilità.
Nel validare il segnale operativo di uno Spike, ad esempio, dovremmo verificare che l'obiettivo pari
ad un terzo della barra sia contenuto nella volatilità, in caso contrario rischieremmo di fallire.
Nel valutare la ricucitura di un Gap andrebbe verificato che questa distanza sia superiore alla
volatilità, così come l'estensione della barra Outside rispetto al punto di breakout.

Per calcolare genericamente lo stop loss di una posizione occorre tenere presente due fattori: il
timing supposto per la conclusione della strategia e un multiplo della volatilità. Il fattore di
moltiplica è pari al timing atteso: chiusura attesa in tre barre equivale ad uno stop loss calcolato
moltiplicando per un fattore 3 la volatilità.

Es.
ATR(14) = 50 pips
Timing atteso = 3 barre
Stop Loss pari a 50 x 3 = 150 pips

Una volta calcolata l'entità dello Stop Loss occorre calcolare la dimensione dell'ordine in modo che
l'eventuale perdita rimanga circoscritta ad una percentuale preordinata del proprio capitale di
rischio.
Supponiamo di non voler perdere più di 200$ ed aver calcolato tramite il multiplo della volatilità
uno stop loss di 150 pips. Per prima cosa dobbiamo correggere lo stop loss per tener conto di un
eventuale slippage (ad esempio 15 pips in scenari volatili e turbolenti) e quindi impostare
l'equazione che ci dia la dimensione corretta.
In seguito dobbiamo recuperare il valore, in moneta di conto del singolo Pip per lotto tradato.
Infine calcoliamo il volume corretto impostando l'equazione seguente:
Volume x PipValue x StopLoss = Perdita Max
Volendo calcolare il volume si reimposta l'equazione come segue:
Volume = Perdita Max / (PipValue x StopLoss)
Nell'esempio precedente avremo i seguenti dati di partenza:
PipValue = 10$
PerditaMax = 200$
StopLoss = 150 pips + 10 di Slippage = 160
Volume = 200/(10 x 160) => 200/1600 => 0,12 lotti

Il valore del Pip (esattamente come il valore del Tick per gli strumenti finanziari tradizionali,
derivati e CFD) viene fornito dall'emittente, dalla Borsa valori ove avvengono gli scambi o
dall'intermediario finanziario (broker, banca).
Il procedimento appena spiegato porta il nome di "Lotto equivalente", ovvero la dimensione che, in
base allo stop impostato, equivale ad un valore di perdita predefinita. La funzione del lotto
equivalente è stata da me definita nel corso di anni di sviluppo di trading system.

Gestione di portafoglio
Una corretta gestione patrimoniale prevede la diversificazione degli investimenti e la distribuzione
del rischio (regola della doppia D). Questi due accorgimenti permettono di stabilizzare le variazioni
più grandi che possono capitare all'interno di ogni singola strategia di trading. Come dire che in
un'orchestra il suono prodotto da tutti i musici permette di contenere le stonature di qualche elemento.
In un portafoglio ben strutturato la stessa strategia può essere utilizzata su più strumenti finanziari
attenendosi alla regola di non applicarla su strumenti correlati. Se infatti la stessa strategia fosse
applicata su strumenti correlati le operazioni in perdita si replicherebbero al posto di compensarsi.
E'invece consigliato distribuire la stessa strategia su più strumenti non correlati e applicare più
strategie in grado ognuna di approcciare i diversi scenari di mercato (trend, lateralità e volatilità).
Una corretta gestione di portafoglio, visti i limiti operativi imposti dai broker (lotto minimo e
margine richiesto) richiede un capitale di rischio di dimensioni adeguate.
Per capire quanto capitale sia necessario facciamo alcune ipotesi, abbastanza realistiche al momento
in cui si scrive, dei vincoli operativi e strategie da operare:

Caratteristiche comuni
3 strategie (trend, lateralità e volatilità)
3 Strumenti finanziari non correlati
StopLoss medio pari a 70 pips

Si consiglia di non impegnare mai più della metà del margine disponibile e comunque avere un
capitale pari al meno al doppio della presunta perdita, di modo che sia possibile replicare le
medesime operazioni per sanare eventuali perdite .

Ipotesi A
Lotto minimo: 0,10
Leva 100:1
Valore StopLoss: 70$
Lotti minimi necessari: 3 x 3 x 0,10 = 0,90
Margine richiesto: 900$
StopLoss globale: 630$
Capitale minimo richiesto: 1.800$
Ipotesi B
Lotto minimo: 0,01
Leva 500:1
Valore StopLoss: 7$
Lotti minimi necessari: 3 x 3 x 0,01 = 0,09
Margine richiesto: 18$
StopLoss globale: 63$
Capitale minimo richiesto: 36$ teorici ma 90$ reali in quanto occorre tenere presente i livelli di
Sellout dei broker.

Come si è visto nelle ipotesi sopra citate, il capitale necessario è molto ridotto se le strategie di
trading non prevedono la suddivisione per parti delle uscite. Qualora invece la prevedano è
necessario tener conto della dimensione minima dell'intero per poter ottenere una chiusura parziale
coerente con la proporzione desiderata.
Se ad esempio volessimo chiudere il 20% della posizione all'attivazione del BEP (Break Even
Point), un successivo 30% all'attivazione del trailing stop e la rimanenza (50%) sul ritracciamento
del trailing, dovremmo trovare la dimensione dell'ordine tale per cui sia possibile suddividerlo in tre
parti secondo la proporzione desiderata (20-30-50).
Appare evidente che se la dimensione minima è 0,01 lotti (un microlotto) la dimensione dell'intero
dovrà essere di un minilotto (0,10) in quanto solo così sarà possibile la suddivisione corretta.
I broker hanno infatti due vincoli nella scelta della posizione: il volume minimo e l'incremento di
volume minimo. Possono coincidere ma più frequentemente sono differenti, preservando
all'incremento la misura più piccola (es. Lotto minimo a 0,10 ed incremento minimo a 0,01).
Per trovare la dimensione dell'ordine base occorre rispettare i seguenti vincoli:
· Qualsiasi parte dell'ordine base deve essere un insieme (anche eccedente) di lotti minimi.
(VolumeBase x %EnnesimaParte)/MinLot >=1

· Il resto dell'insieme eccedente dalla divisione della parte per i lotti minimi deve essere un
multiplo intero di incrementi minimi.
Mod((VolumeBase x %EnnesimaParte)/MinStep)=0

Mantenendo le proporzioni viste precedentemente, ipotizzando una dimensione minima ed un


incremento minimo di 0,01, possiamo dire che un lotto è un volume base corretto ma 1,04 non lo è.
Infatti il 20% di 1,04 equivarrebbe a 0.208, ovvero una dimensione non disponibile.
Anche 1.05 non sarebbe corretta come dimensione base poiché sebbene il 20% equivarrebbe a 0,21
(dimensione disponibile) il 30% sarebbe 0,315 che ovviamente non è permessa.
Fatta questa doverosa precisazione occorre adesso ricalcolare il capitale necessario per le due
ipotesi operative precedenti, alla luce dei vincoli imposti dai broker sulla dimensione degli ordini.
Ipotesi A
Lotto minimo: 0,10
Leva 100:1
Lotto Base: 1,00
Valore StopLoss: 700$
Lotti necessari: 3 x 3 x 1,00 = 9,00
Margine richiesto: 9000$
StopLoss globale: 6300$
Capitale minimo richiesto: 18.000$
Ipotesi B
Lotto minimo: 0,01
Lotto Base: 0,10
Leva 500:1
Valore StopLoss: 70$
Lotti minimi necessari: 3 x 3 x 0,10 = 0,90
Margine richiesto: 180$
StopLoss globale: 630$
Capitale minimo richiesto: 1.260$
Come si può notare il capitale minimo necessario, alla luce dei vincoli imposti per la chiusura per
parti, è cresciuto considerevolmente. Bisogna peraltro sottolineare che questo aumento si presenta
solo in presenza di capitali di partenza molto piccoli, ovvero quando si tende ad utilizzare i lotti
minimi ammessi come lotti base. Quest'ultimo aspetto è quindi un vincolo importante solo nei casi di
sottocapitalizzazione.
Parte terza

Implementazione pratica di un trading system per scenari


volatili

[4]
In questa terza parte si accompagnerà il lettore nella creazione di un trading system che applicherà
le strategie descritte nella prima e seconda parte.
Per comodità verrà utilizzata la piattaforma MetaTrader 4, giunta alla versione 6.00 build 670, ed il
suo linguaggio MQL4 (C-Like).
Creazione passo-passo

Per la creazione di un nuovo trading system, in MetaTrader denominato Expert Advisor, occorre
richiamare l'editor di codice, denominato MetaEditor, tramite il comendo F4 e quindi premere il
pulsante Nuovo.

Figura 18 - Pulsante "Nuovo" sulla barra degli strumenti

Apparirà una finestra di dialogo che ci permette di scegliere la natura del nuovo progetto.

Figura 19 - Finestra del Wizard per la creazione di un nuovo progetto

Selezionaniamo Expert Advisor e premiamo il pulsante Avanti. Quindi scriviamo il nome del nostro
trading system: sdVolatilityBase e premiamo Avanti.
Apparirà ora l'elenco delle funzioni evento opzionali da inserire all'interno del codice (noti come
handler).

Nel nostro caso vanno più che bene gli eventi standard (sia per la prima che la seconda videata) e
quindi premiamo, alla fine, il tasto Fine.
Verrà generato automaticamente lo "scheletro" del nostro tading system, ovvero un elenco di funzioni
evento più una serie di dichiarazioni di proprietà pubbliche ed alcuni commenti utili al
programmatore per orientarsi nel codice.
//+------------------------------------------------------------------+
//| sdVolatilityBase.mq4 |
//| Copyright © 2014, SD Studio DAINESI |
//| http://www.sdStudioDainesi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, SD Studio DAINESI"
#property link "http://www.sdStudioDainesi.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---

//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---

}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---

//---
return(ret);
}
//+------------------------------------------------------------------+
Rispetto alle versioni precedenti la build 600 ora la funzione principale è chiamata OnTick(), in
luogo della precedente start(). Il prefisso On sottolinea la natura di funzione evento causata dalla
generazione di un tick (OnTick), dall'inizio di un test (OnTester), ecc..
Le funzioni OnInit e OnDeinit, come suggerisce il nome sono richiamate nella fase di inizializzazione
e terminazione del trading system (inserimento sul grafico e/o sua modifica dei parametri e sua
rimozione).

Organizzazione del codice all'interno di un trading system

Ogni trading system, al contrario di come sarebbe logico aspettarsi, deve procedere a ritroso per
poter funzionare, e quindi deve prima gestire gli ordini in essere poi aprirne di nuovi. Questo iter è
dettato dalla necessità di assicurarsi di non aprire nuovi ordini in presenza di altri. Pensate ad un
sistema che ad ogni tick verifica la generazione di un segnale di acquisto e quando riceve l'assenso
invia un ordine long. Considerando che il segnale di norma vale per tutta la durata della barra
avremo tanti ordini quanti sono i tick generati in quella candela!! E'evidentemente una pratica da
dimenticare. Occorre prima verificare la presenza di ordini preesistenti che possano invalidare
nuove aperture, gestire il portafoglio in essere e solo dopo verificare i segnali di apertura per i nuovi
ordini.

Nel nostro trading system dovremo dapprima inserire le proprietà esterne e quindi introdurre le
routine di controllo portafogli, verifica segnali e generazione ordini.

Inserimento dei parametri di Input

Dato che la generazione dei segnali avviene leggendo i prezzi ed alcuni indicatori, è necessario poter
indicare i parametri di questi oltre che definire la dimensione del lotto base.
//+------------------------------------------------------------------+
//| sdVolatilityBase.mq4 |
//| Copyright © 2014, SD Studio DAINESI |
//| http://www.sdStudioDainesi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, SD Studio DAINESI"
#property link "http://www.sdStudioDainesi.com"
#property version "1.00"
#property strict

input int MagicNumber = 4082014;


input double Lots = 1.00;

//Bollinger band parameter


input int BBPeriods = 20;
input double BBDeviations = 2.0;
input double PercentBLevel = 0.1;

//ATR parameter
input int ATRPeriods = 14;

//ATRD parameter
input int ATRDPeriods = 14;

La parola input indica che la variabile è definita come parametro modificabile dall'utente tramite una
mascherina. Nelle precedenti versioni in luogo di input veniva utilizzato il token extern.
Questi parametri saranno utilizzati dalle funzioni di verifica segnale che per comodità chiameremo
VerifyLong() e VerifyShort(). Queste due funzioni devono verificare l'esistenza delle condizioni di
esistenza dei rispettivi segnali. Il valore di ritorno di queste funzioni sarà un valore booleano per
indicare la presenza o meno di segnale operativo.

Come accennato all'inizio, il primo controllo da eseguire è però l'analisi del portafoglio esistente.
Questo esame lo si effettua in due modi:

· Leggendo il valore di ritorno della funzione OrdersTotal()


· Analizzando l'insieme degli ordini con la funzione di richiamo OrderSelect().

Il primo metodo ha una valenza accademica mentre il secondo è quello usato per creare un sistema
professionale.
La funzione OrdersTotal riporta il numero degli ordini in portafoglio senza distinzione di tipo, natura,
strumento finanziario nè origine.
Utilizzando la funzione OrderSelect è possibile analizzare in dettaglio la composizione del
portafoglio.

Iniziamo quindi a popolare la funzione OnTick():


void OnTick()
{
//--- Controllo di portafoglio
int iOrders = OrdersTotal();

//Gestione portafoglio
if(iOrders>0)
{
//Money management
}

//Generazione nuovi ordini


if(iOrders==0)
{
bool bResult;

//Ordini LONG
if(VerifyLong()==true)
{
bResult = OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,0,"sdVolatility™ LONG", MagicNumber,0,Green);
return;
}
//Ordini SHORT
if(VerifyShort()==true)
{
bResult = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,0,"sdVolatility™ SHORT", MagicNumber,0,Green);
return;
}

Si noti come il controllo per la generazione di nuovi ordini avvenga solo se non ci sono ordini in
portafoglio.

Occupiamoci ora di creare le funzioni di rilevamento del segnale e di tutte quelle correlate (ovvero
funzioni utili alla funzione radice).
//+------------------------------------------------------------------+
bool VerifyLong()
{
bool result = false;

//Si procede solo in presenza di rilevamento dell'eccesso dei prezzi rispetto alle bande di Bollinger
if(PercentB("C",1)>=1+PercentBLevel)
{
double dATR0 = iATR(Symbol(),Period(),ATRPeriods,1);
double dATR1 = iATR(Symbol(),Period(),ATRPeriods,2);

//Si procede solo in presenza di volatilità stabile o decrescente


if(dATR0<=dATR1)
{
//ATRD Minus volatility
double dATRD0 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,1);
double dATRD1 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,2);

//Generazione del segnale in caso di componente opposta stabile o in diminuzione


if(dATRD0<=dATRD1)result=true;

}
}

return(result);
}

La funzione è strutturata per limitare il tempo di elaborazione in mancanza delle singole condizioni
che formano il segnale. In pratica si evita di far compiere al processore elaborazioni inutili se le
precondizioni non sono soddisfatte. Evitare inutili calcoli risulterà importantissimo in fase di
ottimizzazione dove la quantità di processi elaborativi influisce pesantemente sui tempi di esecuzione
del processo di ottimizzazione.

La funzione accessoria PercentB() restituisce il valore del %b di Bollinger utilizzando il seguente


codice:
//|-------------------------------------------------------------+
double PercentB(string Price = "C", int Offset = 0)
{

//Calcolo del %b

double result = 0;
double BBI;
double BBS;

BBI = iBands(Symbol(), Period() , BBPeriods, BBDeviations, 0, PRICE_CLOSE, MODE_LOWER, Offset);


BBS = iBands(Symbol(), Period() , BBPeriods, BBDeviations, 0, PRICE_CLOSE,MODE_UPPER,Offset);

if(Price=="C")
{
if(Close[Offset]-BBI==0) result=0;
if(Close[Offset]-BBI!=0 && BBS-BBI !=0)
result = (Close[Offset]-BBI)/(BBS-BBI);
}
if(Price=="O")
{
if(Open[Offset]-BBI==0) result=0;
if(Open[Offset]-BBI!=0 && BBS-BBI !=0)
result = (Open[Offset]-BBI)/(BBS-BBI);
}
if(Price=="H")
{
if(High[Offset]-BBI==0) result=0;
if(High[Offset]-BBI!=0 && BBS-BBI !=0)
result = (High[Offset]-BBI)/(BBS-BBI);
}
if(Price=="L")
{
if(Low[Offset]-BBI==0) result=0;
if(Low[Offset]-BBI!=0 && BBS-BBI !=0)
result = (Low[Offset]-BBI)/(BBS-BBI);
}

if(BBS-BBI ==0) result = 0;

return(result);

Da notare che la funzione accetta due argomenti: il prezzo e l'Offset, ovvero la candela relativa al
prezzo sul quale calcolare il %b.

Gestione del portafoglio

In questa prima versione gestiremo le posizioni esistenti chiudendole per il verificarsi delle
condizioni di apertura opposta e quindi si applicherà una manovra altresì detta "Stop and Reverse".
Nel blocco di codice definito "Money Management" inseriremo quindi la funzione SAR() così
definita:
//+-----------------------------------------------------------+
void SAR()
{

bool iFool;

for(int i = OrdersTotal()-1; i>=0; i--)


{
bool bFool = OrderSelect(i, SELECT_BY_POS);
if(OrderType()==OP_BUY && VerifyShort()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);
if(iFool = true)
iFool = OrderSend(Symbol(), OP_SELL, Lots, Bid, 3, 0, 0, "sdVolatility™ SHORT", MagicNumber, 0, Red);
return;
}
if(OrderType()==OP_SELL && VerifyLong()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
if(iFool = true)
iFool = OrderSend(Symbol(), OP_BUY, Lots, Ask, 3, 0, 0, "sdVolatility™ LONG", MagicNumber, 0, Green);
return;
}
}

Si riporta quindi il listato completo:


//+------------------------------------------------------------------+
//| sdVolatilityBase.mq4 |
//| Copyright © 2014, SD Studio DAINESI |
//| http://www.sdStudioDainesi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, SD Studio DAINESI"
#property link "http://www.sdStudioDainesi.com"
#property version "1.00"
#property strict

input int MagicNumber = 4082014;


input double Lots = 1.00;

//Bollinger band parameter


input int BBPeriods = 20;
input double BBDeviations = 2.0;
input double PercentBLevel = 0.1;

//ATR parameter
input int ATRPeriods = 14;

//ATRD parameter
input int ATRDPeriods = 14;

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---

//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Controllo di portafoglio
int iOrders = OrdersTotal();

//Gestione portafoglio
if(iOrders>0)
{
//Money management
SAR();
}

//Generazione nuovi ordini


if(iOrders==0)
{
bool bResult;

//Ordini LONG
if(VerifyLong()==true)
{
bResult = OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,0,"sdVolatility™ LONG", MagicNumber,0,Green);
return;
}
//Ordini SHORT
if(VerifyShort()==true)
{
bResult = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,0,"sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}

}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---

//---
return(ret);
}
//+------------------------------------------------------------------+
bool VerifyLong()
{
bool result = false;

//Si procede solo in presenza di rilevamento dell'eccesso dei prezzi rispetto alle bande di Bollinger
if(PercentB("C",1)>=1+PercentBLevel)
{
double dATR0 = iATR(Symbol(),Period(),ATRPeriods,1);
double dATR1 = iATR(Symbol(),Period(),ATRPeriods,2);

//Si procede solo in presenza di volatilità stabile o decrescente


if(dATR0<=dATR1)
{
//ATRD Minus volatility
double dATRD0 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,1);
double dATRD1 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,2);

//Generazione del segnale in caso di componente opposta stabile o in diminuzione


if(dATRD0<=dATRD1)result=true;

}
}

return(result);
}

//+------------------------------------------------------------------+
bool VerifyShort()
{
bool result = false;

//Si procede solo in presenza di rilevamento dell'eccesso dei prezzi rispetto alle bande di Bollinger
if(PercentB("C",1)<=0-PercentBLevel)
{
double dATR0 = iATR(Symbol(),Period(),ATRPeriods,1);
double dATR1 = iATR(Symbol(),Period(),ATRPeriods,2);

//Si procede solo in presenza di volatilità stabile o decrescente


if(dATR0<=dATR1)
{
//ATRD Plus volatility
double dATRD0 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,0,1);
double dATRD1 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,0,2);

//Generazione del segnale in caso di componente opposta stabile o in diminuzione


if(dATRD0<=dATRD1)result=true;

}
}

return(result);
}

//|---------------------------------------------------------------------+
double PercentB(string Price = "C", int Offset = 0)
{

//Calcolo del %b

double result = 0;
double BBI = iBands(Symbol(), Period() ,BBPeriods,BBDeviations,0,PRICE_CLOSE,MODE_LOWER,Offset);
double BBS = iBands(Symbol(), Period() ,BBPeriods,BBDeviations,0,PRICE_CLOSE,MODE_UPPER,Offset);

if(Price=="C")
{
if(Close[Offset]-BBI==0) result=0;
if(Close[Offset]-BBI!=0 && BBS-BBI !=0) result = (Close[Offset]-BBI)/(BBS-BBI);
}
if(Price=="O")
{
if(Open[Offset]-BBI==0) result=0;
if(Open[Offset]-BBI!=0 && BBS-BBI !=0) result = (Open[Offset]-BBI)/(BBS-BBI);
}
if(Price=="H")
{
if(High[Offset]-BBI==0) result=0;
if(High[Offset]-BBI!=0 && BBS-BBI !=0) result = (High[Offset]-BBI)/(BBS-BBI);
}
if(Price=="L")
{
if(Low[Offset]-BBI==0) result=0;
if(Low[Offset]-BBI!=0 && BBS-BBI !=0) result = (Low[Offset]-BBI)/(BBS-BBI);
}

if(BBS-BBI ==0) result = 0;

return(result);

//+-----------------------------------------------------------+
void SAR()
{

bool iFool;

for(int i = OrdersTotal()-1; i>=0; i--)


{
bool bFool = OrderSelect(i, SELECT_BY_POS);
if(OrderType()==OP_BUY && VerifyShort()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);
if(iFool = true)iFool = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,0,"sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}
if(OrderType()==OP_SELL && VerifyLong()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
if(iFool = true)iFool = OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,0,"sdVolatility™ LONG", MagicNumber,0,Green);
return;
}
}

Utilizzando questo sistema per effettuare un backtest utilizzando come strumento finanziario la coppia
EURUSD, time frame a un'ora e periodo l'intero anno 2013, otterremo il seguente risultato:

Figura 20 - Esito del primo test

Per cercare di migliorare le performance e limitare il rischio si adotterà ora un procedimento


dinamico di calcolo degli stops correlati con la volatilità: lo stop loss ed il take profit saranno
calcolati come multipli dell'ATR. Introduciamo quindi i parametri esterni necessari:
//Dynamic Stops parameters
input double SLLevel = 2.0;
input double TPLevel = 1.5;
input int StopsATRPeriods = 2;

SLLevel e TPLevel sono, rispettivamente, i multipli dell'ATR calcolato su StopsATRPeriods


periodi. Se pensiamo di avere operazioni dalla durata breve opteremo per lunghezze contenute (2 o 3
periodi), altrimenti possiamo ottenere la volatilità media su lunghezze da 14 a 21 periodi.

Introducendo gli stops e ripetendo il test otteniamo il seguente risultato:

Figura 21 - Esito del secondo test: introduzione degli stops dinamici

Rispetto al primo test l'introduzione degli stop ha drasticamente diminuito il drawdown e accorciato
la durata delle operazioni.
L'eliminazione del TakeProfit aumenta la possibilità di profitti elevati elevando al contempo la
longevità delle operazioni. Il mantenimento dello stop loss mantiene calmierato il drawdown.

Figura 22 - Test con il solo Stop Loss dinamico e chiusura per SL o Stop & Reverse

La numerosità ridotta delle operazioni è da ricercare nel doppio filtro sulla volatilità (ATR e ATRD)
e nel time frame adottato (H1). Mantenendo le medesime configurazioni e riducendo il TF su un
quarto d'ora la quantità di operazioni aumenta sensibilmente mantenendo una performance similare:
Figura 23 - Test eseguito su M5 con il solo SL dinamico

Dal profilo della curva dell'equity si possono riconoscere i profitti derivanti da inversioni violente
del trend. Operazioni che vengono chiuse per Stop & Reverse. Le serie di perdite moderate
rappresentano invece le chiusure per StopLoss.

Applicazione dei lotti equivalenti


Al nostro sistema per la volatilità "buona" manca ancora un ultimo ritocco, ovvero il contenimento
del rischio ottenibile grazie all'applicazione del lotto equivalente, ovvero il mantenimento del livello
di perdita all'interno della propensione al rischio definita. Per fare ciò dovremo ricalcolare la
dimensione in lotti di ogni trade affinché il raggiungimento dello stop loss provochi una perdita
percentualmente predeterminata rispetto al capitale di rischio.
Per inserire la funzionalità del lotto equivalente è necessario implementare una funzione che abbia
come argomenti l'entità dello stop loss e la percentuale di perdita massima, ovvero la propensione al
rischio.
//|--------------------------------------------------------------------+
double EquivalentLots(int iSL, double dMaxRisk)
{

double result;
int MaxPips = iSL;
double Loss;
double PipValue;

if(Point==Poin)
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE);
else
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE)*10;

Loss = AccountBalance()*dMaxRisk;

result = Loss/(MaxPips*PipValue); //es. 500/(30*10) => 500/300 = ca. 1.5

double P = MarketInfo(Symbol(), MODE_LOTSTEP);

result = MathRound(result/ P);


result = result * P;

if(result<MarketInfo(Symbol(), MODE_MINLOT))result=MarketInfo(Symbol(), MODE_MINLOT);

return(result);
}

Per finire dovremo aggiornare l'elenco dei parametri esterni con l'aggiunta di quelli relativi
all'adozione della propensione al rischio e collegare la funzionalità nel codice operativo.
Il codice finale, con le aggiunte per il lotto equivalente, gli stop dinamici e la propensione al rischio
definita è il seguente:
//+------------------------------------------------------------------+
//| sdVolatilityBase.mq4 |
//| Copyright © 2014, SD Studio DAINESI |
//| http://www.sdStudioDainesi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, SD Studio DAINESI"
#property link "http://www.sdStudioDainesi.com"
#property version "1.00"
#property strict
input int MagicNumber = 4082014;
input double Lots = 1.00;

//Money management
input bool EquivalentLots = true;
input double MaxRisk = 0.05;

//Dynamic Stops parameters


input double SLLevel = 4.0;
input double TPLevel = 2.0;
input int StopsATRPeriods = 14;

//Bollinger band parameter


input int BBPeriods = 20;
input double BBDeviations = 2.0;
input double PercentBLevel = 0.1;

//ATR parameter
input int ATRPeriods = 21;

//ATRD parameter
input int ATRDPeriods = 21;

//Stops value in pips


int SL;
int TP;

double Poin;
double dLots;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
if (Point == 0.00001) Poin = 0.0001;
else if (Point == 0.001) Poin = 0.01;
else Poin = Point;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{

dLots = Lots;

//--- Controllo di portafoglio


int iOrders = OrdersTotal();

double dSATR = iATR(Symbol(),Period(),StopsATRPeriods,1);

SL=0;
TP=0;

SL = (dSATR*SLLevel)/Poin;
TP = (dSATR*TPLevel)/Poin;

if(SLLevel!=0 && TPLevel!=0 && EquivalentLots==true)


{
dLots = EquivalentLots(SL,MaxRisk);
}

//Gestione portafoglio
if(iOrders>0)
{
//Money management
SAR();
}

//Generazione nuovi ordini


if(iOrders==0)
{
bool bResult;

//Ordini LONG
if(VerifyLong()==true)
{
if(SLLevel!=0)bResult = OrderSend(Symbol(),OP_BUY,dLots,Ask, 3, Ask - SL*Poin, Ask + TP*Poin, "sdVolatility™ LONG", MagicNumber,0,Green);
if(SLLevel==0 && TPLevel==0)bResult = OrderSend(Symbol(),OP_BUY,dLots,Ask, 3, 0, 0, "sdVolatility™ LONG", MagicNumber,0,Green);

return;
}
//Ordini SHORT
if(VerifyShort()==true)
{
if(SLLevel!=0)bResult = OrderSend(Symbol(),OP_SELL,dLots,Bid, 3, Bid + SL*Poin, Bid - TP*Poin, "sdVolatility™ SHORT", MagicNumber,0,Red);
if(SLLevel==0)bResult = OrderSend(Symbol(),OP_SELL,dLots,Bid, 3, 0, 0, "sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}

}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---

//---
return(ret);
}
//+------------------------------------------------------------------+
bool VerifyLong()
{
bool result = false;

//Si procede solo in presenza di rilevamento dell'eccesso dei prezzi rispetto alle bande di Bollinger
if(PercentB("C",1)<=0-PercentBLevel)
{
double dATR0 = iATR(Symbol(),Period(),ATRPeriods,1);
double dATR1 = iATR(Symbol(),Period(),ATRPeriods,2);

//Si procede solo in presenza di volatilità stabile o decrescente


if(dATR0<=dATR1)
{
//ATRD Minus volatility
double dATRD0 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,1);
double dATRD1 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,1,2);

//Generazione del segnale in caso di componente opposta stabile o in diminuzione


if(dATRD0<=dATRD1)result=true;
if(ATRDPeriods==0)result=true;
}
}

return(result);
}

//+------------------------------------------------------------------+
bool VerifyShort()
{
bool result = false;

//Si procede solo in presenza di rilevamento dell'eccesso dei prezzi rispetto alle bande di Bollinger
if(PercentB("C",1)>=1+PercentBLevel)
{
double dATR0 = iATR(Symbol(),Period(),ATRPeriods,1);
double dATR1 = iATR(Symbol(),Period(),ATRPeriods,2);

//Si procede solo in presenza di volatilità stabile o decrescente


if(dATR0<=dATR1)
{
//ATRD Plus volatility
double dATRD0 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,0,1);
double dATRD1 = iCustom(Symbol(),Period(),"sdATRD v1",ATRDPeriods,0,2);

//Generazione del segnale in caso di componente opposta stabile o in diminuzione


if(dATRD0<=dATRD1)result=true;
if(ATRDPeriods==0)result=true;
}
}

return(result);
}

//|---------------------------------------------------------------------+
double PercentB(string Price = "C", int Offset = 0)
{

//Calcolo del %b

double result = 0;
double BBI = iBands(Symbol(), Period() ,BBPeriods,BBDeviations,0,PRICE_CLOSE,MODE_LOWER,Offset);
double BBS = iBands(Symbol(), Period() ,BBPeriods,BBDeviations,0,PRICE_CLOSE,MODE_UPPER,Offset);

if(Price=="C")
{
if(Close[Offset]-BBI==0) result=0;
if(Close[Offset]-BBI!=0 && BBS-BBI !=0) result = (Close[Offset]-BBI)/(BBS-BBI);
}
if(Price=="O")
{
if(Open[Offset]-BBI==0) result=0;
if(Open[Offset]-BBI!=0 && BBS-BBI !=0) result = (Open[Offset]-BBI)/(BBS-BBI);
}
if(Price=="H")
{
if(High[Offset]-BBI==0) result=0;
if(High[Offset]-BBI!=0 && BBS-BBI !=0) result = (High[Offset]-BBI)/(BBS-BBI);
}
if(Price=="L")
{
if(Low[Offset]-BBI==0) result=0;
if(Low[Offset]-BBI!=0 && BBS-BBI !=0) result = (Low[Offset]-BBI)/(BBS-BBI);
}

if(BBS-BBI ==0) result = 0;

return(result);

//+-----------------------------------------------------------+
void SAR()
{

bool iFool;

for(int i = OrdersTotal()-1; i>=0; i--)


{
bool bFool = OrderSelect(i, SELECT_BY_POS);
if(OrderType()==OP_BUY && VerifyShort()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);
if(iFool = true)
{
if(SLLevel!=0 && TPLevel!=0)iFool = OrderSend(Symbol(),OP_SELL,dLots,Bid,3, Bid + SL*Poin, Bid - TP*Poin, "sdVolatility™ SHORT", MagicNumber,0,Red);
if(SLLevel==0 && TPLevel==0)iFool = OrderSend(Symbol(),OP_SELL,dLots,Bid,3, 0, 0, "sdVolatility™ SHORT", MagicNumber,0,Red);
}
return;
}
if(OrderType()==OP_SELL && VerifyLong()==true)
{
iFool = OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
if(iFool = true)
{
if(SLLevel!=0 && TPLevel!=0)iFool = OrderSend(Symbol(),OP_BUY,dLots,Ask,3,Ask - SL*Poin, Ask + TP*Poin, "sdVolatility™ LONG", MagicNumber,0,Green);
if(SLLevel==0 && TPLevel==0)iFool = OrderSend(Symbol(),OP_BUY,dLots,Ask,3,0, 0, "sdVolatility™ LONG", MagicNumber,0,Green);
}
return;
}
}

//|--------------------------------------------------------------------+
double EquivalentLots(int iSL, double dMaxRisk)
{
double result;
int MaxPips = iSL;
double Loss;
double PipValue;

if(Point==Poin)
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE);
else
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE)*10;

Loss = AccountBalance()*dMaxRisk;

result = Loss/(MaxPips*PipValue); //es. 500/(30*10) => 500/300 = ca. 1.5

double P = MarketInfo(Symbol(), MODE_LOTSTEP);

result = MathRound(result/ P);


result = result * P;

if(result<MarketInfo(Symbol(), MODE_MINLOT))result=MarketInfo(Symbol(), MODE_MINLOT);

return(result);

Con la funzionalità del lotto equivalente le performance vengono notevolmente incrementate, al pari
del drawdown che si sposta da livelli intorno al 5% a quasi il 50%.
Figura 24 - Stessi parametri ma ogni posizione ha un rischio pari al 5% del capitale

Figura 25 - Calo del DD al 20% grazie al rischio ridotto al 2%

Figura 26 - Se il rischio viene impostato a mezzo punto percentuale (0,5% ) il DD cala sotto il 7% e la resa si mantiene su livelli interessanti (33% )

In uno scenario volatile la gestione del rischio tramite il calcolo degli stop ed il conseguente calcolo
del lotto equivalente è lo strumento essenziale per poter operare efficacemente con rischi ridotti.
Parte quarta

Implementazione pratica di un trading system per scenari


turbolenti

In questa quarta parte si accompagnerà il lettore nella creazione di un trading system che applicherà
le strategie descritte nelle prime parti, relativamente ai mercati ove le regole per la normale
volatilità non hanno fondamento. Si tratta dei mercati turbolenti, soggetti agli isterismi di mercato o
alle fasi sottili che caratterizzano gli strumenti finanziari meno liquidi.
In questa parte si insegnerà al lettore come riconoscere un pattern e conseguentemente operare
coerentemente, gestendo il rischio approssimando gli ipotetici stops.

Riconoscere lo scenario turbolento


La prima azione necessaria per mettere in azione una strategia basata sulla volatilità "cattiva" è il
riconoscimento dello scenario. Questo avviene attraverso la scansione del periodo alla ricerca dei
pattern di turbolenza. A corollario di quanto detto si consiglia di fermare l'operatività di altre
strategie (trend, lateralità e volatilità "buona") in presenza di pattern di turbolenza.
Riconoscere lo scenario tramite il riconoscimento dei pattern ci spinge direttamente ad analizzare gli
algoritmi di riconoscimento che verranno poi tradotti in codice all'interno del trading system.
In questa quarta parte ci concentreremo sul riconoscimento dei seguenti tre pattern:
· Spike
· Gap
· Barra Inside
Per ognuno di essi esistono delle regole per definire gli stops ed i setup.
Per gli Spike ricercheremo la ricucitura di almeno un terzo dell'estensione della candela con stop
loss identico.
Per i Gap il target è la loro ricucitura completa e lo stop loss è un multiplo della volatilità a medio
periodo.
Per le barre Inside lo stop loss è pari all'opposto del punto di break out della barra Outside e
obiettivo libero.

Riconoscimento degli Spike


Per riconoscere un pattern occorre analizzare a ritroso lo storico dei prezzi. Questo metodo, alquanto
inusuale nella pratica visuale, permette di riconoscere in modo rapido i pattern, anche complessi e
formati da più barre. Se infatti dovessimo analizzare da sinistra verso destra (come la mente umana è
solita fare nel pen trading) dovremmo far analizzare dal processore tutto lo storico, dal più remoto al
più recente, prima di riconoscere un pattern. Con l'analisi a ritroso, invece, riconosciamo il pattern
più recente o possiamo addirittura fermare la ricerca se l'ipotetico riconoscimento dovesse risultare
non più attuale (ovvero appena concluso).
Il pattern dello Spike è formato da alcune barre in trend seguite da una barra di lunghezza molto
ampia dove l'apertura e la chiusura sono molto vicine e la barra successiva è in controtendenza
rispetto all'eccesso dello spike. Alcuni teorici indicano che il prezzo di chiusura deve essere nei
pressi del minimo negli Spike Up e nei pressi del massimo negli Spike Down. Chi vi scrive è invece
dell'avviso che questa indicazione non ha molta importanza in quanto l'orario di chiusura di alcune
barre è differente e dipende dal fuso orario adottato, quindi lo stesso strumento finanziario potrebbe
generare un segnale ad un cliente europeo e negarlo ad uno asiatico. Quello che conta è la dimensione
anomala della candela in rapporto alle precedenti e il raggiungimento o superamento dei
minimi/massimo di periodo. Si ricorda infatti che, a differenza di tante altre tecniche di sfruttamento
degli spike che operano sulla rottura del successivo Ledge, in questo libro si insegnerà a sfruttare gli
spike durante la loro formazione. La direzione del trend che precede lo spike non è determinante.
I dati di cui avremo bisogno, prima di analizzare a ritroso lo storico, sono i seguenti:
· Massimi e minimi di periodo (si possono utilizzare anche i punti Pivot)
· La volatilità media calcolata su un intervallo di almeno 14 periodi
Successivamente analizzeremo le candele dei prezzi iniziando sempre da quella in corso, la quale per
validare la prosecuzione di ricerca deve essere di ampiezza almeno doppia rispetto alla volatilità
media e apertura lontana dal prezzo attuale, situato ai massimi o minimi di barra.
Se la condizione precedente è verificata si passa a controllare le barre precedenti che devono essere
di estensione nella media e con direzionalità definita (massimi e minimi crescenti o massimi e minimi
calanti).
Se entrambe le condizioni sono verificate si calcolano gli stop, ovvero si ottiene il valore pari ad un
terzo dell'estensione della barra in corso (quella dell'ipotetico Spike).
Ottenuti gli stop (in questo caso identici) si calcola il lotto equivalente e si apre la posizione.
Vediamo quindi il codice della funzione apposita che oltre a riconoscere il pattern determina anche
gli stop e la dimensione dell'ordine.

//+------------------------------------------------------------------+
bool VerifySpike(int& Direction, int& SL, int& TP, double& Vol)
{

bool result = false;

Direction = -1;

//Recupero del min/max di periodo


double dMax = High[iHighest(Symbol(),Period(),MODE_HIGH,RangeInspection,1)];
double dMin = Low[iLowest(Symbol(),Period(),MODE_LOW,RangeInspection,1)];

//Esco se non sono in corrispondenza dei max/min di periodo


if(Ask<dMax && Bid>dMin)return(false);
//Recupero della volatilità come misura media delle barre
double dATR = iATR(Symbol(),Period(),RangeInspection,1);

//Riconoscimento dell'anomalia di estensione


double dExtension = High[0]-Low[0];
if(dATR*2>dExtension)return(false);

//Identificazione della direzione e distanza tra Open e Bid/Ask per determinarne il verso operativo
if(Ask>Open[0] && Ask-Open[0]>dExtension/2)Direction=OP_SELL;
if(Bid<Open[0] && Open[0]-Bid>dExtension/2)Direction=OP_BUY;
if(Direction<0)return(false);

//Ricerca a ritroso delle barre in trend


if(Direction>=0)
{
if((Low[1]>Low[2]&&High[1]>High[2])||(Low[1]<Low[2]&&High[1]<High[2])) result=true;
}

//Se ilo pattern è trovato determino gli stop ed il volume


if(result==true)
{
TP = (dExtension/3)/Poin;
SL = TP;
Vol = EquivalentLots(SL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(SL<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

return(result);

Osservando bene questa funzione si potrà notare come si è cercato di ottimizzare il codice per
incrementare la velocità di esecuzione (se le precondizioni non sono soddisfatte si esce dalla
funzione) e come risolvere incongruenze operative quali la dimensione assoluta minima degli stop in
relazione allo spread. Un pattern potrebbe trovarsi anche in presenza di volatilità oggettivamente
bassa e generare una barra spike quale multiplo della volatilità. Per limitare questi inconvenienti si è
deciso di adottare un parametro, SLSpreadMultiplier, che filtra i segnali con stop troppo ridotti.
Di seguito si mostrano i risultati ottenuti con diverse misure di questo parametro sul periodo 2013 e
strumento EURUSD M15 e spread fissato a 2 pips.

Figura 27 - SL minimo pari a 5 volte lo Spread

Figura 28 - SL minimo pari a 8 volte lo Spread

Figura 29 - SL minimo pari a 12 volte lo Spread

Come si può notare dall'esito dei test, il filtro sulla dimensione degli Stop permette di rendere
profittevole il sistema a scapito della frequenza operativa.
Figura 30 - Esempio di entrata su presunto Spike

In figura 29 è evidenziata un'operazione da manuale eseguita su quella che sino ad allora pareva
essere una Spike in formazione. Come si può notare, il brusco movimento rialzista si è parzialmente
riassorbito permettendo il raggiungimento del profitto pari al terzo dell'estensione di barra. Col
passare del tempo il segnale si sarebbe perso e l'identificazione della Spike impossibile.

Figura 31 - Ottimizzazione del parametro SLSpreadMultiplier (capitale di base 100.000)

Come si può notare all'aumentare del moltiplicatore aumenta l'attendibilità ma diminuiscono i segnali
con conseguente impoverimento dei profitti. Calando il parametro si accolgono troppi falsi segnali e
si generano troppe operazioni. Lo spike non è un pattern frequente per cui è lecito aspettarsi pochi
buoni segnali all'interno di un test.

Riconoscimento dei Gap


Il Gap è il pattern più facile da riconoscere in quanto l'elemento qualificante è la differenza tra Open
e Close della candela precedente, oltre ad evidenziare un distacco dagli estremi (massimo e minimo)
della candela precedente.
Questo pattern si presenta tipicamente alla ripresa delle sessioni di trading. L'entità della distanza, il
gap, è direttamente connessa alle notizie che avranno turbato le aspettative degli investitori tra la fine
della sessione precedente e la ripresa di quella attuale. Nei mercati regolamentati si è soliti
pubblicare notizie che potrebbero turbare i mercati alla chiusura delle sessioni di contrattazione.
questa pratica permette di smorzare gli effetti sulle quotazioni in quanto gli operatori di mercato
saranno in grado di "metabolizzare" meglio l'effetto della notizia prima di riprendere l'attività di
trading. Naturalmente più è estesa la pausa tra una sessione e la successiva e maggiore è la
possibilità di assistere a grandi gap. E'questo il caso della ripresa settimanale.
Un gap si può generare anche per la diffusione di notizie influenti derivanti da accadimenti
geopolitici o eventi macroeconomici. In questo caso si tratta di gap all'interno delle sessioni.
Altre volte i gap si verificano per l'improvvisa nascita di un rally dovuto al superamento di
determinate soglie di prezzo corrispondenti a livelli di stop utilizzati dalla maggioranza degli
investitori (supporti e resistenze di lungo periodo).
Riconoscimento del Gap via codice
Il riconoscimento del pattern è particolarmente semplice, occorre solo verificare la distanza del
prezzo di apertura dalla chiusura della candela precedente e dagli estremi (minimo e massimo).
Naturalmente anche nel gap occorre astenersi dall'utilizzare gap talmente piccoli da essere
insignificanti. Anche su questo pattern utilizzeremo il medesimo parametro utilizzato sugli Spike per
filtrare gli stop troppo piccoli.
La funzione di riconoscimento dovrà anche fornire gli Stops e la dimensione equivalente.
//+------------------------------------------------------------------+
bool VerifyGap(int& Direction, int& SL, int& TP, double& Vol)
{

bool result = false;

Direction = -1;

//Verifica del del Gap


if(Open[0]<Low[1])Direction=OP_BUY;
if(Open[0]>High[1])Direction=OP_SELL;
if(Direction<0)return(false);

result=true;

//Misura del Gap


double dExtension;
if(Direction==OP_BUY)dExtension=Low[1]-Ask;
if(Direction==OP_SELL)dExtension=Bid-High[1];

//Se il pattern è trovato determino gli stop ed il volume


if(result==true)
{
TP = dExtension/Poin;
SL = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*SLLevel;
Vol = EquivalentLots(SL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(TP<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

return(result);

Osservando il codice MQL si può notare come il riconoscimento del Gap sia particolarmente
semplice, è sufficiente constatare che il prezzo di apertura della candela in corso sia staccato
dall'intervallo di prezzi coperto dalla candela precedente e se l'apertura è sotto l'intervallo
precedente saremo in presenza di un "gap down", viceversa se l'apertura è sopra avremo un "gap
up". L'operatività suggerita sarà contraria alla direzione del gap.
if(Open[0]<Low[1])Direction=OP_BUY;
if(Open[0]>High[1])Direction=OP_SELL;

Il calcolo degli stop sarà fatto in funzione della distanza tra Open e estremo dell'intervallo
precedente per il take profit e come multiplo della volatilità per lo stop loss.
TP = dExtension/Poin;
SL = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*SLLevel;

Per evitare di prendere in considerazioni gap poco significativi viene introdotto un filtro "anti
rumore" che nega il segnale in caso il gap sia particolarmente ridotto (meno di un multiplo dello
spread attuale).
if(TP<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

La dimensione dell'operazione viene quindi calcolata in base alla propensione al rischio tramite
l'ormai nota funzione di calcolo del lotto equivalente.
Vol = EquivalentLots(SL, MaxRisk);

Al fine di testare la strategia basata sui soli Gap si riporta il grafico dell'equity ottenuta su un periodo
di quattro anni su EURUSD H4.

Figura 32 - 4 anni di ricerca sui Gap su EURUSD H4

Riconoscimento dei pattern Inside

Dopo gli spike ed i gap veniamo ora ai pattern Inside quale strategia applicabile negli scenari di
instabilità dei mercati.
Per riconoscere un pattern inside occorre verificare l'intervallo di estensione di due barre
consecutive e quindi intercettare il breakout della barra in corso sul range precedente.

La funzione VerifyInside, simile alle precedenti, si occupa proprio di questo.


//+------------------------------------------------------------------+
bool VerifyInside(int& Direction, int& iSL, int& iTP, double& Vol)
{

bool result = false;

//Verifica che la volatilità attuale sia superiore a quella media


if(iATR(Symbol(),Period(),ATRPeriods,1)<iATR(Symbol(),Period(),RangeInspection,1))return(false);

Direction = -1;

//Verifica del del breakout


if(Bid<Low[1])Direction=OP_SELL;
if(Ask>High[1])Direction=OP_BUY;
if(Direction<0)return(false);

result=true;

//Verifica del pattern Inside


if(High[1]>High[2] || Low[1]<Low[2])return(false);

//Misura dell'estensione degli stop


double dExtension = 0;
if(Direction==OP_BUY) dExtension=Ask-Low[1];
if(Direction==OP_SELL)dExtension=High[1]-Bid;

//Se il pattern è trovato determino gli stop ed il volume


if(result==true)
{
iSL = dExtension/Poin;
iTP = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*TPLevel;
if(iSL > 0) Vol = EquivalentLots(iSL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(iSL<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

return(result);

Nella prima parte del codice si ricerca solamente il breakout per determinare il tipo di operatività.
if(Bid<Low[1])Direction=OP_SELL;
if(Ask>High[1])Direction=OP_BUY;

Mentre solo successivamente si ricerca il pattern inside,


if(High[1]>High[2] || Low[1]<Low[2])return(false);

e successivamente si calcolano gli stops.


SL = dExtension/Poin;
TP = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*TPLevel;
if(SL > 0) Vol = EquivalentLots(SL, MaxRisk);

Al fine di testare la strategia basata sui soli pattern Inside si riporta il grafico dell'equity ottenuta su
un periodo di quattro anni su EURUSD Daily.

Figura 33 - 4 anni di ricerca sui pattern Inside su EURUSD Daily


Parte quinta

Considerazioni finali

Ognuna delle strategie mostrate ha adottato degli stops fissi, calcolati nel momento stesso
dell'apertura degli ordini. Questo modo di operare è ovviamente limitante ma è ottimo per insegnare
al lettore le strategie operative che fungeranno da base di partenza per costruirsi una strategia
personale e professionale.
Un buon money management non si ferma ad un calcolo corretto degli stops e delle dimensioni più
convenienti per singola operazione ma prosegue con la loro gestione dinamica. Questo significa
implementare una strategia di uscita per parti ed uno spostamento dinamico, monodirezionale, degli
stops. Grazie a queste tecniche è possibile abbassare il drawdown e correggere in tempo gli obiettivi
di profitto.
Si rimanda ad un successivo testo l'approfondimento sulle tecniche di implementazione del money
management.
Appendice I
Codice per l'implementazione dell'indicatore ATRD

//+------------------------------------------------------------------+
//| SD Average True Range Directional.mq4 |
//| Copyright © 2014, sd Studio DAINESI |
//| http://www.sdStudioDainesi.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, sd Studio DAINESI"
#property link "http://www.sdStudioDainesi.com/"

#property indicator_separate_window
#property indicator_buffers 3
//COLORS
#property indicator_color1 DodgerBlue
#property indicator_color2 Green
#property indicator_color3 Yellow

//---- input parameters


extern int ATRDPeriods = 3;

//---- buffers
double AtrBuffer[];
double AtrDPlusBuffer[];
double AtrDMinusBuffer[];

double TempBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
string short_name;

IndicatorBuffers(3);

//---- indicator line


SetIndexStyle(0,DRAW_LINE);
SetIndexStyle(1,DRAW_LINE);
SetIndexStyle(2,DRAW_LINE);

SetIndexBuffer(0,AtrDPlusBuffer);
SetIndexBuffer(1,AtrDMinusBuffer);
SetIndexBuffer(2,AtrBuffer);

//---- name for DataWindow and indicator subwindow label


short_name="ATRD(" + ATRDPeriods + ")";
IndicatorShortName(short_name);

SetIndexLabel(0,"Plus volatility");
SetIndexLabel(1,"Minus volatility");
SetIndexLabel(2,"ATR");

//----
SetIndexDrawBegin(0,ATRDPeriods);
SetIndexDrawBegin(1,ATRDPeriods);
SetIndexDrawBegin(2,ATRDPeriods);

//----
return(0);
}
//+------------------------------------------------------------------+
//| Average True Range |
//+------------------------------------------------------------------+
int start()
{

int i;
int counted_bars = IndicatorCounted();

if(Bars<=ATRDPeriods) return(0);

//---- initial zero


if(counted_bars<1)
{
for(i=1;i<=ATRDPeriods;i++)
{
AtrBuffer[Bars-i]=0;
AtrDPlusBuffer[Bars-i]=0;
AtrDMinusBuffer[Bars-i]=0;
}
}
if(counted_bars>0) counted_bars--;

int limit = Bars-counted_bars;

for(i=0; i<limit; i++)


{
double ATRI;
double RPlus;
double RMinus;

ATRI = 0;
RPlus = 0;
RMinus = 0;

for(int y=i;y<i+ATRDPeriods;y++)
{
ATRI = ATRI + MathMax(High[y],High[y+1])-MathMin(Low[y],Low[y+1]);
//Corpo Positivo
if(Open[y]<Close[y])
{
RPlus = RPlus + (Close[y]-Open[y]); //Il Body
RMinus = RMinus + (High[y]-Close[y]) + (Open[y]-Low[y]); //Le Shadows
RPlus = RPlus + (High[y]-Open[y]) + (Close[y]-Low[y]);
if(High[y+1]>High[y])RMinus = RMinus + (High[y+1]-High[y]);
if(Low[y+1]<Low[y]) RPlus = RPlus + (Low[y]-Low[y+1]);

}
//Corpo Negativo
if(Open[y]>Close[y])
{
RMinus = RMinus + (Open[y]-Close[y]);
RPlus = RPlus + (High[y]-Open[y]) + (Close[y]-Low[y]);
RMinus = RMinus + (High[y]-Close[y]) + (Open[y]-Low[y]);
if(High[y+1]>High[y])RMinus = RMinus + (High[y+1]-High[y]);
if(Low[y+1]<Low[y])RPlus = RPlus + (Low[y]-Low[y+1]);

}
//Doji
if(Open[y]==Close[y])
{
RPlus = RPlus + (High[y]-Low[y]);
RMinus = RMinus + (High[y]-Low[y]);
if(High[y+1]>High[y])RMinus = RMinus + (High[y+1]-High[y]);
if(Low[y+1]<Low[y])RPlus = RPlus + (Low[y]-Low[y+1]);
}
}

AtrBuffer[i]=ATRI/ATRDPeriods;
AtrDPlusBuffer[i] = RPlus/ATRDPeriods;
AtrDMinusBuffer[i] = RMinus/ATRDPeriods;
}

return(0);
}
//+------------------------------------------------------------------+
Codice per l'implementazione del trading system sdVolatilityBadBase
//+------------------------------------------------------------------+
//| sdVolatilityBadBase.mq4 |
//| Copyright © 2014, SD Studio DAINESI |
//| http://www.sdStudioDainesi.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2014, SD Studio DAINESI"
#property link "http://www.sdStudioDainesi.com"
#property version "1.00"
#property strict

input int MagicNumber = 7082014;


input double MaxRisk = 0.05;

//Dynamic Stops parameters


input double SLLevel = 4.0;
input double TPLevel = 2.0;
input int StopsATRPeriods = 14;
input double SLSpreadMultiplier = 12.0;

//Pattern recognition parameter


input bool SpikeSignal = true;
input bool GapSignal = true;
input bool InsideSignal = true;

input int RangeInspection = 100;

//ATR parameter
input int ATRPeriods = 21;

//Stops value in pips


int SL;
int TP;

double Poin;
double dLots;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
if (Point == 0.00001) Poin = 0.0001;
else if (Point == 0.001) Poin = 0.01;
else Poin = Point;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---

}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{

//--- Controllo di portafoglio


int iOrders = OrdersTotal();

double dSATR = iATR(Symbol(),Period(),StopsATRPeriods,1);

SL=0;
TP=0;

SL = (dSATR*SLLevel)/Poin;
TP = (dSATR*TPLevel)/Poin;

if(SLLevel!=0 && TPLevel!=0)


{
dLots = EquivalentLots(SL,MaxRisk);
}

//Gestione portafoglio
if(iOrders>0)
{
//Money management

//Generazione nuovi ordini


if(iOrders==0)
{
int Dir = -1;
bool bResult = false;
if(SpikeSignal==true)bResult = VerifySpike(Dir, SL, TP, dLots);

if(bResult == true)
{
if(Dir==OP_BUY) bResult = OrderSend(Symbol(),OP_BUY,dLots,Ask, 3, Ask - SL*Poin, Ask + TP*Poin, "sdVolatility™ LONG", MagicNumber,0,Green);
if(Dir==OP_SELL)bResult = OrderSend(Symbol(),OP_SELL,dLots,Bid, 3, Bid + SL*Poin, Bid - TP*Poin, "sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}

if(bResult==false)
{
if(GapSignal==true)bResult = VerifyGap(Dir, SL, TP, dLots);
}

if(bResult == true)
{
if(Dir==OP_BUY) bResult = OrderSend(Symbol(),OP_BUY,dLots,Ask, 3, Ask - SL*Poin, Ask + TP*Poin, "sdVolatility™ LONG", MagicNumber,0,Green);
if(Dir==OP_SELL)bResult = OrderSend(Symbol(),OP_SELL,dLots,Bid, 3, Bid + SL*Poin, Bid - TP*Poin, "sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}

if(bResult==false)
{
if(InsideSignal==true)bResult = VerifyInside(Dir, SL, TP, dLots);
}

if(bResult == true)
{
if(Dir==OP_BUY) bResult = OrderSend(Symbol(),OP_BUY,dLots,Ask, 3, Ask - SL*Poin, Ask + TP*Poin, "sdVolatility™ LONG", MagicNumber,0,Green);
if(Dir==OP_SELL)bResult = OrderSend(Symbol(),OP_SELL,dLots,Bid, 3, Bid + SL*Poin, Bid - TP*Poin, "sdVolatility™ SHORT", MagicNumber,0,Red);
return;
}

}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---

//---
return(ret);
}

//+------------------------------------------------------------------+
bool VerifySpike(int& Direction, int& iSL, int& iTP, double& Vol)
{

bool result = false;

Direction = -1;

//Recupero del min/max di periodo


double dMax = High[iHighest(Symbol(),Period(),MODE_HIGH,RangeInspection,1)];
double dMin = Low[iLowest(Symbol(),Period(),MODE_LOW,RangeInspection,1)];

//Esco se non sono in corrispondenza dei max/min di periodo


if(Ask<dMax && Bid>dMin)return(false);

//Recupero della volatilità come misura media delle barre


double dATR = iATR(Symbol(),Period(),RangeInspection,1);

//Riconoscimento dell'anomalia di estensione


double dExtension = High[0]-Low[0];
if(dATR*2>dExtension)return(false);

//Identificazione della direzione e distanza tra Open e Bid/Ask per determinarne il verso operativo
if(Ask>Open[0] && Ask-Open[0]>dExtension/2)Direction=OP_SELL;
if(Bid<Open[0] && Open[0]-Bid>dExtension/2)Direction=OP_BUY;
if(Direction<0)return(false);

//Ricerca a ritroso delle barre in trend


if(Direction>=0)
{
if((Low[1]>Low[2] && High[1]>High[2])||(Low[1]<Low[2] && High[1]<High[2]))result=true;
}

//Se ilo pattern è trovato determino gli stop ed il volume


if(result==true)
{
iTP = (dExtension/3)/Poin;
iSL = iTP;
Vol = EquivalentLots(iSL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(iSL<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;
return(result);

//+------------------------------------------------------------------+
bool VerifyGap(int& Direction, int& iSL, int& iTP, double& Vol)
{

bool result = false;

Direction = -1;

//Verifica del del Gap


if(Open[0]<Low[1])Direction=OP_BUY; //&& Open[0]==Close[0]
if(Open[0]>High[1])Direction=OP_SELL;// && Open[0]==Close[0]
if(Direction<0)return(false);

result=true;

//Misura del Gap


double dExtension = 0;
if(Direction==OP_BUY)dExtension=Low[1]-Ask;
if(Direction==OP_SELL)dExtension=Bid-High[1];

//Se ilo pattern è trovato determino gli stop ed il volume


if(result==true)
{
iTP = dExtension/Poin;
iSL = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*SLLevel;
Vol = EquivalentLots(iSL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(iTP<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

return(result);

//+------------------------------------------------------------------+
bool VerifyInside(int& Direction, int& iSL, int& iTP, double& Vol)
{

bool result = false;

//Verifica che la volatilità attuale sia superiore a quella media


if(iATR(Symbol(),Period(),ATRPeriods,1)<iATR(Symbol(),Period(),RangeInspection,1))return(false);

Direction = -1;

//Verifica del del breakout


if(Bid<Low[1])Direction=OP_SELL;
if(Ask>High[1])Direction=OP_BUY;
if(Direction<0)return(false);

result=true;

//Verifica del pattern Inside


if(High[1]>High[2] || Low[1]<Low[2])return(false);

//Misura dell'estensione degli stop


double dExtension = 0;
if(Direction==OP_BUY) dExtension=Ask-Low[1];
if(Direction==OP_SELL)dExtension=High[1]-Bid;

//Se il pattern è trovato determino gli stop ed il volume


if(result==true)
{
iSL = dExtension/Poin;
iTP = (iATR(Symbol(),Period(),RangeInspection,1)/Poin)*TPLevel;
if(iSL > 0) Vol = EquivalentLots(iSL, MaxRisk);
}

//Inibizione in caso di estensione ridotta rispetto allo spread


if(iSL<((Ask-Bid)/Poin)*SLSpreadMultiplier)result=false;

return(result);

//|--------------------------------------------------------------------+
double EquivalentLots(int iSL, double dMaxRisk)
{

double result;
int MaxPips = iSL;
double Loss;
double PipValue;

if(Point==Poin)
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE);
else
PipValue=MarketInfo(Symbol(), MODE_TICKVALUE)*10;
Loss = AccountBalance()*dMaxRisk;

result = Loss/(MaxPips*PipValue); //es. 500/(30*10) => 500/300 = ca. 1.5

double P = MarketInfo(Symbol(), MODE_LOTSTEP);

result = MathRound(result/ P);


result = result * P;

if(result<MarketInfo(Symbol(), MODE_MINLOT))result=MarketInfo(Symbol(), MODE_MINLOT);

return(result);

[1]
In Microeconomia, ad esempio, un livello può rappresentare lo strike per delle opzioni e quindi un suo superamento muterebbe il valore del derivato. In Macroeconomia un livello potrebbe fare da discriminante per rendere o meno
competitiva l'economia di una nazione su beni fungibili di libero scambio.
[2]
Il corpo di una candela, o body , è la zona compresa tra prezzo di apertura e prezzo di chiusura. Le zone comprese tra il corpo ed il massimo e tra il corpo ed il minimo sono definite ombre, o shadows.
[3]
Si rimanda ad altro libro l'illustrazione di siffatti indicatori.
[4]
Si avverte il lettore che il trading system che verrà creato avrà una sola valenza accademica e non dovrà essere utilizzato con denaro reale o in concomitanza con altri trading system. Qualora si volesse la versione professionale si prega di
contattare lo Studio Dainesi per una valutazione commerciale (info@sdStudioDainesi.com).
Table of Contents
[1]
[2]
[3]
[4]

Potrebbero piacerti anche