English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Diversi Modi per Trovare una Trend in MQL5

Diversi Modi per Trovare una Trend in MQL5

MetaTrader 5Trading | 9 dicembre 2021, 13:52
784 0
Dmitriy Skub
Dmitriy Skub

Introduzione

Qualsiasi trader conosce la regola "Il trend è tuo amico, segui la tendenza", ma quasi ognuno ha la sua idea di cosa sia un trend. Quasi tutti i trader hanno sentito o letto storie orribili che raccontano come i trader che hanno fatto trading contro il trend si sono rovinati.

Qualsiasi trader darebbe molto per l'opportunità di rilevare con precisione una tendenza in un dato momento. Forse, questo è il Santo Graal che tutti stanno cercando. In questo articolo, considereremo diversi modi per rilevare una tendenza. Per essere più precisi - come programmare diversi modi classici per rilevare una tendenza mediante MQL5.


1. Cos'è un Trend e Perché Conoscerlo

Prima di tutto, formuliamo il concetto generale di trend.

Trend - è una tendenza a lungo termine (direzione) del cambiamento dei prezzi nel mercato. Da questa definizione generale di trend derivano le conseguenze:

  • La direzione della variazione dei prezzi dipende dall’intervallo in cui viene considerata la timeseries dei prezzi.
  • La direzione della variazione dei prezzi dipende dal punto di riferimento da cui parte l'analisi delle timeseries per individuare un trend.

Illustriamo questo concetto:

Figura 1. Analisi del Trend

Figura 1. Analisi del Trend

Guardando la figura, si può vedere che la tendenza generale dalla fine del 2005 fino a maggio 2006 è in crescita (freccia verde sul grafico). Ma se consideriamo porzioni più piccole del grafico dei prezzi, scoprirai che a febbraio 2006 la tendenza era chiaramente al ribasso (freccia rossa sul grafico) e quasi per tutto il mese di gennaio il prezzo era nel corridoio laterale (freccia gialla).

Quindi, prima di identificare una tendenza, devi determinare a quale timeframe sei interessato. Per il trading, il timeframe determina prima di tutto il tempo di mantenimento della posizione sul mercato, dalla sua apertura fino alla chiusura. Oltre a ciò, dipendenti sono i livelli di stop protettivi e le chiusure previste, nonché la frequenza delle operazioni di trading.

Lo scopo di questo articolo è quello di aiutare i nuovi trader a utilizzare con competenza gli strumenti di rilevamento dei trend forniti dalla piattaforma MetaTrader 5. Questo articolo ha anche lo scopo di fornire conoscenze di base sulla scrittura di semplici indicatori che automatizzano questo processo. L'obiettivo finale è quello di scrivere semplici expert che utilizzano questi indicatori per il trading automatizzato.  

  In definitiva, considereremo il grafico dei prezzi giornalieri (timeframe D1 nel terminale) dello strumento più liquido nel mercato Forex - EURUSD. Il tempo di mantenimento della posizione su questo timeframe può variare da diversi giorni a diversi mesi. Di conseguenza, l'obiettivo - è quello di prendere centinaia e persino migliaia di punti e gli stop loss protettivi si trovano a una distanza di diverse centinaia di punti.

In generale, tutto ciò che viene descritto di seguito può essere utilizzato in qualsiasi timeframe. Tuttavia, tieni presente che più piccolo è il timeframe del grafico, maggiore è l'impatto sul trade della componente rumore, causata da notizie, speculazioni di mercato dei principali partecipanti e altri fattori che influenzano la volatilità del mercato.

Se teniamo conto del fatto che più lunga è la tendenza, meno è probabile che si sposti, allora, quando si fa trading con il trend, è più probabile che guadagni piuttosto che perdere denaro. Ora, devi capire come individuare una trend sul grafico dei prezzi. Ne parleremo in questo articolo.


2. Come Rilevare un Trend

Ecco alcuni modi noti per rilevare un trend

  1. Mediante Media Mobile
  2. Da picchi di zigzag
  3. Mediante indicazioni ADX
  4. Attraverso NRTR
  5. Mediante il colore dei candlestick Heiken Ashi

Considereremo coerentemente tutti questi metodi, i loro vantaggi e svantaggi. Poi, li confronteremo nello stesso periodo.

2.1. Rilevamento dei Trend Utilizzando la Media Mobile

Forse, il modo più semplice per rilevare un trend e la sua direzione - usando le medie mobili. Uno dei primi strumenti di analisi tecnica - la media mobile - è ancora utilizzato in diverse varianti ed è alla base della maggior parte degli indicatori. I trader usano sia una media mobile che un intero set di esse che a volte viene chiamato "fan". 

Formuliamo una semplice regola per una media mobile:
  • Il trend sale se in un determinato timeframe il prezzo di chiusura della barra è superiore alla media mobile.
  • Il trend scende se in un determinato timeframe il prezzo di chiusura della barra è inferiore alla media mobile.

In questo caso useremo il prezzo di chiusura della barra per ridurre il numero di cambiamenti di trend "false", quando il prezzo fluttua su e giù vicino alla media mobile (il cosiddetto "bounce").  

Illustriamo questo metodo:

Figura 2. Identificazione di un Trend Utilizzando la Media Mobile

Figura 2. Identificazione di un Trend Utilizzando la Media Mobile

Qui usiamo il grafico EURUSD D1 e una semplice media mobile con periodo 200, costruita sui prezzi di chiusura (linea rossa sul grafico). Nella figura in basso, puoi vedere l'indicatore di tendenza appositamente sviluppato - MATrendDetector. La direzione del trend è indicata dalla posizione dell'istogramma dell'indicatore, rispetto all'asse zero. +1 corrisponde alla tendenza al rialzo. -1 - tendenza al ribasso. In questo articolo, inoltre, parleremo di questo e altri indicatori.

Puoi vedere che quando la barra si chiude sopra/sotto la media mobile, il prezzo si trasforma spesso in direzione opposta. In altre parole, questo metodo dà molti falsi segnali. Ecco perché il suo utilizzo in expert ed indicatori è molto limitato, solo come filtro di tendenza molto "rudimentale".

2.2. Rilevamento dei Trend Utilizzando Tre Medie Mobili

Cosa si può fare per migliorare la qualità del rilevamento del trend utilizzando le medie mobili? Ad esempio, è possibile utilizzare due o più medie mobili con periodi diversi. Dunque, la regola di rilevamento dei trend per qualsiasi numero (più di uno) di medie mobili con periodi diversi sarà la seguente:

  • Il trend cresce se in un determinato timeframe tutte le medie mobili sono tracciate in ordine crescente corretto alla chiusura della barra.
  • Il trend diminuisce se in un determinato timeframe tutte le medie mobili sono tracciate in ordine di caduta corretto alla chiusura della barra.

Qui usiamo i seguenti termini:

  • Ordine crescente corretto: ogni media mobile deve essere superiore a tutte le altre medie mobili con periodo più elevato.
  • Ordine decrescente corretto - ogni media mobile deve essere inferiore a tutte le altre medie mobili con periodo più alto.

Tale "ordine corretto delle medie" è anche chiamato come l'apertura al rialzo/al ribasso del fan delle medie, a causa della somiglianza visiva.

Illustriamo questo metodo:

Figura 3. Rilevamento del Trend Utilizzando Diverse Medie Mobili

Figura 3. Rilevamento dei Trend Utilizzando Diverse Medie Mobili

Qui utilizziamo il grafico EURUSD D1 e le medie mobili semplici con periodi 200 (linea rossa spessa), 50 (linea gialla di medio spessore) e 21 (linea viola sottile), costruiti sui prezzi di chiusura.

Nella figura in basso, puoi vedere l'indicatore di tendenza appositamente sviluppato - FanTrendDetector. La direzione del trend è indicata dalla posizione dell'istogramma dell'indicatore, rispetto all'asse zero. +1 corrisponde alla tendenza al rialzo. -1 - tendenza al ribasso. Se il valore dell'istogramma è pari a zero, significa che il trend non può essere rilevato. C'è anche l'indicatore MATrendDetector per il confronto.

È evidente che il numero di falsi allarmi di cambiamento di trend è stato ridotto. Tuttavia, il ritardo nel rilevamento dei trend è stato aumentato. Questo ha senso: fino a quando tutte le medie mobili non si allineeranno nell'ordine "corretto", potrebbe essere necessario del tempo. Cosa è meglio e cosa no, dipende dal sistema di trading che utilizza questi metodi.

In questo caso, i valori di periodo delle medie non sono comunque selezionati, ma sono più ampiamente utilizzati dai trader e dall'autore dell'articolo. Selezionando un insieme di medie e il loro numero, puoi provare a migliorare le caratteristiche di questo metodo di rilevamento dei trend per una particolare coppia di valute.

2.3. Rilevamento dei Trend Utilizzando i Massimi e i Minimi dell'indicatore ZigZag

Ora, affrontiamo il rilevamento dei trend dal punto di vista dei classici dell'analisi tecnica. Vale a dire, useremo la seguente regola di Charles Dow:

  • Il trend sale se ogni successivo massimo locale del grafico dei prezzi è superiore al precedente massimo locale e ogni successivo minimo locale del grafico dei prezzi è anche superiore al precedente minimo locale.
  • Il trend scende se ogni successivo grafico dei prezzi minimo locale è inferiore al minimo locale precedente e ogni successivo massimo locale del grafico dei prezzi è anche inferiore al massimo locale precedente.

Troveremo massimi/minimi locali nelle parti superiori dell'indicatore Zigzag.

Illustriamo questo metodo:

Figura 4. Rilevamento dei Trend Utilizzando l'Indicatore ZigZag

Figura 4. Rilevamento dei Trend Utilizzando l'Indicatore ZigZag

Qui usiamo il grafico EURUSD D1 e Zigzag con i seguenti parametri: ExtDepth =, 5,ExtDeviation = 5, ExtBackstep = 3.

Nella figura in basso, puoi vedere l'indicatore di tendenza appositamente sviluppato - ZigZagTrendDetector.

Lo svantaggio principale di questo metodo di rilevamento dei trend - in tempo reale è impossibile da capire se l'extremum è già formato o meno. Nella cronologia gli extrema possono essere visti molto bene e si può capire dove si sono formati. Tuttavia, quando il prezzo cambia in tempo reale, l'extremum formato può improvvisamente scomparire o apparire di nuovo. Per vedere questo, basta guardare le linee di Zigzag tracciate in modalità test visivo di qualsiasi expert.

Questo inconveniente rende questo metodo inutile per l'uso pratico nel trading. Tuttavia, è molto utile per l'analisi tecnica dei dati storici per trovare modelli e valutare la qualità di vari sistemi di trading.

2.4. Rilevamento dei Trend Utilizzando l'Indicatore ADX

Il seguente modo preso in esame - è il rilevamento dei trend utilizzando l'indicatore ADX (Average Directional Movement Index). Questo indicatore viene utilizzato non solo per rilevare la direzione del trend, ma anche per valutarne la forza. Questa è una caratteristica molto importante dell'indicatore ADX. La forza del trend è determinata dalla linea ADX principale: se il valore è maggiore di 20 (il livello generalmente accettato, ma non necessariamente il migliore al momento), allora il trend è abbastanza forte.

La direzione del trend è determinata dalle linee +DI e -DI l'una verso l'altra. Questo indicatore utilizza lo smoothing di tutte e tre le linee con media esponenziale e,quindi, ha un ritardo di risposta al cambiamento di trend.

Formuliamo la regola del rilevamento dei trend:

  • Il trend sale se la linea +DI è superiore alla linea -DI.
  • Il trend scendese la linea +DI è inferiore alla linea -DI.

In questo caso, la linea di trend ADX non viene utilizzata per rilevare un trend. È necessario ridurre il numero di falsi segnali di questo indicatore. Se il trend è debole (ADX è inferiore a 20), è meglio attendere che diventi più forte e, solo allora, iniziare a fare trading con il trend.

Illustriamo questo metodo:

Figura 5. Identificazione di un Trend Utilizzando l'Indicatore ADX

Figura 5. Identificazione di un Trend Utilizzando l'Indicatore ADX

Qui usiamo il grafico EURUSD D1 e l'indicatore ADX con i seguenti parametri: PeriodADX = 21 (linea blu spessa - valore della forza del trend di ADX, linea verde sottile - valore di +DI, linea rossa sottile - valore di -DI).

Nella figura in basso, puoi vedere l'indicatore del trend appositamente sviluppato - ADXTrendDetector. Per confronto, nel grafico superiore (cremisi) dell'indicatore ADXTrendDetector il filtro di forza del trend è stato disabilitato (ADXTrendLevel = 0) e nel grafico inferiore (blu) - è stato abilitato (ADXTrendLevel = 20).

Si noti che parte del cosiddetto "bounce" nel rilevare la direzione del trend è stata eliminata quando abbiamo attivato il filtro di forza del trend. È auspicabile utilizzare questo filtro nel lavoro reale. Un ulteriore miglioramento della qualità degli indicatori può essere ottenuto mediante l'abile selezione di parametri esterni in base alla situazione attuale del mercato (piatto/range/trend) e in base alla natura del movimento della coppia di valute.

In generale, questo indicatore offre una buona opportunità per costruire sistemi di trading di tracciamento delle tendenze come filtro degli input.

2.5. Rilevamento dei Trend Utilizzando l'Indicatore NRTR

Il seguente metodo per rilevare un trend - utilizzando l'indicatore NRTR (Nick Rypock Trailing Reverse). Questo indicatore si trova sempre a distanza costante dall'extrema di prezzo raggiunto: prezzi più bassi su trend rialzisti e prezzi più alti su trend ribassisti. L'idea principale di questo indicatore: piccoli movimenti correttivi contro il trend principale dovrebbero essere ignorati e il movimento contro il trend principale, superando un certo livello, segnali sul cambiamento della direzione del trend.

Da questa affermazione, deriva la regola di rilevare la direzione del trend:

  • Il trend sale se la linea dell'indicatore corrisponde al trend rialzista sulla chiusura della barra.
  • Il trend scende - se la linea dell'indicatore corrisponde al trend al ribasso sulla chiusura della barra.

Per ridurre l'influenza delle false inversioni di tendenza sulle fluttuazioni dei prezzi, utilizzeremo i prezzi di chiusura per verificare la posizione della linea NRTR.

Illustriamo questo metodo:

Figura 6. Identificazione di un Trend Utilizzando l'Indicatore NRTR

Figura 6. Identificazione di un Trend Utilizzando l'Indicatore NRTR

Questi grandi punti blu corrispondono al trend al rialzo, mentre i grandi punti rossi - al trend al ribasso. Nella parte inferiore del grafico visualizzato, il nostro indicatore di tendenza NRTRTrendDetector, viene descritto di seguito.

2.6. Rilevamento dei Trend con Tre Candlestick Heiken Ashi

Un altro metodo comune per rilevare una trend - è usare i candlestick Heiken Ashi. I grafici Heiken Ashi sono i grafici a candele giapponesi modificati. I loro valori sono in parte mediati con la candela precedente.

Illustriamo questo metodo:

Figura 7. Rilevamento dei Trend per Colore dei Candlestick Heiken Ashi

Figura 7. Rilevamento dei Trend per Colore dei Candlestick Heiken Ash

Come puoi vedere, nemmeno questo metodo è esente da "falsi" segnali quando il prezzo fluttua in un corridoio laterale. Tuttavia, la cosa peggiore è che questo indicatore può ridisegnare non solo l'ultima barra, ma anche la penultima. In altre parole, il segnale su cui siamo entrati può essere invertito sulla barra successiva. Ciò è dovuto al fatto che quando viene determinato il colore dei candlestick, vengono analizzate due barre, quindi si consiglia di utilizzare questo metodo in combinazione con altri segnali di supporto.


3. Indicatori di Tendenza

Ora, creiamo indicatori di tendenza.

3.1. Indicatore di Tendenza Basato sulla Media Mobile

L'indicatore più semplice, come il modo più semplice per determinare un trend, in base alla media mobile. Analizziamo da quali parti esso è costituito. Il codice sorgente completo dell'indicatore si trova nel file MATrendDetector.MQ5 allegato all'articolo.

All'inizio del programma dell’indicatore, arriva la line che collega la libreria per calcolare le varie medie mobili. Questa libreria viene fornita con il Client Terminal ed è pronta per l'uso immediatamente dopo l'installazione. Ecco questa linea:

#include <MovingAverages.mqh>

useremo una funzione da essa che calcola una semplice media mobile:

double SimpleMA(const int position, const int period, const double &price[])

Qui, puoi definire i parametri di input:

  • position - indice iniziale nell’array price[] da cui inizia il calcolo.
  • period - periodo di media mobile, deve essere maggiore di zero.
  • price[] - array, che contiene la fascia di prezzo specificata durante il posizionamento dell'indicatore sul grafico. Di default, vengono utilizzati i prezzi di chiusura Close[] della barra.

La funzione restituisce il valore calcolato della media mobile.

La parte successiva del testo contiene le impostazioni iniziali per visualizzare l'indicatore sullo schermo:

//---------------------------------------------------------------------
#property indicator_separate_window
//---------------------------------------------------------------------
#property indicator_applied_price       PRICE_CLOSE
#property indicator_minimum             -1.4
#property indicator_maximum             +1.4
//---------------------------------------------------------------------
#property indicator_buffers             1
#property indicator_plots               1
//---------------------------------------------------------------------
#property indicator_type1               DRAW_HISTOGRAM
#property indicator_color1              Black
#property indicator_width1              2
//---------------------------------------------------------------------

I parametri disponibili sono i seguenti:

  • #property indicator_separate_window dice al terminale MetaTrader 5 di visualizzare il grafico degli indicatori in una finestra separata.
  • #property indicator_applied_price PRICE_CLOSE - tipo di prezzi utilizzati per default.
  • #property indicator_minimum -1,4 - valore minimo dell'asse verticale, visualizzato nella finestra dell'indicatore.
  • #property indicator_maximum +1,4 - valore massimo dell'asse verticale, visualizzato nella finestra dell'indicatore.

Gli ultimi due parametri consentono di impostare una scala fissa per visualizzare il grafico degli indicatori. Ciò è possibile perché conosciamo i valori minimi e massimi del nostro indicatore - da -1 a +1 inclusi. Ciò viene fatto affinché il grafico appaia esteticamente bello, per non sovrapporre i bordi della finestra e il titolo dell'indicatore sulla finestra.

  • #property indicator_buffers 1 - numero di buffer per il calcolo degli indicatori. Utilizziamo un solo buffer.
  • #property indicator_plots 1 - numero di serie grafiche nell’indicatore. Visualizziamo solo un grafico sullo schermo.
  • #property indicator_type1 DRAW_HISTOGRAM - visualizza il grafico dell'indicatore come istogramma.
  • #property indicator_color1 Black - colore predefinito del grafico dell'indicatore.
  • #property indicator_width1 2 - larghezza della linea del grafico dell'indicatore, in questo caso è la larghezza delle colonne dell'istogramma.

Successivamente, arriva la parte per inserire i parametri esterni dell'indicatore che possono essere modificati durante il posizionamento dell'indicatore sul grafico e, in seguito, quando sta lavorando:

input int   MAPeriod = 200;

C'è solo un parametro: il valore del periodo della media mobile.

La prossima parte essenziale delle funzioni dell’indicatore che elaborano vari eventi che si verificano quando l'indicatore lavora sul grafico.

La prima è la funzione di inizializzazione - OnInit(). Viene chiamata immediatamente dopo aver caricato l'indicatore. Nel nostro indicatore, appare nel seguente modo:

void OnInit()
{
  SetIndexBuffer( 0, TrendBuffer, INDICATOR_DATA );
  PlotIndexSetInteger( 0, PLOT_DRAW_BEGIN, MAPeriod );
}

La funzione SetIndexBuffer() associa l'array precedentemente dichiarato in cui memorizzeremo i valori del trend TrendBuffer[]con uno dei buffer degli indicatori. Abbiamo un solo buffer di indicatori e il suo indice è uguale a zero.

La funzione PlotIndexSetInteger() configura il numero di barre iniziali senza disegnarle nella finestra dell'indicatore.

Poiché è matematicamente impossibile calcolare una media mobile semplice sul numero di barre più piccole del suo periodo, specifichiamo il numero di barre, pari al periodo della media mobile.

Segue la funzione che elabora gli eventi sulla necessità di ricalcolare un indicatore - OnCalculate():

int OnCalculate(const int _rates_total, 
                const int _prev_calculated,
                const int _begin, 
                const double& _price[ ] )
{
  int  start, i;

//   If number of bars on the screen is less than averaging period, calculations can't be made:
  if( _rates_total < MAPeriod )
  {
    return( 0 );
  }

//  Determine the initial bar for indicator buffer calculation:
  if( _prev_calculated == 0 )
  {
    start = MAPeriod;
  }
  else
  {
    start = _prev_calculated - 1;
  }

//      Loop of calculating the indicator buffer values:
  for( i = start; i < _rates_total; i++ )
  {
    TrendBuffer[ i ] = TrendDetector( i, _price );
  }

  return( _rates_total );
}

Questa funzione viene chiamata per la prima volta dopo l'inizializzazione dell'indicatore e, successivamente, ogni volta che i dati sui prezzi cambiano. Ad esempio, quando arriva un nuovo tick sul simbolo per il quale viene calcolato l'indicatore. Analizziamo nel dettaglio.

Innanzitutto, controlla se c'è un numero sufficiente di barre su un grafico - se è inferiore al periodo della media mobile, allora non c'è nulla da calcolare e questa funzione termina con l'operatore di return. Se il numero di barre è sufficiente per i calcoli, determinare la barra iniziale, da cui verrà calcolato l'indicatore. Ciò avviene per non ricalcolare tutti i valori dell'indicatore su ogni tick del prezzo.

Qui usiamo il meccanismo fornito dal terminale. Ogni volta che si chiama una funzione dell’handler, controlla il valore dell'argomento della funzione _prev_calculated - ovvero il numero di barre elaborate in base alla chiamata precedente della funzione OnCalculate(). Se è zero, allora, ricalcola tutti i valori dell'indicatore. Altrimenti ricalcolare solo l'ultima barra con l'indice _prev_calculated - 1.

Il ciclo di calcolo dei valori del buffer dell'indicatore viene eseguito dall'operatore for - nel suo corpo chiamiamo la funzione di rilevamento dei trend TrendDetector per ogni valore del buffer dell'indicatore ricalcolato. Pertanto, sovrascrivendo solo questa funzione, possiamo implementare diversi algoritmi per il calcolo della direzione del trend. In questo caso, il resto delle parti dell'indicatore rimane infatti invariato (è possibile che i parametri esterni cambino).

Ora, consideriamo la funzione di rilevamento del trend stesso - TrendDetector.

int TrendDetector(int _shift, const double& _price[])
{
  double  current_ma;
  int     trend_direction = 0;

  current_ma = SimpleMA(_shift, MAPeriod, _price);

  if(_price[_shift] > current_ma)
  {
    trend_direction = 1;
  }
  else if(_price[_shift] < current_ma)
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

La funzione esegue le seguenti attività:

  • Calcola la media mobile semplice, partendo dalla barra, impostata dall'argomento _shift. Utilizza la funzione della libreria SimpleMA.
  • Confronta i valori di prezzo su questa barra con il valore della media mobile.
  • Se il valore del prezzo è superiore al valore della media mobile, restituisce 1, altrimenti se il valore del prezzo è inferiore al valore della media mobile, restituisce -1, altrimenti restituisce zero.

Se la funzione ha restituito zero, significa che non è stato possibile rilevare il trend.

Il risultato del lavoro degli indicatori può osservato nella Figura 2 e nella Figura 3.

3.2. Indicatore di Tendenza Basato sul "Fan" delle Medie Mobili

Ora vediamo, come sulla base di questo indicatore è possibile creare un indicatore un po’ più complesso che utilizza il "fan" delle medie mobili per rilevare un trend.

Il codice sorgente completo dell'indicatore si trova nel file FanTrendDetector.MQ5 allegato all'articolo.

Le differenze di questo indicatore dal precedente sono le seguenti:

  • I periodi di tre medie mobili sono impostati sui parametri esterni:
input int MA1Period = 200; // period value of senior moving average
input int MA2Period = 50;  // period value of medium moving average
input int MA3Period = 21;  // period value of junior moving average
  • Un'altra funzione TrendDetector:
int TrendDetector(int _shift, const double& _price[])
{
  double  current_ma1, current_ma2, current_ma3;
  int     trend_direction = 0;

  current_ma1 = SimpleMA(_shift, MA1Period, _price);
  current_ma2 = SimpleMA(_shift, MA2Period, _price);
  current_ma3 = SimpleMA(_shift, MA3Period, _price);

  if(current_ma3 > current_ma2 && current_ma2 > current_ma1)
  {
    trend_direction = 1;
  }
  else if(current_ma3 < current_ma2 && current_ma2 < current_ma1)
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

la funzione controlla se le medie mobili si trovano nell'ordine corretto, confrontandole tra loro utilizzando gli operatori if...else e il loro ordine. Se le medie sono disposte in ordine crescente, restituisce 1 - trend rialzista. Se le medie sono disposte in ordine decrescente, restituisce -1 - trend ribassista. Se entrambe le condizioni, verificate nel bloccoif sono false, restituisce zero (il trend non è stato rilevato). La funzione ha due argomenti di input: lo spostamento nel buffer della barra analizzata e il buffer stesso con una serie di prezzi.

Il resto delle parti dell'indicatore sono le stesse del precedente.

3.3. Indicatore di Tendenza Basato sull'Indicatore ZigZag

Consideriamo ora l'indicatore che utilizza le fratture di Zigzag per determinare l'extrema e rilevare la direzione del trend secondo Charles Dow. Il codice sorgente completo dell'indicatore si trova nel file ZigZagTrendDetector.MQ5 allegato all'articolo.

Le variabili esterne sono assegnate con i parametri dei valori dell'indicatore esterno ZigZag:

//---------------------------------------------------------------------
//  External parameters:
//---------------------------------------------------------------------
input int   ExtDepth = 5;
input int   ExtDeviation = 5;
input int   ExtBackstep = 3;
//---------------------------------------------------------------------

Una differenza importante di questo indicatore: il numero di buffer degli indicatori. Qui, oltre al buffer di visualizzazione utilizziamo altri due buffer di calcolo. Pertanto, abbiamo modificato la relativa impostazione nel codice dell'indicatore:

#property indicator_buffers  3

Aggiungere due buffer aggiuntivi. Immagazzineranno gli extrema, ottenuti dall'indicatore esterno ZigZag:

double ZigZagHighs[];  // zigzag's upper turnarounds
double ZigZagLows[];   // zigzag's lower turnarounds

È, inoltre, necessario apportare modifiche al gestore eventi di inizializzazione degli indicatori: impostare questi due buffer aggiuntivi come buffer di calcolo:

//  Buffers to store zigzag's turnarounds
SetIndexBuffer(1, ZigZagHighs, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, ZigZagLows, INDICATOR_CALCULATIONS);

Nel codice di calcolo della funzione OnCalculate, dobbiamo anche fornire la lettura delle fratture a zigzag nei nostri buffer. Ciò avviene nel seguente modo:

//  Copy upper and lower zigzag's turnarounds to buffers:
  CopyBuffer(indicator_handle, 1, 0, _rates_total - _prev_calculated, ZigZagHighs);
  CopyBuffer(indicator_handle, 2, 0, _rates_total - _prev_calculated, ZigZagLows);

//  Loop of calculating the indicator buffer values:
  for(i = start; i < _rates_total; i++)
  {
    TrendBuffer[i] = TrendDetector(i);
  }

La funzione TrendDetector è simile alla visualizzazione 1:

//---------------------------------------------------------------------
//  Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
double    ZigZagExtHigh[2];
double    ZigZagExtLow[2];
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int    trend_direction = 0;

//  Find last four zigzag's turnarounds:
  int    ext_high_count = 0;
  int    ext_low_count = 0;
  for(int i = _shift; i >= 0; i--)
  {
    if(ZigZagHighs[i] > 0.1)
    {
      if(ext_high_count < 2)
      {
        ZigZagExtHigh[ext_high_count] = ZigZagHighs[i];
        ext_high_count++;
      }
    }
    else if(ZigZagLows[i] > 0.1)
    {
      if(ext_low_count < 2)
      {
        ZigZagExtLow[ext_low_count] = ZigZagLows[i];
        ext_low_count++;
      }
    }

//  If two pairs of extrema are found, break the loop:
    if(ext_low_count == 2 && ext_high_count == 2)
    {
      break;
    }
  }

//  If required number of extrema is not found, the trend can't be determined:
  if(ext_low_count != 2 || ext_high_count != 2)
  {
    return(trend_direction);
  }

//  Check Dow's condition fulfillment:
  if(ZigZagExtHigh[0] > ZigZagExtHigh[1] && ZigZagExtLow[0] > ZigZagExtLow[1])
  {
    trend_direction = 1;
  }
  else if(ZigZagExtHigh[0] < ZigZagExtHigh[1] && ZigZagExtLow[0] < ZigZagExtLow[1])
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Qui cerchiamo gli extrema degli ultimi quattro zigzag. Si noti che la ricerca risale alla cronologia. Ecco perché, l'indice nel ciclo for diminuisce a ogni iterazione di ricerca fino a zero. Se gli extrema vengono trovati, vengono confrontati tra loro per coerenza della definizione del trend secondo Dow. Ci sono due possibili posizioni di extrema - per il trend rialzista e per il trend ribassista. Queste varianti sono controllate dagli operatori if...else.

3.4. Indicatore di Tendenza Basato sull'Indicatore ADX

Si consideri l'indicatore di tendenza ADXTrendDetector che utilizza l'indicatore ADX. Il codice sorgente completo dell'indicatore si trova nel file ADXTrendDetector.MQ5 allegato all'articolo. I parametri esterni sono assegnati con valori dell’indicatore esterno ADX:

//---------------------------------------------------------------------
//      External parameters
//---------------------------------------------------------------------
input int  PeriodADX     = 14;
input int  ADXTrendLevel = 20;

La funzione TrendDetector è simile alla visualizzazione 1:

//---------------------------------------------------------------------
//  Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int     trend_direction = 0;
  double  ADXBuffer[ 1 ];
  double  PlusDIBuffer[ 1 ];
  double  MinusDIBuffer[ 1 ];

//  Copy ADX indicator values to buffers:
  CopyBuffer(indicator_handle, 0, _shift, 1, ADXBuffer);
  CopyBuffer(indicator_handle, 1, _shift, 1, PlusDIBuffer);
  CopyBuffer(indicator_handle, 2, _shift, 1, MinusDIBuffer);

//  If ADX value is considered (trend strength):
  if(ADXTrendLevel > 0)
  {
    if(ADXBuffer[0] < ADXTrendLevel)
    {
      return(trend_direction);
    }
  }

//  Check +DI and -DI positions relative to each other:
  if(PlusDIBuffer[0] > MinusDIBuffer[0])
  {
    trend_direction = 1;
  }
  else if(PlusDIBuffer[0] < MinusDIBuffer[0])
  {
    trend_direction = -1;
  }

  return( trend_direction );
}

Utilizzando CopyBuffer() ottenere i valori necessari dei buffer degli indicatori dall'indicatore esterno ADX per il numero di barre dato dall'argomento _shift. Dunque, analizza le posizioni delle linee +DI e -DI l'una rispetto all'altra. Se necessario, considera la forza del trend: se è inferiore a quella definita, allora il trend non viene rilevato.

3.5. Indicatore di Tendenza Basato sull'IndicatoreNTRT

La struttura dell'indicatore di tendenza NRTRTrendDetector, basato su NRTR, è simile al precedente. Il codice sorgente completo dell'indicatore si trova nel file NRTRTrendDetector.MQ5 allegato all'articolo.

La prima differenza - nel blocco di parametri esterni:

//---------------------------------------------------------------------
//      External parameters:
//---------------------------------------------------------------------
input int     ATRPeriod =  40;    // ATR period, in bars
input double  Koeff     = 2.0;    // Coefficient of ATR value change   
//---------------------------------------------------------------------

La seconda differenza - nella funzione TrendDetector di rilevare la direzione del trend:

//---------------------------------------------------------------------
//      Determine the current trend direction:
//---------------------------------------------------------------------
//  Returns:
//    -1 - Down trend
//    +1 - Up trend
//     0 - trend is not defined
//---------------------------------------------------------------------
int TrendDetector(int _shift)
{
  int     trend_direction = 0;
  double  Support[1];
  double  Resistance[1];

//      Copy NRTR indicator values to buffers::
  CopyBuffer(indicator_handle, 0, _shift, 1, Support);
  CopyBuffer(indicator_handle, 1, _shift, 1, Resistance);

//  Check values of indicator lines:
  if(Support[0] > 0.0 && Resistance[0] == 0.0)
  {
    trend_direction = 1;
  }
  else if(Resistance[0] > 0.0 && Support[0] == 0.0)
  {
    trend_direction = -1;
  }

  return( trend_direction );
}

Qui leggiamo i valori da due buffer dell'indicatore esterno NRTR con indici 0 e 1. I valori nel buffer di Supporto sono diversi da zero quando c'è un trend al rialzo e i valori nel buffer di Resistenza sono diversi da zero quando c'è il trend al ribasso.

3.6. Indicatore di Tendenza Basato sui Candlestick Heiken Ashi

Consideriamo ora l'indicatore di tendenza che utilizza i candlestick Heiken Ashi.

In questo caso, non chiameremo l'indicatore esterno, ma calcoleremo da soli le candele . Ciò migliorerà le prestazioni dell'indicatore e libererà la CPU per attività più importanti. Il codice sorgente completo dell'indicatore si trova nel file HeikenAshiTrendDetector.MQ5 allegato all'articolo.

Poiché l'indicatore Heiken Ashi non presuppone l'impostazione di parametri esterni, possiamo rimuovere il blocco con gli operatori di input. Importanti cambiamenti ci attendono nel gestore dell'evento di ricalcolo degli indicatori. Qui useremo una variante alternativa del gestore, che fornisce l'accesso a tutti gli array di prezzo del grafico corrente.

La funzione OnCalculate() ora appare così:

int OnCalculate(const int _rates_total, 
                const int _prev_calculated,
              const datetime& Time[],
              const double& Open[],
              const double& High[],
              const double& Low[],
              const double& Close[],
              const long& TickVolume[],
              const long& Volume[], 
              const int& Spread[])
{
  int     start, i;
  double  open, close, ha_open, ha_close;

//  Determine the initial bar for indicator buffer calculation:
  if(_prev_calculated == 0)
  {
    open = Open[0];
    close = Close[0];
    start = 1;
  }
  else
  {
    start = _prev_calculated - 1;
  }

//  Loop of calculating the indicator buffer values:
  for(i = start; i < _rates_total; i++)
  {
//  Heiken Ashi candlestick open price:
    ha_open = (open + close) / 2.0;

//  Heiken Ashi candlestick close price:
    ha_close = (Open[i] + High[i] + Low[i] + Close[i]) / 4.0;

    TrendBuffer[i] = TrendDetector(ha_open, ha_close);

    open = ha_open;
    close = ha_close;
  }

  return(_rates_total);
}

per quanto riguarda la determinazione del colore delle candele Heiken Ashi, abbiamo bisogno solo di due prezzi: l'apertura e la chiusura, quindi contare solo questi. 

Dopo aver rilevato la direzione del trend attraverso la chiamata alla funzione TrendDetector, salvare i valori di prezzo correnti delle candele Heiken Ashi in variabili intermedie open e close. La funzione TrendDetector sembra molto semplice. Puoi inserirlo in OnCalculate, ma per maggior versatilità, in caso di ulteriore sviluppo e complessità dell'algoritmo, lasciamo questa funzione. Ecco questa funzione:

int TrendDetector(double _open, double _close)
{
  int    trend_direction = 0;

  if(_close > _open)         // if candlestick is growing, then it is the up trend
  {
    trend_direction = 1;
  }
  else if(_close < _open)     // if candlestick is falling, then it is the down trend
  {
    trend_direction = -1;
  }

  return(trend_direction);
}

Gli argomenti della funzione sono due prezzi per la candela Heiken Ashi: di apertura e di chiusura, con cui viene determinata la sua direzione.


4. Esempio di Utilizzo dell'Indicatore di Rilevamento dei Trend nell’Expert

Creiamo un Expert Advisor che utilizza diversi indicatori. Sarà interessante confrontare i risultati degli expert che utilizzano diversi modi di rilevamento dei trend. Innanzitutto, controlla i risultati con i parametri predefiniti, quindi prova a regolarli per trovare i migliori.

In questo caso, lo scopo della creazione degli Expert Advisor- è quello di confrontare i metodi di rilevamento dei trend per accuratezza e velocità. Pertanto, formuliamo i principi generali della creazione di tutti gli Expert Advisor:

  • Laposizione Buy si apre quando la tendenza cambia dal basso verso l'alto o dall'indefinito al rialzo.
  • La posizione Sell si apre quando la tendenza cambia dall'alto al ribasso o dall'indefinito al ribasso.
  • La posizione si chiude quando il trend cambia direzione in modo inverso o indefinito.
  • L’Expert Advisor deve aprire/chiudere una posizione quando si apre una nuova barra (quando c'è un segnale corrispondente).

Tutti gli indicatori di tendenza che abbiamo creato contengono un buffer di indicatori con indice zero che memorizza i dati richiesti sulla direzione del trend. Lo useremo negli Expert Advisor per ottenere un segnale per aprire/chiudere la posizione.

Poiché abbiamo bisogno di funzioni di trading, abbiamo incluso la libreria corrispondente che viene installata insieme a MetaTrader 5. Questa libreria contiene la classe CTrade e diversi metodi di lavoro con posizioni e ordini. Ciò semplifica il lavoro di routine con le funzioni di trading. La biblioteca è inclusa nella seguente riga:

#include <Trade\Trade.mqh>

useremo due metodi da esso: apertura della posizione e chiusura. Il primo metodo consente di aprire una posizione di una determinata direzione e volume:

PositionOpen(const string symbol, 
             ENUM_ORDER_TYPE order_type,
             double volume, double price,
             double sl, double tp, const string comment )

Gli argomenti di input sono i seguenti:

  • symbol- name dello strumento per il trading, ad esempio "EURUSD".
  • order_type - direzione di apertura della posizione, short o long.
  • volume - volume della posizione aperta in lotti, ad esempio 0,10.
  • price - prezzo di apertura.
  • sl - prezzo dello Stop Loss.
  • tp - prezzo del Take Profit.
  • comment - commento, mostrato quando la posizione viene visualizzata nel terminale di trading.

Il secondo metodo consente di chiudere una posizione:

PositionClose( const string symbol, ulong deviation )

Gli argomenti di input sono i seguenti:

  •  symbol- name dello strumento per il trading, ad esempio "EURUSD".
  •  deviation - deviazione massima consentita dal prezzo corrente (in punti) quando si chiude una posizione.

Consideriamo nel dettaglio la struttura dell’ Expert Advisor che utilizza l'indicatore MATrendDetector. Il codice sorgente completo dell’Expert Advisor si trova nel file MATrendExpert.MQ5 allegato all'articolo. Il primo blocco principale dell'expert - è il blocco di impostazione dei parametri esterni.

input double Lots = 0.1;
input int    MAPeriod = 200;

Il parametro Lots dell’Expert Advisor - è la dimensione del lotto utilizzato quando la posizione viene aperta. Per ottenere risultati comparativi di diversi metodi di rilevamento dei trend, utilizziamo il lotto permanente senza gestione del denaro. Tutti gli altri parametri esterni sono utilizzati dagli indicatori di tendenza di cui si è parlato in precedenza. L'elenco e lo scopo sono esattamente gli stessi dell'indicatore corrispondente.

Il secondo blocco importante dell’Expert Advisor - gestore di eventi dell'inizializzazione dell’Expert Advisor.

//---------------------------------------------------------------------
//      Initialization event handler:
//---------------------------------------------------------------------
int OnInit()
{
//  Create external indicator handle for future reference to it:
  ResetLastError();
  indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Examples\\MATrendDetector", MAPeriod);

// If initialization was unsuccessful, return nonzero code:
  if(indicator_handle == INVALID_HANDLE)
  {
    Print("MATrendDetector initialization error, Code = ", GetLastError());
    return(-1);
  }
  return(0);
}

Qui creare un handle per fare riferimento all'indicatore di tendenza e, se tale creazione ha avuto esito positivo, restituisce il codice zero. Se non è stato possibile creare l'handle dell'indicatore (ad esempio, l'indicatore non è stato compilato in formato EX5), stampiamo il messaggio su questo e restituiamo un codice diverso da zero. In questo caso, l’Expert Advisor interrompe il suo ulteriore lavoro e viene scaricato dal terminale con il messaggio corrispondente nel Journal.

Il prossimo blocco dell’Expert Advisor - gestore dell'evento di reinizializzazione dell’Expert Advisor.

//---------------------------------------------------------------------
//      Indicator deinitialization event handler:
//---------------------------------------------------------------------
void OnDeinit(const int _reason)
{
//  Delete indicator handle:
  if(indicator_handle != INVALID_HANDLE)
  {
    IndicatorRelease(indicator_handle);
  }
}

Qui l'handle dell'indicatore viene eliminato e la memoria allocata viene liberata.

Non è necessario eseguire altre azioni per reinizializzare l’Expert Advisor.

Poi, segue il blocco principale dell’Expert Advisor - gestore dell'evento sul nuovo teak dal simbolo corrente.

//---------------------------------------------------------------------
//  Handler of event about new tick by the current symbol:
//---------------------------------------------------------------------
int    current_signal = 0;
int    prev_signal = 0;
bool   is_first_signal = true;
//---------------------------------------------------------------------
void OnTick()
{
//  Wait for beginning of a new bar:
  if(CheckNewBar() != 1)
  {
    return;
  }

//  Get signal to open/close position:
  current_signal = GetSignal();
  if(is_first_signal == true)
  {
    prev_signal = current_signal;
    is_first_signal = false;
  }

//  Select position by current symbol:
  if(PositionSelect(Symbol()) == true)
  {
//  Check if we need to close a reverse position:
    if(CheckPositionClose(current_signal) == 1)
    {
      return;
    }
  }

//  Check if there is the BUY signal:
  if(CheckBuySignal(current_signal, prev_signal) == 1)
  {
    CTrade  trade;
    trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, Lots, SymbolInfoDouble(Symbol(), SYMBOL_ASK ), 0, 0);
  }

//  Check if there is the SELL signal:
  if(CheckSellSignal(current_signal, prev_signal) == 1)
  {
    CTrade  trade;
    trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, Lots, SymbolInfoDouble(Symbol(), SYMBOL_BID ), 0, 0);
  }

//  Save current signal:
  prev_signal = current_signal;
}

Consideriamo le funzioni ausiliarie, che vengono utilizzate dall’Expert Advisor.

Prima di tutto, il nostro Expert Advisor deve controllare il segnale per aprire un'altra nuova barra sul grafico. Per questo, viene utilizzata la funzione CheckNewBar:

//---------------------------------------------------------------------
//  Returns flag of a new bar:
//---------------------------------------------------------------------
//  - if it returns 1, there is a new bar
//---------------------------------------------------------------------
int CheckNewBar()
{
  MqlRates  current_rates[1];

  ResetLastError();
  if(CopyRates(Symbol(), Period(), 0, 1, current_rates)!= 1)
  {
    Print("CopyRates copy error, Code = ", GetLastError());
    return(0);
  }

  if(current_rates[0].tick_volume>1)
  {
    return(0);
  }

  return(1);
}

La presenza di una nuova barra è determinata dal valore del volume del tick. Quando si apre una nuova barra, il volume per esso è inizialmente uguale a zero (poiché non c'erano quotazioni). Con il nuovo tick in arrivo la dimensione diventa uguale a 1.

In questa funzione creeremo l’array current_rates[] di strutture MqlRates, costituita da un elemento, copiare le informazioni correnti su prezzi e volumi al suo contenuto, quindi controllare il valore del volume del tick. 

Nel nostro gestore eventi sul nuovo tick per il simbolo corrente, useremo questa funzione nel modo seguente:

//  Wait for beginning of a new bar:
if(CheckNewBar()!= 1)
{
  return;
}

Quindi, si apre una nuova barra e puoi ottenere un segnale sulla direzione del trend corrente. Ciò avviene nel seguente modo:

//  Get signal to open/close position:
  current_signal = GetSignal();
  if(is_first_signal == true)
  {
    prev_signal = current_signal;
    is_first_signal = false;
  }

Poiché dobbiamo tenere traccia dei cambiamenti nella tendenza, è necessario ricordare il valore della tendenza sulla barra precedente. Nella porzione di codice sopra, per questo usiamo la variabile prev_signal. Inoltre, dovresti usare il flag, segnalando che questo è il primo segnale (non ce n'è ancora uno precedente). Questa è la variabile is_first_signal. Se il flag ha valore true, inizializziamo la variabile prev_signal con valore iniziale.

Qui usiamo la funzione GetSignal che restituisce la direzione del trend corrente, ottenuta dal nostro indicatore. Appare nel seguente modo:  

//---------------------------------------------------------------------
//      Get signal to open/close position:
//---------------------------------------------------------------------
int GetSignal()
{
  double    trend_direction[1];

//  Get signal from trend indicator:
  ResetLastError();
  if(CopyBuffer(indicator_handle, 0, 0, 1, trend_direction) != 1)
  {
    Print("CopyBuffer copy error, Code = ", GetLastError());
    return(0);
  }

  return((int)trend_direction[0]);
}

I dati dell'indicatore di tendenza vengono copiati dal buffer zero al nostro array trend_direction, costituito da un elemento. E il valore dell'elemento array viene restituito dalla funzione. Anche il doppio tipo viene proiettato al tipo int per evitare l'avviso del compilatore.

Prima di aprire una nuova posizione, dovresti verificare se è necessario chiudere la posizione opposta, aperta in precedenza. Dovresti anche controllare se esiste già una posizione aperta nella stessa direzione. Tutto questo viene fatto dalla seguente porzione di codice:

//  Select position by current symbol:
  if(PositionSelect(Symbol()) == true)
  {
//  Check if we need to close a reverse position:
    if(CheckPositionClose(current_signal) == 1)
    {
      return;
    }
  }

per ottenere l'accesso alla posizione, prima esso deve essere selezionato - questo viene fatto usando la funzione PositionSelect() per il simbolo corrente. Se la funzione restituisce true, allora la posizione esiste ed è stata selezionata correttamente, in modo da poterla gestire.

Per chiudere la posizione opposta viene utilizzata la funzione CheckPositionClose:

//---------------------------------------------------------------------
//  Check if we need to close position:
//---------------------------------------------------------------------
//  Returns:
//    0 - no open position
//    1 - position already opened in signal's direction
//---------------------------------------------------------------------
int CheckPositionClose(int _signal)
{
  long    position_type = PositionGetInteger(POSITION_TYPE);

  if(_signal == 1)
  {
//  If there is the BUY position already opened, then return:
    if(position_type == (long)POSITION_TYPE_BUY)
    {
      return(1);
    }
  }

  if(_signal==-1)
  {
//  If there is the SELL position already opened, then return:
    if( position_type == ( long )POSITION_TYPE_SELL )
    {
      return(1);
    }
  }

//  Close position:
  CTrade  trade;
  trade.PositionClose(Symbol(), 10);

  return(0);
}

Innanzitutto, controlla se la posizione è aperta nella direzione del trend. In tal caso, la funzione restituisce 1 e la posizione corrente non viene chiusa. Se la posizione è aperta nella direzione di trend opposta, è necessario chiuderla. Questo viene fatto dal metodo PositionClose descritto sopra. Poiché la posizione aperta non è più, restituisce zero.

Una volta effettuati tutti i controlli e le azioni necessarie per le posizioni esistenti, è necessario verificare la presenza di un nuovo segnale. Ciò viene fatto dalla seguente porzione di codice:

//  Check if there is the BUY signal:
if(CheckBuySignal(current_signal, prev_signal)==1)
{
  CTrade  trade;
  trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, Lots, SymbolInfoDouble(Symbol(), SYMBOL_ASK), 0, 0);
}

Se c'è il segnale Buy, apri la posizione long con un dato volume dato dal prezzo corrente SYMBOL_ASK . Poiché tutte le posizioni sono chiuse dal segnale opposto, non vengono utilizzati Take Profit e Stop Loss. L'Expert Advisor è "sempre sul mercato". 

Nel trading reale si consiglia di utilizzare uno Stop Loss protettivo in caso di circostanze impreviste, come la perdita di connessione con il server DC e altre cause di forza maggiore.

Per i segnali Sell, è tutto simile:

//  Check if there is the SELL signal:
if(CheckSellSignal(current_signal, prev_signal) == 1)
{
  CTrade  trade;
  trade.PositionOpen(Symbol(), ORDER_TYPE_SELL, Lots, SymbolInfoDouble(Symbol(), SYMBOL_BID), 0, 0);
}

L'unica differenza è nel prezzo di vendita - SYMBOL_BID.

La presenza di un segnale è controllata dalla funzione CheckBuySignal - per acquistare e dalla funzione CheckSellSignal - per vendere. Queste funzioni sono molto semplici e chiare:

//---------------------------------------------------------------------
//  Check if signal has changed to BUY:
//---------------------------------------------------------------------
//  Returns:
//    0 - no signal
//    1 - there is the BUY signal
//---------------------------------------------------------------------
int CheckBuySignal(int _curr_signal, int _prev_signal)
{
//  Check if signal has changed to BUY:
  if((_curr_signal==1 && _prev_signal==0) || (_curr_signal==1 && _prev_signal==-1))
  {
    return(1);
  }

  return(0);
}

//---------------------------------------------------------------------
//  Check if there is the SELL signal:
//---------------------------------------------------------------------
//  Returns:
//    0 - no signal
//    1 - there is the SELL signal
//---------------------------------------------------------------------
int CheckSellSignal(int _curr_signal, int _prev_signal)
{
//  Check if signal has changed to SELL:
  if((_curr_signal==-1 && _prev_signal==0) || (_curr_signal==-1 && _prev_signal==1))
  {
    return(1);
  }

  return(0);
}

Qui controlliamo se il trend è cambiato nella direzione opposta o se è apparsa la direzione del trend. Se una di queste condizioni viene soddisfatta, la funzione restituisce la presenza del segnale.

In generale, tale schema di Expert Advisor fornisce una struttura abbastanza universale che può essere facilmente aggiornata ed ampliata per adattarsi ad algoritmi più complessi.

Gli altri Expert Advisor sono costruiti esattamente allo stesso modo. Esistono differenze significative solo nel blocco dei parametri esterni: devono corrispondere all'indicatore di tendenza utilizzato e devono essere passati come argomenti durante la creazione dell’handle dell'indicatore.

Consideriamo i risultati del nostro primo Expert Advisor sui dati storici. Utilizzeremo la cronologia EURUSD nel range dal 01.04.2004 al 06.08.2010 sulle barre giornaliere. Dopo aver eseguito l’Expert Advisor nello Strategy Tester con i parametri predefiniti, otteniamo i seguenti risultati:

Figura 8. Risultati del Test dell'Expert Advisor Utilizzando l'Indicatore MATrendDetector

Figura 8. Risultati del Test dell' Expert Advisor Utilizzando l'Indicatore MATrendDetector

Rapporto dello Strategy Test
MetaQuotes-Demo (Build 302)

Impostazioni
Expert: MATrendExpert
Simbolo: EURUSD
Periodo: Giornaliero 01.04.2004 - 06.08.2010)
Input: Lots=0,100000

MAPeriod=200
Broker: MetaQuotes Software Corp.
Valuta: dollaro USA
Deposito Iniziale: 10.000,00

Risultati
Barre: 1.649 Tick: 8.462.551
Utile Netto Totale: 3.624,59 Profitto Lordo: 7.029,16 Perdita Lorda: -3.404,57
Fattore di Profitto: 2,06 Payoff previsto: 92,94
Fattore di Recupero: 1,21 Indice di Sharpe: 0,14

Drawdown del Saldo:
Drawdown del Saldo Assoluto: 2.822,83 Drawdown Massimo del Saldo: 2.822.83 (28,23%) Saldo Drawdown Relativo: 28,23% (2.822,83)
Drawdown del Capitale:
Drawdown Assoluto del Capitale: 2.903,68 Drawdown Massimo del Capitale: 2.989.93 (29,64%) Drawdown Relativo del Capitale: 29,64% (2.989,93)

Totale Operazioni: 39 Short Trade (vinti%) 20 (20,00%) Long Trade (vinti%) 19 (15,79%)
Totale Posizioni: 78 Operazioni di profitto (% del totale): 7 (17,95%) Operazioni di perdita (% del totale): 32 (82,05%)

Il più grande profitto di trading: 3.184,14 Maggior numero di perdite di trading (% del totale): -226,65

Trading con profitto medio: 1.004,17 Perdita media di trading (% del totale): -106,39

Vincite massime consecutive ($): 4 (5.892,18) Massime perdite consecutive($): 27 (-2.822,83)

Profitto massimo consecutivo (conteggio): 5.892,18 (4) Massime perdite consecutive (conteggio): -2.822,83 (27)

Media vittorie consecutive: 2 Massime perdite consecutive 8


In generale sembra buono, tranne la sezione dall'inizio dei test fino al 22.09.2004. Non vi è alcuna garanzia che questa sezione non verrà ripetuta in futuro. Se guardi sul grafico di questo periodo, puoi vedere che c'era un movimento laterale predominante in un range limitato. In queste condizioni, il nostro semplice expert di trend non era così bravo. Ecco l'immagine di questo periodo con le offerte posizionate su di esso:

Figura 9. Sezione con Movimento Laterale

Figura 9. Sezione con Movimento Laterale

Inoltre c'è la media mobile SMA200 sul grafico.

Ora vediamo cosa mostrerà l’Expert Advisor più "avanzato" utilizzando l'indicatore con più medie mobili - sullo stesso intervallo e con parametri predefiniti:

Figura 10. Risultati del Test dell'Expert Advisor Utilizzando l'Indicatore FanTrendDetector

Figura 10. Risultati del Test dell'Expert Advisor Utilizzando l'Indicatore FanTrendDetector

Rapporto dello Strategy Test
MetaQuotes-Demo (Build 302)

Impostazioni
Expert: FanTrendExpert
Simbolo: EURUSD
Periodo: Giornaliero 01.04.2004 - 06.08.2010)
Input: Lots=0,100000

MA1Period=200

MA2Period=50

MA3Period=21
Broker: MetaQuotes Software Corp.
Valuta: dollaro USA
Deposito Iniziale: 10.000,00

Risultati
Barre: 1.649 Tick: 8.462.551
Utile Netto Totale: 2.839,63 Profitto Lordo: 5.242,93 Perdita Lorda: -2.403,30
Fattore di Profitto: 2,18 Payoff previsto: 149,45
Fattore di Recupero: 1,06 Indice di Sharpe: 0,32

Drawdown del Saldo:
Drawdown del Saldo Assoluto: 105,20 Drawdown Massimo del Saldo: 1.473,65 (11,73%) Saldo Drawdown Relativo: 11,73% (1.473,65)
Drawdown del Capitale:
Drawdown Assoluto del Capitale: 207,05 Drawdown Massimo del Capitale: 2.671,98 (19,78%) Drawdown Relativo del Capitale: 19,78% (2.671,98)

Totale Operazioni: 19 Short Trade (vinti%) 8 (50,00%) Long Trade (vinti%) 11 (63,64%)
Totale Posizioni: 38 Operazioni di profitto (% del totale): 11 (57,89%) Operazioni di perdita (% del totale): 8 (42,11%)

Il più grande profitto di trading: 1.128,30 Maggior numero di perdite di trading (% del totale): -830,20

Trading con profitto medio: 476,63 Perdita media di trading (% del totale): -300,41

Vincite massime consecutive ($): 2 (1.747,78) Massime perdite consecutive($): 2 (-105,20)

Profitto massimo consecutivo (conteggio): 1.747,78 (2) Massime perdite consecutive (conteggio): -830,20 (1)

Media vittorie consecutive: 2 Massime perdite consecutive 1

Molto meglio! Se guardi la nostra sezione "problemi", a cui l'expert precedente ha rinunciato prima, l'immagine sarà la seguente:

Figura 11.Risultati di FanTrendExpert su sezioni con Movimento Laterale

Figura 11. Risultati di FanTrendExpert sulla Sezioni con Movimento Laterale

Confrontalo con la Figura 9 - è ovvio che il numero di falsi allarmi di cambiamento di tendenza è stato ridotto. Ma il numero di posizioni è stato ridotto della metà, il che è abbastanza logico. Quando si analizza la curva di equilibrio/equità di entrambi gli Expert Advisors, puoi vedere che molte posizioni sono state chiuse meno di quelle ottimali per ottenere il massimo profitto. Pertanto, il prossimo aggiornamento dell’Expert Advisor - è il miglioramento dell'algoritmo di chiusura della posizione. Tuttavia, ciò va oltre lo scopo di questo articolo. I lettori possono farlo da soli.


5. Risultati dei Test degli Expert Advisor

Mettiamo alla prova tutti i nostri expert. Di seguito, vengono presentati i risultati su tutti i range storici disponibili dal 1993 al 2010 sulla coppia EURUSD e timeframe D1.

Figura 12. Testare MATrendExpert

Figura 12. Testare MATrendExpert

Figura 13.Testare FanTrendExpert

Figura 13. Testare FanTrendExpert

Figura 14. Testare ADXTrendExpert (ADXTrendLevel = 0)

Figura 14. Testare ADXTrendExpert (ADXTrendLevel = 0)

Figura 15. Testare ADXTrendExpert (ADXTrendLevel= 20)

Figura 15. Testare ADXTrendExpert (ADXTrendLevel = 20)

Figura 16. Testare NRTRTrendExpert

Figura 16. Testare NRTRTrendExpert

Figura 17. Testare Heiken Ashi

Figura 17. Testare Heiken Ashi

Consideriamo i risultati dei test.

Come leader ci sono due Expert Advisor più comuni: su una media mobile e il "fan" delle medie mobili. In effetti, questi expert sono i più vicini alla regola di seguire il trend (e, quindi, il prezzo), semplicemente utilizzando una serie di prezzi adattati per l'ultimo periodo di tempo. Poiché utilizziamo una media mobile piuttosto "pesante" con un periodo di 200, l'impatto della volatilità del mercato sembra diminuire.

Il basso numero di posizioni da parte di questi Expert Advisor non è uno svantaggio, poiché il tempo di mantenimento della posizione può durare fino a diversi mesi, seguendo la tendenza a 200 giorni. È interessante notare come MATrendExpert alterna aree di tendenza, dove l'equilibrio è in crescita, piatto (nel contesto dell'expert), dove il denaro viene perso.

Anche il metodo di rilevamento delle tendenze sull'indicatore ADX ha dato buoni risultati. Lì il PeriodADX è stato cambiato leggermente al valore di 17 che dà risultati più uniformi nel corso della storia. L'effetto filtro in base alla forza del trend non è significativo. Potrebbe essere necessario regolare il parametro ADXTrendLevel o addirittura impostarlo dinamicamente a seconda dell'attuale volatilità del mercato. Ci sono diversi periodi di drawdown e, quindi, sono necessarie misure aggiuntive per equalizzare la curva di bilanciamento.

L'indicatore NRTR ha mostrato una redditività praticamente pari a zero utilizzando le impostazioni predefinite, sia sull'intera gamma di test che su un lungo range scelto a caso. In una certa misura, questo è un segno di stabilità di questo metodo di rilevamento dei trend. Forse, la regolazione dei parametri renderà redditizio questo Expert Advisor, ovvero è necessaria l'ottimizzazione.

L’Expert Advisor basato su Heiken Ashi, ovviamente, non era redditizio. Anche se sembra bello sulla storia, probabilmente a causa del ridisegno in tempo reale i risultati del test sono tutt'altro che ideali. Forse, si otterranno risultati migliori utilizzando una versione adattata di questo indicatore - Smoothed Heiken Ashi che non è così incline a ridisegnare.

Sicuramente, tutti gli Expert Advisor trarranno vantaggio dal sistema di conduzione di una posizione aperta con dinamico tirando lo stop level e con la creazione di un livello target. Inoltre, sarebbe bello avere un sistema di gestione del capitale che consente di ridurre al minimo il drawdown e potrebbe essere quello di aumentare il profitto sul lungo intervallo.


Conclusione

In tal modo, non è così difficile scrivere un codice che rilevi un trend. La cosa principale qui è lavorare e un'idea sensata, sfruttando alcune leggi del mercato. E più fondamentali saranno queste leggi, più sarai sicuro di te nel sistema di trading basato su queste leggi - non si romperà dopo un breve periodo di lavoro.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/136

File allegati |
experts.zip (9.35 KB)
indicators.zip (7.82 KB)
Valutazione dei Sistemi di Trading - l'Efficacia dell'Entrata, dell'Uscita e dei Trade in Generale Valutazione dei Sistemi di Trading - l'Efficacia dell'Entrata, dell'Uscita e dei Trade in Generale
Ci sono molte misure che consentono di determinare l'efficacia e la redditività di un sistema di trading. Tuttavia, i trader sono sempre pronti a sottoporre qualsiasi sistema a un nuovo crash test. L'articolo spiega come le statistiche basate su misure di efficacia possono essere utilizzate per la piattaforma MetaTrader 5. Esso include la classe per la trasformazione dell'interpretazione delle statistiche dalle posizioni a quella che non contraddice la descrizione fornita nel libro "Statistika dlya traderov" ("Statistiche per i Trader") di S.V. Bulashev. Include anche un esempio di funzione personalizzata per l'ottimizzazione.
Creazione di Indicatori Multicolor in MQL5 Creazione di Indicatori Multicolor in MQL5
In questo articolo, considereremo come creare indicatori multicolor o convertire quelli esistenti in multicolor. MQL5 permette di rappresentare le informazioni nella forma più conveniente. Ora, non è più necessario guardare una dozzina di grafici con indicatori ed eseguire analisi dell’RSI o dei livelli stocastici, è meglio semplicemente colorare le candele con colori diversi a seconda dei valori degli indicatori.
Expert Advisor basato sulle "New Trading Dimensions" di Bill Williams Expert Advisor basato sulle "New Trading Dimensions" di Bill Williams
In questo articolo, parlerò dello sviluppo dell’Expert Advisor basato sul libro "New Trading Dimensions: Come Trarre Profitto dal Caos in Azioni, Bond e Materie Prime" di Bill Williams. La strategia stessa è ben nota ed il suo utilizzo è ancora piuttosto controverso tra i trader. L'articolo considera i segnali di trading del sistema, le specifiche della sua implementazione e i risultati dei test sui dati storici.
Come creare il Tuo Trailing Stop Come creare il Tuo Trailing Stop
La regola di base del trader: lascia che il profitto cresca, riduci le perdite! Questo articolo considera una delle tecniche di base che consentono di seguire questa regola: spostare lo stop level protettivo (livello di Stop Loss) dopo aver aumentato il profitto della posizione, ovvero il livello di Trailing Stop. Troverai la procedura step by step per creare una classe per il trailing stop sugli indicatori SAR e NRTR. Tutti potranno inserire questo trailing stop nei propri expert o utilizzarlo autonomamente per controllare le posizioni nei propri account.