Indicatore per la costruzione di un grafico Three Line Break
Introduzione
Gli articoli precedenti riguardavano i grafici Point and Figure, Kagi and Renko. Continuando la serie di articoli sui grafici del 20 ° secolo, questa volta parleremo del grafico Three Line Break o, per essere precisi, della sua implementazione attraverso un codice di programma . Ci sono pochissime informazioni sull'origine di questo grafico. Suppongo che sia stato inventato in Giappone. Negli Stati Uniti è stato introdotto da "Beyond Candlesticks" di Steve Nison pubblicato nel 1994.
Così come nei grafici sopra menzionati, l'intervallo di tempo non viene preso in considerazione quando si costruisce il grafico Three Line Break. Il grafico si basa sui prezzi di chiusura di nuova formazione di un determinato intervallo di tempo, che consente di filtrare le fluttuazioni minori di un prezzo rispetto al movimento precedente.
Steve Nison nel suo libro "Beyond Candlesticks" ha descritto undici principi per tracciare questo grafico (p. 185). Li ho raggruppati in tre principi:
- Principio №1: Per la costruzione, seleziona un prezzo iniziale e poi, a seconda che il mercato si muova al rialzo o al ribasso, traccia una linea ascendente o discendente. Questo segnerà un nuovo minimo o massimo.
- Principio №2: Quando un nuovo prezzo scende al di sotto del minimo o supera il massimo, possiamo tracciare una linea discendente o ascendente.
- Principio №3: Per tracciare una linea nella direzione opposta al movimento precedente, è necessario superare il minimo o il massimo. Allo stesso tempo, se c'è più di una riga identica, il minimo o il massimo viene calcolato in base a due righe (se ci sono due righe identiche consecutive) o tre righe (se ci sono tre o più righe identiche consecutive).
Diamo uno sguardo più da vicino all'esempio di una classica costruzione di grafici basata su dati storici (fig. 1).
Fig.1 Esempio di costruzione di un grafico Three Line Break (EURUSD H1 27.06.2014)
La Fig. 1 rappresenta un grafico Candlestick sul lato sinistro e un grafico Three Line Break sul lato destro. Questo è un grafico di EURUSD, timeframe H1. La data di inizio del grafico è 27.06.2014 al prezzo 1.3613 (l'orario di chiusura della candela è 00:00), quindi la candela (01:00) chiude a 1.3614, formando la prima linea ascendente del grafico Three Line Break. La successiva candela di direzione ribassista (02:00) forma una linea ascendente, chiudendo a 1,3612 (il prezzo di chiusura è inferiore al minimo precedente).
Quindi le candele rialziste stanno spostando il prezzo verso il segno 1,3619 (03:00), formando un nuovo massimo e una nuova linea. La candela alle 04:00 non è scesa al di sotto del minimo e non ha influito sulla costruzione. La candela alle 05:00 chiude a 1.3623, segnando un nuovo massimo (nuova linea ascendente).
Ora per estendere la tendenza al ribasso, dobbiamo superare due minimi (1,3613), ma i rialzisti (tori) non rinunceranno alla loro posizione e formeranno un nuovo massimo 1,3626 (06:00). Quindi i rialzisti stanno cercando di invertire il trend rialzista per due ore, ma lo stesso trend continua con un nuovo massimo raggiunto a 1,3634 (09:00). I tori sono in testa. Ora per tracciare una linea ascendente bisogna superare tre minimi (1.3626; 1.3623 e 1.3619).
Come si vede, nelle tre ore successive i ribassisti (orsi) stanno prendendo il sopravvento sul mercato, portandolo a quota 1,3612 (12:00). Questo si riflette in una nuova linea ascendente. Tuttavia, le cinque ore successive mostrano che i rialzisti stanno riconquistando la loro posizione e riportano il mercato al punto di 1.3641, superando il precedente massimo a 1.3626 e formando una nuova linea ascendente alle 17:00. I ribassisti non riescono a superare il minimo precedente alle 18:00 e per le successive cinque ore i rialzisti stanno portando il mercato fino al punto di 1,3649, formando ogni ora una nuova linea ascendente.
Nozioni di base sulla costruzione di grafici
Prima di arrivare al codice, parleremo dell'indicatore stesso e scopriremo cosa lo rende diverso dagli altri. È ovvio che il grafico Three Line Break, come altri indicatori, è stato progettato per facilitare un'analisi di mercato efficiente e la ricerca di nuove strategie. Sono sicuro che vorrai sapere se ci sono novità. In realtà ce ne sono alcune. L'indicatore consente di modificare il tipo di prezzo per il calcolo. Copre tutti e quattro i prezzi standard del bar. Il modello classico è progettato per costruire grafici solo per un tipo di prezzo quando la versione modernizzata prevede l'utilizzo di tutti e quattro i tipi di prezzo (aperto, alto, basso e chiuso). Esso modifica l'aspetto della classica costruzione del grafico aggiungendo "ombre" alle linee e facendole sembrare candele giapponesi, il che migliora la percezione visiva del grafico.
La versione aggiornata dispone anche di impostazioni per la sincronizzazione dei dati sui prezzi nel tempo con la sostituzione dei prezzi mancanti con quelli prioritari.
Il tipo modernizzato di costruzione del grafico è presentato in fig. 2:
Fig.2 Grafico modificato basato su quattro tipi di prezzo
Poiché la costruzione modernizzata combina quattro grafici Three Line Break di diversi tipi di prezzo, è naturale trovare discrepanze tra i prezzi. Per evitarlo, è necessaria la sincronizzazione dei dati nel tempo. La sincronizzazione dei prezzi è stata effettuata in due varianti: completa (fig. 2 a destra) e parziale (fig. 2 a sinistra). La sincronizzazione completa è una sincronizzazione parziale filtrata, dove tutti i dati vengono disegnati sul grafico e i dati mancanti vengono sostituiti dai prezzi prioritari specificati nelle impostazioni. Nella modalità di sincronizzazione completa i dati mancanti vengono semplicemente omessi e vengono disegnati solo le candele con un set completo di dati.
Un'altra innovazione è un separatore di punti, introdotto per comodità per dividere i segnali. Come ben sai, il separatore di punti può essere abilitato nelle impostazioni del grafico. Nell'indicatore questi cambiano a seconda del periodo di tempo, specificato nelle impostazioni. A differenza dei grafici in MetaTrader 5, dove i periodi sono separati da una linea tratteggiata verticale, in questo indicatore un nuovo periodo viene indicato cambiando il colore di una linea (candele, fig. 3):
Fig.3 Separatori di periodo nell'indicatore
Un'altra aggiunta è l'implementazione di un indicatore tecnico iMA, che è costruito sulla base dei prezzi del grafico principale, ma è sincronizzato con i dati dell'indicatore nel tempo. Pertanto i dati vengono filtrati dalla media mobile (fig. 4):
Fig.4 Media mobile interna
L'indicatore ha anche una funzione per impostare un movimento minimo in punti per tracciare una linea e il numero di linee necessarie per un'inversione. Funge anche da filtro.
Codice dell'indicatore
L'algoritmo dell'indicatore è piuttosto semplice e prevede tre fasi: copia dei dati, calcolo basato sui dati copiati e riempimento dei buffer dell'indicatore (costruzione di un grafico basato sui dati ricevuti). Il codice è suddiviso in funzioni che sono interconnesse o tra loro, o con i dati di input. Diamo un'occhiata da vicino al codice.
1. Numero di parametri di input dell'indicatore
Il preambolo dell'indicatore contiene una dichiarazione di costruzioni grafiche. Ce ne sono due nell'indicatore: grafico "ABCTB" (DRAW_COLOR_CANDLES) e media mobile aggiuntiva "LINE_TLB" (DRAW_LINE). Di conseguenza, ci sono sei buffer. Seguono quindi i dati di tipo enum per migliorare le impostazioni dell'interfaccia e le impostazioni stesse:
- magic_numb - Il numero magico ha il tipo long. È un numero univoco per indicare l'indicatore. In caso di necessità, può essere convertito in tipo string senza molte modifiche;
- time_frame - L'intervallo di tempo di calcolo, tipo ENUM_TIMEFRAMES, è il parametro principale (l'intervallo di tempo dell'indicatore);
- time_redraw - Periodo degli aggiornamenti del grafico, tipo ENUM_TIMEFRAMES. È l'intervallo di tempo durante il quale avviene un ricalcolo del grafico. Per ridisegnare velocemente il grafico premere il tasto "R" sulla tastiera, il quale effettuerà un controllo integrato dell'indicatore;
- first_date_start - Data di inizio, digita datetime.datetime. È il parametro principale, il punto di partenza per la copia dei dati e la creazione di grafici;
- chart_price - Tipo di prezzo per il calcolo (0-Close, 1-Open, 2-High, 3-Low). Per la costruzione di un grafico classico è necessario selezionare un tipo di prezzo. Come già accennato, questo parametro viene ignorato quando è abilitata la costruzione modificata;
- step_min_f - Passo minimo per una nuova colonna (>0, tipo int) o un salto richiesto per disegnare una linea;
- line_to_back_f - Numero di righe per visualizzare un'inversione (>0, tipo int). Il tipo classico suggerisce tre linee per mostrare un'inversione;
- chart_type - Tipo di costruzione del grafico (0-classico, 1-modificato), tipo select. È un cambiamento tra i tipi di costruzione;
- chart_color_period - Cambia colore all'inizio di un nuovo periodo (tipo boolean). Utilizzato per cambiare il colore della linea all'inizio di ua nuova frase;
- chart_synchronization - Costruzione di un grafico solo dopo la sincronizzazione completa (tipo boolean, se vero, si verifica una sincronizzazione completa con l'eliminazione di tutti i valori mancanti prima della costruzione di un grafico);
- chart_priority_close - Priorità del prezzo di chiusura (tipo select, ha quattro varianti. Punta alla priorità del prezzo di chiusura alla sincronizzazione parziale e viene ignorata a quella completa;
- chart_priority_open - Priorità del prezzo di apertura. Lo stesso vale qui;
- chart_priority_high - Priorità del prezzo massimo. Lo stesso vale qui;
- chart_priority_low - Priorità del prezzo minimo. Lo stesso vale qui;
- ma_draw - Disegna la media (tipo booleano, se vero, quindi traccia la media mobile);
- ma_price - Tipo di prezzo per la costruzione della media, può essere uno tra ENUM_APPLIED_PRICE;
- ma_method - Tipo di costruzione, può essere uno tra ENUM_MA_METHOD;
- ma_period - Periodo medio della media mobile;
Quindi dichiariamo array di buffer, variabili e strutture necessarie per il calcolo.
//+------------------------------------------------------------------+ //| ABCTB.mq5 | //| "Azotskiy Aktiniy ICQ:695710750" | //| "" | //+------------------------------------------------------------------+ // ABCTB - Auto Build Chart Three Line Break #property copyright "Azotskiy Aktiniy ICQ:695710750" #property link "" #property version "1.00" #property indicator_separate_window #property indicator_buffers 6 #property indicator_plots 2 //--- plot ABCTB #property indicator_label1 "ABCTB" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrBlue,clrRed,clrGreenYellow #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot LINE_TLB #property indicator_label2 "LINE_TLB" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- Price type for calculation enum type_price { close=0, // Close open=1, // Open high=2, // Hight low=3, // Low }; //--- type of chart construction enum type_build { classic=0, // Classic modified=1, // Modified }; //--- priority enum priority { highest_t=4, // Highest high_t=3, // High medium_t=2, // Medium low_t=1, // Low }; //--- input parameters input long magic_numb=65758473787389; // Magic number input ENUM_TIMEFRAMES time_frame=PERIOD_CURRENT; // Calculation time range input ENUM_TIMEFRAMES time_redraw=PERIOD_M1; // Period of chart updates input datetime first_date_start=D'2013.03.13 00:00:00'; // Start date input type_price chart_price=close; // Price type for calculation (0-Close, 1-Open, 2-High, 3-Low) input int step_min_f=4; // Minimum step for a new column (>0) input int line_to_back_f=3; // Number of lines to display a reversal(>0) input type_build chart_type=classic; // Type of chart construction (0-classic, 1-modified) input bool chart_color_period=true; // Changing color for a new period input bool chart_synchronization=true; // Constructing a chart only upon complete synchronization input priority chart_priority_close=highest_t; // Priority of the closing price input priority chart_priority_open=highest_t; // Priority of the opening price input priority chart_priority_high=highest_t; // Priority of the maximum price input priority chart_priority_low=highest_t; // Priority of the minimum price input bool ma_draw=true; // Draw the average input ENUM_APPLIED_PRICE ma_price=PRICE_CLOSE; // Price type for constructing the average input ENUM_MA_METHOD ma_method=MODE_EMA; // Construction type input int ma_period=14; // Averaging period //--- indicator buffers //--- buffer of the chart double ABCTBBuffer1[]; double ABCTBBuffer2[]; double ABCTBBuffer3[]; double ABCTBBuffer4[]; double ABCTBColors[]; //--- buffer of the average double LINE_TLBBuffer[]; //--- variables MqlRates rates_array[];// bar data array for analysis datetime date_stop; // current date datetime date_start; // start date variable for calculation //+------------------------------------------------------------------+ //| Struct Line Price | //+------------------------------------------------------------------+ struct line_price// structure for storing information about the past lines { double up; // value of the high price double down;// value of the low price }; //+------------------------------------------------------------------+ //| Struct Line Information | //+------------------------------------------------------------------+ struct line_info// structure for storing information about the shared lines { double up; double down; char type; datetime time; }; line_info line_main_open[]; // data on the opening prices chart line_info line_main_high[]; // data on the maximum prices chart line_info line_main_low[]; // data on the minimum prices chart line_info line_main_close[]; // data on the closing prices chart //+------------------------------------------------------------------+ //| Struct Buffer Info | //+------------------------------------------------------------------+ struct buffer_info// structure for storing data for filling a buffer { double open; double high; double low; double close; char type; datetime time; }; buffer_info data_for_buffer[];// data for filling the modified construction buffer datetime array_datetime[]; // array for storing information of the time for every line int time_array[3]; // array for the function func_date_color datetime time_variable; // variable for the function func_date_color bool latch=false; // variable-latch for the function func_date_color int handle; // handle of the indicator iMA int step_min; // variable of the minimum step int line_to_back; // variable of the number of lines to display a reversal
2. Funzione OnInit
Tutti i buffer degli indicatori sono dichiarati nella funzione OnInit e l'indicazione dell'array è impostata come in una serie temporale.
Quindi impostiamo i valori dell'indicatore che non si rifletteranno sul grafico, impostiamo il nome, specifichiamo il livello di precisione e rimuoviamo i valori correnti perchè sovraccaricano il grafico. Qui impostiamo anche l'handle dell'indicatore iMA e controlliamo la correttezza dei dati inseriti. In caso di errore, viene stampato un messaggio appropriato e il valore viene modificato al minimo.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- buffers for a chart SetIndexBuffer(0,ABCTBBuffer1,INDICATOR_DATA); ArraySetAsSeries(ABCTBBuffer1,true); SetIndexBuffer(1,ABCTBBuffer2,INDICATOR_DATA); ArraySetAsSeries(ABCTBBuffer2,true); SetIndexBuffer(2,ABCTBBuffer3,INDICATOR_DATA); ArraySetAsSeries(ABCTBBuffer3,true); SetIndexBuffer(3,ABCTBBuffer4,INDICATOR_DATA); ArraySetAsSeries(ABCTBBuffer4,true); SetIndexBuffer(4,ABCTBColors,INDICATOR_COLOR_INDEX); ArraySetAsSeries(ABCTBColors,true); //--- buffer for constructing the average SetIndexBuffer(5,LINE_TLBBuffer,INDICATOR_DATA); ArraySetAsSeries(LINE_TLBBuffer,true); //--- set the values that are not going to be reflected on the chart PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0); // for the chart PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0); // for the average //--- set the indicator appearance IndicatorSetString(INDICATOR_SHORTNAME,"ABCTB "+IntegerToString(magic_numb)); // name of the indicator //--- accuracy of display IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //--- prohibit displaying the results of the indicator current value PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); PlotIndexSetInteger(1,PLOT_SHOW_DATA,false); //--- handle=iMA(_Symbol,time_frame,ma_period,0,ma_method,ma_price); if(step_min_f<1) { step_min=1; Alert("Minimum step for a new column must be greater than zero"); } else step_min=step_min_f; //--- if(line_to_back_f<1) { line_to_back=1; Alert("The number of lines to display a reversal must be greater than zero"); } else line_to_back=line_to_back_f; //--- return(INIT_SUCCEEDED); }
3. Funzione di copia dei dati
Poiché l'indicatore è progettato per funzionare con tutti e quattro i tipi di prezzi, è essenziale copiare tutti i dati, compreso il tempo. In MQL5 c'è una struttura chiamata MqlRates. Viene utilizzata per memorizzare informazioni sull'ora di inizio di una sessione di trading, prezzi, volumi e spread.
I parametri di input della funzione sono la data di inizio e di fine, il timeframe e l'array di destinazione del tipo MqlRates. La funzione restituisce true se la copia ha esito positivo. I dati vengono copiati in un array intermedio. I dati mancanti calcolati più una sessione vengono copiati nell’array intermedio e i dati vengono rinnovati in modo permanente. Se la copia nell'array intermedio ha avuto successo, i dati vengono copiati nell'array e passati per garantire il corretto funzionamento della funzione.
//+------------------------------------------------------------------+ //| Func All Copy | //+------------------------------------------------------------------+ bool func_all_copy(MqlRates &result_array[],// response array ENUM_TIMEFRAMES period, // timeframe datetime data_start, // start date datetime data_stop) // end date { //--- declaration of auxiliary variables bool x=false; // variable for the function response int result_copy=-1; // copied data count //--- adding variables and arrays for calculation static MqlRates interim_array[]; // temporary dynamic array for storing copied data static int bars_to_copy; // number of bars for copying static int bars_copied; // number of copied bars since the start date //--- find out the current number of bars in the time range bars_to_copy=Bars(_Symbol,period,data_start,data_stop); //--- count the number of bars to be copied bars_to_copy-=bars_copied; //--- if it is not the first time when data is being copied if(bars_copied>0) { bars_copied--; bars_to_copy++; } //--- change the size of the receiving array ArrayResize(interim_array,bars_to_copy); //--- copy data to a temporary array result_copy=CopyRates(_Symbol,period,0,bars_to_copy,interim_array); //--- check the result of copying data if(result_copy!=-1) // if copying to the temporary array was successful { ArrayCopy(result_array,interim_array,bars_copied,0,WHOLE_ARRAY); // copy the data from the temporary array to the main one x=true; // assign the positive response to the function bars_copied+=result_copy; // increase the value of the copied data } //--- return(x); }
4. Funzione di calcolo dei dati
Questa funzione è un prototipo di calcolo dei dati per una costruzione classica del grafico Three Line Break. Come già accennato, la funzione calcola solo i dati e li dispone in un array speciale del tipo di struttura line_info, dichiarato all'inizio del codice.
Questa funzione contiene altre due funzioni: func_regrouping (funzione di raggruppamento) e func_insert (funzione di inserimento). Per cominciare, li esamineremo:
4.1. Funzione di raggruppamento
Questa funzione raggruppa le informazioni su linee consecutive con la stessa direzione. È limitata dalla dimensione dell'array che passa al suo interno o, per essere precisi, dal parametro line_to_back_f (numero di righe per visualizzare un'inversione) nelle impostazioni dell'indicatore. Quindi, ogni volta che il controllo viene passato alla funzione, tutti i dati ricevuti su linee identiche si spostano in basso di un punto verso la fine e l'indice 0 viene riempito con un nuovo valore.
In questo modo vengono memorizzate le informazioni sulle linee necessarie per un'interruzione (in caso di costruzione classica l'interruzione ha tre linee).
//+------------------------------------------------------------------+ // Func Regrouping | //+------------------------------------------------------------------+ void func_regrouping(line_price &input_array[],// array for regrouping double new_price, // new price value char type) // type of movement { int x=ArraySize(input_array);// find out the size of the array for regrouping for(x--; x>0; x--) // regrouping loop { input_array[x].up=input_array[x-1].up; input_array[x].down=input_array[x-1].down; } if(type==1) { input_array[0].up=new_price; input_array[0].down=input_array[1].up; } if(type==-1) { input_array[0].down=new_price; input_array[0].up=input_array[1].down; } }
4.2. Funzione di inserimento
La funzione esegue l'inserimento dei valori nell'array di risposta. Il codice è semplice e non richiede spiegazioni dettagliate.
//+------------------------------------------------------------------+ // Func Insert | //+------------------------------------------------------------------+ void func_insert(line_info &line_m[], // target array line_price &line_i[], // source array int index, // array element being inserted char type, // type of the target column datetime time) // date { line_m[index].up=line_i[0].up; line_m[index].down=line_i[0].down; line_m[index].type=type; line_m[index].time=time; }
La funzione per il calcolo dei dati è stata convenzionalmente suddivisa in tre parti. La prima parte copia i dati in analisi su un array intermedio con l'aiuto dell'switch dell'operatore. Viene copiato solo il prezzo in questione. La seconda parte esegue un test per calcolare lo spazio richiesto nell'array di dati. Quindi l'array di dati line_main_array[], inizialmente passato alla funzione per la risposta, subisce una modifica. La terza parte, a sua volta, riempie l'array di dati regolato.
//+------------------------------------------------------------------+ //| Func Build Three Line Break | //+------------------------------------------------------------------+ void func_build_three_line_break(MqlRates &input_array[], // array for analysis char price_type, // type of the price under analysis (0-Close, 1-Open, 2-High, 3-Low) int min_step, // minimum step for drawing a line int line_back, // number of lines for a reversal line_info &line_main_array[]) // array for return (response) of the function { //--- calculate the size of the array for analysis int array_size=ArraySize(input_array); //--- extract data required for calculation to an intermediate array double interim_array[];// intermediate array ArrayResize(interim_array,array_size);// adjust the intermediate array to the size of the data switch(price_type) { case 0: // Close { for(int x=0; x<array_size; x++) { interim_array[x]=input_array[x].close; } } break; case 1: // Open { for(int x=0; x<array_size; x++) { interim_array[x]=input_array[x].open; } } break; case 2: // High { for(int x=0; x<array_size; x++) { interim_array[x]=input_array[x].high; } } break; case 3: // Low { for(int x=0; x<array_size; x++) { interim_array[x]=input_array[x].low; } } break; } //--- enter the variables for storing information about current situation line_price passed_line[];// array for storing information about the latest prices of the lines (type structure line_price) ArrayResize(passed_line,line_back+1); int line_calc=0;// number of lines int line_up=0;// number of the last ascending lines int line_down=0;// number of the last descending lines double limit_up=0;// upper limit necessary to pass double limit_down=0;// lower limit necessary to pass /* Fill variables informing of the current situation with the first values */ passed_line[0].up=interim_array[0]; passed_line[0].down=interim_array[0]; //--- start the first loop to calculate received data for filling a buffer for drawing for(int x=0; x<array_size; x++) { if(line_calc==0)// no lines have been drawn { limit_up=passed_line[0].up; limit_down=passed_line[0].down; if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup line_calc++;// update the line counter line_up++; } if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup line_calc++;// update the line counter line_down++; } } if(line_up>line_down)// last ascending line (lines) { limit_up=passed_line[0].up; limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down; if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup line_calc++;// update the line counter line_up++; } if(interim_array[x]<limit_down)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup line_calc++;// update the line counter line_up=0; line_down++; } } if(line_down>line_up)// last descending line (lines) { limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up; limit_down=passed_line[0].down; if(interim_array[x]>limit_up)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup line_calc++;// update the line counter line_down=0; line_up++; } if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup line_calc++;// update the line counter line_down++; } } } ArrayResize(line_main_array,line_calc);// change the size of the target array //--- zeroise variables and fill with the the initial data line_calc=0; line_up=0; line_down=0; passed_line[0].up=interim_array[0]; passed_line[0].down=interim_array[0]; //--- start the second loop to fill a buffer for drawing for(int x=0; x<array_size; x++) { if(line_calc==0)// no lines have been drawn { limit_up=passed_line[0].up; limit_down=passed_line[0].down; if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time); line_calc++;// update the line counter line_up++; } if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time); line_calc++;// update the line counter line_down++; } } if(line_up>line_down)// last ascending line (lines) { limit_up=passed_line[0].up; limit_down=passed_line[(int)MathMin(line_up,line_back-1)].down; if(interim_array[x]>=limit_up+min_step*_Point)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time); line_calc++;// update the line counter line_up++; } if(interim_array[x]<limit_down)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time); line_calc++;// update the line counter line_up=0; line_down++; } } if(line_down>line_up)// last descending line (lines) { limit_up=passed_line[(int)MathMin(line_down,line_back-1)].up; limit_down=passed_line[0].down; if(interim_array[x]>limit_up)// the upper limit has been passed { func_regrouping(passed_line,interim_array[x],1);// regroup func_insert(line_main_array,passed_line,line_calc,1,input_array[x].time); line_calc++;// update the line counter line_down=0; line_up++; } if(interim_array[x]<=limit_down-min_step*_Point)// the lower limit has been passed { func_regrouping(passed_line,interim_array[x],-1);// regroup func_insert(line_main_array,passed_line,line_calc,-1,input_array[x].time); line_calc++;// update the line counter line_down++; } } } }
5. Funzione di costruzione del grafico
Lo scopo di questa funzione è calcolare i dati per un grafico in base al parametro di costruzione selezionato (classico o modificato) e riempire il buffer dell'indicatore con i dati per la visualizzazione. Oltre alla funzione precedente, la funzione di costruzione del grafico ha tre funzioni aggiuntive. Queste sono la funzione del colore, la funzione della sincronizzazione e la funzione della media mobile. Affrontiamo l’argomento in modo più dettagliato.
5.1. Funzione colore
Questa funzione ha un solo parametro di input: il tempo. La risposta della funzione è una variabile booleana. Se i dati passati sono il bordo del periodo, la funzione restituirà true. Poiché i periodi dipendono dall'intervallo di tempo selezionato, la funzione ha una separazione dei periodi incorporata dall'operatore condizionale if. Dopo che il periodo è stato selezionato, viene verificato se è già iniziato un nuovo periodo. Viene effettuato mediante la conversione di una data in struttura MqlDateTime e tramite il suo confronto. Per il periodo fino al secondo semestre compreso, le variazioni del valore della data indicano l'inizio di un nuovo periodo. I tempi da H12 a D1 inclusi indicano variazioni in mesi e tra W1 e MN controlliamo la variazione nell'anno.
Sfortunatamente, la struttura MqlDateTime non ha informazioni sulla settimana corrente. Questo problema è stato risolto creando un punto iniziale rappresentato dalla variabile time_variable. Più avanti, un certo numero di secondi in una settimana viene sottratto da questa data.
//+------------------------------------------------------------------+ // Func Date Color | //+------------------------------------------------------------------+ bool func_date_color(datetime date_time) // input date { bool x=false;// response variable int seconds=PeriodSeconds(time_frame);// find out the calculation time range MqlDateTime date; TimeToStruct(date_time,date);// convert data if(latch==false) // check the state of the latch { MqlDateTime date_0; date_0=date; date_0.hour=0; date_0.min=0; date_0.sec=0; int difference=date_0.day_of_week-1; datetime date_d=StructToTime(date_0); date_d=date_d-86400*difference; time_variable=date_d; latch=true;// lock the latch } if(seconds<=7200)// period is less than or equal to H2 { if(time_array[0]!=date.day) { x=true; time_array[0]=date.day; } } if(seconds>7200 && seconds<=43200)// period is greater than H2 but less than or equal to H12 { if(time_variable>=date_time) { x=true; time_variable=time_variable-604800; } } if(seconds>43200 && seconds<=86400)// period is greater than H12 but less than or equal to D1 { if(time_array[1]!=date.mon) { x=true; time_array[1]=date.mon; } } if(seconds>86400)// period W1 or MN { if(time_array[2]!=date.year) { x=true; time_array[2]=date.year; } } return(x); }
5.2. Funzione di sincronizzazione
La funzione di sincronizzazione ha sei parametri di input: quattro di questi sono la priorità dei prezzi, il parametro booleano di sincronizzazione completa o parziale e l'array stesso in analisi. La funzione è divisa in due parti, le quali rappresentano un caso di sincronizzazione completa e parziale.
La sincronizzazione completa viene eseguita in tre fasi:
- Calcolo degli elementi dell'array che soddisfano la condizione di contenimento di dati su tutti e quattro i tipi di prezzo.
- Copia di elementi in una matrice intermedia nelle stesse condizioni.
- Copia dall'array intermedio a quello passato dai parametri.
La sincronizzazione parziale è più complessa.
L'array di struttura unidimensionale passato viene convertito in uno bidimensionale, dove il primo indice indica l'ordine e il secondo il tipo di prezzo. Quindi viene introdotto un array unidimensionale con quattro elementi. I livelli di priorità dei prezzi vengono copiati in questo array e quindi l'array viene ordinato per identificare l'ordine di priorità. Successivamente eseguiamo la distribuzione in base alle priorità utilizzando il ciclo for e l'operatore condizionale if. Allo stesso tempo, se le priorità sono uguali, la sequenza dei prezzi è la seguente: chiusura, apertura, massimo, minimo. Non appena l'operatore if trova il primo valore prioritario, il ciclo for sostituisce tutti i dati ‘zero’ nell'array bidimensionale creato in precedenza con quelli prioritari ecc.
//+------------------------------------------------------------------+ // Func Synchronization | //+------------------------------------------------------------------+ void func_synchronization(buffer_info &info[], bool synchronization, char close, char open, char high, char low) { if(synchronization==true)// carry out a complete synchronization { int calc=0;// count variable for(int x=0; x<ArraySize(info); x++)// count complete data { if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0)calc++; } buffer_info i_info[]; // enter a temporary array for copying ArrayResize(i_info,calc);// change the size of the temporary array calc=0; for(int x=0; x<ArraySize(info); x++)// copy data into the temporary array { if(info[x].close!=0 && info[x].high!=0 && info[x].low!=0 && info[x].open!=0) { i_info[calc]=info[x]; calc++; } } ZeroMemory(info); // clear the target array ArrayResize(info,calc); // change the size of the main array for(int x=0; x<calc; x++)// copy data from the temporary array to the main one { info[x]=i_info[x]; } } if(synchronization==false) // change zero values to priority ones { int size=ArraySize(info); // measure the size of the array double buffer[][4]; // create a temporary array for calculation ArrayResize(buffer,size); // change the size of the temporary array for(int x=0; x<size; x++) // copy data into the temporary array { buffer[x][0]=info[x].close; buffer[x][1]=info[x].open; buffer[x][2]=info[x].high; buffer[x][3]=info[x].low; } char p[4];// enter an array for sorting by the order p[0]=close; p[1]=open; p[2]=high; p[3]=low;// assign variables for further sorting ArraySort(p); // sort int z=0,v=0; // initialize frequently used variables for(int x=0; x<4; x++)// taking into account the results of the sorting, look through all variables and substitute them according to the priority { if(p[x]==close)// priority is for the closing prices { for(z=0; z<size; z++) { for(v=1; v<4; v++) { if(buffer[z][v]==0)buffer[z][v]=buffer[z][0]; } } } if(p[x]==open)// priority is for the opening prices { for(z=0; z<size; z++) { for(v=0; v<4; v++) { if(v!=1 && buffer[z][v]==0)buffer[z][v]=buffer[z][1]; } } } if(p[x]==high)// priority is for the maximum prices { for(z=0; z<size; z++) { for(v=0; v<4; v++) { if(v!=2 && buffer[z][v]==0)buffer[z][v]=buffer[z][2]; } } } if(p[x]==low)// priority is for the minimum prices { for(z=0; z<size; z++) { for(v=0; v<3; v++) { if(buffer[z][v]==0)buffer[z][v]=buffer[z][3]; } } } } for(int x=0; x<size; x++)// copy data from the temporary array back { info[x].close=buffer[x][0]; info[x].open=buffer[x][1]; info[x].high=buffer[x][2]; info[x].low=buffer[x][3]; } } }
5.3. Funzione della media mobile
È la funzione più semplice. Utilizzando l'handle dell'indicatore, ricevuto nella funzione OnInit, copiamo il valore, corrispondente alla data passata nei parametri della funzione. Quindi questo valore viene restituito come risposta a questa funzione.
//+------------------------------------------------------------------+ // Func MA | //+------------------------------------------------------------------+ double func_ma(datetime date) { double x[1]; CopyBuffer(handle,0,date,1,x); return(x[0]); }
La funzione di tracciare un grafico è convenzionalmente divisa in modo classico e quella modificato. La funzione ha due parametri di input: tipo di prezzo per la costruzione (ignorato durante la costruzione modificata) e tipo di costruzione (classica e modificata).
All'inizio i buffer indicatori vengono cancellati e poi, a seconda del tipo di costruzione, divisi in due parti. La prima parte (stiamo parlando della costruzione modificata) inizia con il richiamo della funzione per il calcolo di tutti e quattro i tipi di prezzo. Quindi creiamo un array di dati comune in cui copiamo i dati in uso, ricevuti quando si chiama la funzione di calcolo dei dati. Quindi l'array di dati ricevuto viene ordinato e cancellato dai dati replicati. Successivamente l'array data_for_buffer[], dichiarato a livello globale, viene riempito in base a date consecutive con la seguente sincronizzazione dei dati. Il riempimento dei buffer indicatori è la fase finale della costruzione modificata.
La seconda parte (costruzione classica) è molto più semplice. Dapprima viene richiamata la funzione di calcolo dati e poi vengono riempiti i buffer indicatori.
//+------------------------------------------------------------------+ //| Func Chart Build | //+------------------------------------------------------------------+ void func_chart_build(char price, // price type for chart construction char type) // type of chart construction { //--- Zeroise the buffers ZeroMemory(ABCTBBuffer1); ZeroMemory(ABCTBBuffer2); ZeroMemory(ABCTBBuffer3); ZeroMemory(ABCTBBuffer4); ZeroMemory(ABCTBColors); ZeroMemory(LINE_TLBBuffer); if(type==1)// construct a modified chart (based on all price types) { func_build_three_line_break(rates_array,0,step_min,line_to_back,line_main_close);// data on closing prices func_build_three_line_break(rates_array,1,step_min,line_to_back,line_main_open);// data on opening prices func_build_three_line_break(rates_array,2,step_min,line_to_back,line_main_high);// data on maximum prices func_build_three_line_break(rates_array,3,step_min,line_to_back,line_main_low);// data on minimum prices //--- calculate data arrays int line_main_calc[4]; line_main_calc[0]=ArraySize(line_main_close); line_main_calc[1]=ArraySize(line_main_open); line_main_calc[2]=ArraySize(line_main_high); line_main_calc[3]=ArraySize(line_main_low); //--- gather the date array int all_elements=line_main_calc[0]+line_main_calc[1]+line_main_calc[2]+line_main_calc[3];// find out the number of all elements datetime datetime_array[];// enter the array for copying ArrayResize(datetime_array,all_elements); int y[4]; ZeroMemory(y); for(int x=0;x<ArraySize(datetime_array);x++)// copy data into the array { if(x<line_main_calc[0]) { datetime_array[x]=line_main_close[y[0]].time; y[0]++; } if(x<line_main_calc[0]+line_main_calc[1] && x>=line_main_calc[0]) { datetime_array[x]=line_main_open[y[1]].time; y[1]++; } if(x<line_main_calc[0]+line_main_calc[1]+line_main_calc[2] && x>=line_main_calc[0]+line_main_calc[1]) { datetime_array[x]=line_main_high[y[2]].time; y[2]++; } if(x>=line_main_calc[0]+line_main_calc[1]+line_main_calc[2]) { datetime_array[x]=line_main_low[y[3]].time; y[3]++; } } ArraySort(datetime_array);// sort the array //--- delete replicated data from the array int good_info=1; for(int x=1;x<ArraySize(datetime_array);x++)// count useful information { if(datetime_array[x-1]!=datetime_array[x])good_info++; } ArrayResize(array_datetime,good_info); array_datetime[0]=datetime_array[0];// copy the first element as it is the pattern in the beginning of comparison good_info=1; for(int x=1;x<ArraySize(datetime_array);x++)// fill the new array with useful data { if(datetime_array[x-1]!=datetime_array[x]) { array_datetime[good_info]=datetime_array[x]; good_info++; } } //--- fill the buffer for drawing (colored candles) int end_of_calc[4];// variables of storing information about the last comparison ZeroMemory(end_of_calc); ZeroMemory(data_for_buffer); ArrayResize(data_for_buffer,ArraySize(array_datetime));// change the size of the declared global array for storing data before passing it to a buffer for(int x=0; x<ArraySize(array_datetime); x++) { data_for_buffer[x].time=array_datetime[x]; for(int s=end_of_calc[0]; s<line_main_calc[0]; s++) { if(array_datetime[x]==line_main_close[s].time) { end_of_calc[0]=s; if(line_main_close[s].type==1)data_for_buffer[x].close=line_main_close[s].up; else data_for_buffer[x].close=line_main_close[s].down; break; } } for(int s=end_of_calc[1]; s<line_main_calc[1]; s++) { if(array_datetime[x]==line_main_open[s].time) { end_of_calc[1]=s; if(line_main_open[s].type==1)data_for_buffer[x].open=line_main_open[s].down; else data_for_buffer[x].open=line_main_open[s].up; break; } } for(int s=end_of_calc[2]; s<line_main_calc[2]; s++) { if(array_datetime[x]==line_main_high[s].time) { end_of_calc[2]=s; data_for_buffer[x].high=line_main_high[s].up; break; } } for(int s=end_of_calc[3]; s<line_main_calc[3]; s++) { if(array_datetime[x]==line_main_low[s].time) { end_of_calc[3]=s; data_for_buffer[x].low=line_main_low[s].down; break; } } } //--- start the function of synchronizing data func_synchronization(data_for_buffer,chart_synchronization,chart_priority_close,chart_priority_open,chart_priority_high,chart_priority_low); //--- preparatory actions before starting the function func_date_color ZeroMemory(time_array); time_variable=0; latch=false; //--- fill the buffer for drawing candles for(int x=ArraySize(data_for_buffer)-1,z=0; x>=0; x--) { ABCTBBuffer1[z]=data_for_buffer[x].open; ABCTBBuffer2[z]=data_for_buffer[x].high; ABCTBBuffer3[z]=data_for_buffer[x].low; ABCTBBuffer4[z]=data_for_buffer[x].close; if(ABCTBBuffer1[z]<=ABCTBBuffer4[z])ABCTBColors[z]=0; if(ABCTBBuffer1[z]>=ABCTBBuffer4[z])ABCTBColors[z]=1; if(func_date_color(data_for_buffer[x].time)==true && chart_color_period==true)ABCTBColors[z]=2; if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(data_for_buffer[x].time); z++; } } else// construct a classic chart (based on one price type) { func_build_three_line_break(rates_array,price,step_min,line_to_back,line_main_close);// find data on selected prices ArrayResize(array_datetime,ArraySize(line_main_close)); //--- preparatory actions before starting the function func_date_color ZeroMemory(time_array); time_variable=0; latch=false; //--- the buffer for drawing candles for(int x=ArraySize(line_main_close)-1,z=0; x>=0; x--) { ABCTBBuffer1[z]=line_main_close[x].up; ABCTBBuffer2[z]=line_main_close[x].up; ABCTBBuffer3[z]=line_main_close[x].down; ABCTBBuffer4[z]=line_main_close[x].down; if(line_main_close[x].type==1)ABCTBColors[z]=0; else ABCTBColors[z]=1; if(func_date_color(line_main_close[x].time)==true && chart_color_period==true)ABCTBColors[z]=2; if(ma_draw==true)LINE_TLBBuffer[z]=func_ma(line_main_close[x].time); z++; } } }
6. Funzione di consolidamento
Questa funzione unisce tutti gli elementi indicatori di controllo. Dapprima viene definita la data corrente, poi vengono richiamate la funzione di copia dei dati e la funzione di costruzione del grafico.
//+------------------------------------------------------------------+ //| Func Consolidation | //+------------------------------------------------------------------+ void func_consolidation() { //--- defining the current date date_stop=TimeCurrent(); //--- copying data for analysis func_all_copy(rates_array,time_frame,first_date_start,date_stop); //--- basic construction of the chart func_chart_build(chart_price,chart_type); ChartRedraw(); }
7. Funzione di costruzione comandata da chiave e controllata automaticamente
Queste funzioni sono progettate per ridisegnare l'indicatore premendo il tasto "R" (OnChartEvent) sulla tastiera o farlo automaticamente in base all'intervallo di tempo selezionato (OnCalculate). Quest'ultimo viene analizzato dalla nuova funzione bar (func_new_bar) che è una versione semplificata della funzione descritta in IsNewBar.
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { //--- if(func_new_bar(time_redraw)==true) { func_consolidation(); }; //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- event of a keystroke if(id==CHARTEVENT_KEYDOWN) { if(lparam==82) //--- the key "R" has been pressed { func_consolidation(); } } } //+------------------------------------------------------------------+ //| Func New Bar | //+------------------------------------------------------------------+ bool func_new_bar(ENUM_TIMEFRAMES period_time) { //--- static datetime old_times; // variable of storing old values bool res=false; // variable of the analysis result datetime new_time[1]; // time of a new bar //--- int copied=CopyTime(_Symbol,period_time,0,1,new_time); // copy the time of the last bar to the cell new_time //--- if(copied>0) // everything is ок. data copied { if(old_times!=new_time[0]) // if the old time of the bar is not equal to the new one { if(old_times!=0) res=true; // if it is not the first start, then new bar = true old_times=new_time[0]; // remember the time of the bar } } //--- return(res); }
A questo punto finiremo di descrivere il codice dell'indicatore e parleremo delle modalità di utilizzo.
Esempi di utilizzo dell'indicatore in una strategia di trading
Partiamo dalle principali strategie di analisi basate sulla classica costruzione del grafico.
1. Linee bianche e nere come segnali per comprare e vendere
In linea di massima possiamo parlare di due regole:
- Regola №1: Acquista, quando ci sono tre linee ascendenti consecutive e vendi, quando ci sono tre linee discendenti consecutive. Tre linee consecutive indicano una tendenza apparente.
- Regola №2: Vendi, quando la linea di inversione scende al di sotto di tre linee ascendenti consecutive, acquista, quando la linea di inversione è superiore a tre linee discendenti consecutive.
Diamo un'occhiata alla fig.6, che rappresenta una costruzione classica per EURUSD H1 dall'inizio del 2013 (l'intervallo temporale analizzato è illustrato nella fig.5).
Fig.5 Intervallo temporale analizzato EURUSD H1
Fig.6 Costruzione classica del grafico Three Line Break per EURUSD H1, inizio 2013, prezzi di chiusura
Sul grafico (fig. 6) possiamo vedere chiaramente il segnale (regola №1) tra i punti 1 e 2, il quale rappresenta un punto di partenza per la vendita. In questo caso il guadagno è di oltre 200 punti per quattro cifre decimali. Il successivo punto 4 indica una situazione favorevole per l'acquisto (come nella regola №2). Alla chiusura del punto 5 il profitto era di 40 punti e alla chiusura del punto 6 siamo in pareggio.
Nel punto 6 riconosciamo un segnale per vendere (regola №2). Otteniamo 10 punti di profitto quando chiudiamo al punto 7 e pareggio quando chiudiamo al punto 8. I punti 8 e 9 non possono essere considerati segnali in quanto non soddisfano né la regola №1, né la regola №2. Possiamo acquistare al punto 10 (regola №1); possiamo anche ottenere un profitto di 20 punti alla chiusura al punto 11 o al pareggio al punto 12. Tutti i numeri sono stati arrotondati.
Nel migliore dei casi, utilizzando questa strategia potremmo generare un profitto di 270 punti, il che è impressionante. Allo stesso tempo, nell'intervallo di tempo specificato c'è un movimento intenso che influisce sul profitto. Nel peggiore dei casi, il trading può portare a un pareggio, il che non è male.
Vale la pena ricordare che quando una situazione soddisfa la regola №1 o la regola №2, dobbiamo attendere una conferma di inversione di tendenza rappresentata da una linea nella stessa direzione della tendenza.
2. Canale equidistante, linee di sostegno e resistenti
Un'altra strategia di trading consiste nell'applicare l'analisi tecnica al grafico Three Line Break. Diamo un'occhiata alla fig. 7:
Fig. 7 Canale equidistante, linee di supporto e resistenza, GBPUSD H1, intervallo temporale dal 01.03.2014 al 01.05.2014
In Fig. 7 puoi vedere che il canale discendente equidistante è disegnato in linee rosse, il canale ascendente è disegnato in blu e le linee di supporto e resistenza sono disegnate in nero. È chiaro che la prima linea di resistenza si sta trasformando in linea di supporto.
3. Modelli di candele giapponesi
Un grafico modificato (interruzione di due righe) sul timeframe M30 per la coppia USDCAD all'inizio del 2013 sembra piuttosto interessante.
Possiamo distinguere pattern di candele giapponesi che hanno giustificato i loro segnali (fig. 8).
Fig. 8 Grafico modificato con tre linee di interruzione, USDCAD M30, inizio 2013, due linee di interruzione
All'inizio del grafico possiamo vedere un modello di inversione detto di "Engulfing" sotto №1. Si compone di due candele: rossa e la precedente blu. Dopo la linea di tendenza al rialzo, il mercato scende al numero 2, che è un modello di inversione a una sola candela detto "Hammer". A questo punto il mercato cambia direzione. Lo stesso accade nel modello №3 ("Trottola"). Il seguente schema di inversione "Kharami" (№4) è mostrato dalla candela 4 e da quella grande ascendente accanto ad essa. Anche il pattern №6 è composto da due candele (pattern "Engulfing") ma a differenza del primo modello molto simile, esso fa girare il mercato nella direzione opposta.
Pertanto, si può concludere che l'utilizzo dell'indicatore in questo tipo di analisi è accettabile, ma presenta svantaggi come la rarità del verificarsi di segnali e la possibilità di un significativo drawdown. Questa strategia ha certamente bisogno di ulteriore sviluppo.
4. Media mobile
La modifica parziale, come l'aggiunta di una media mobile solo alle linee tracciate, offre nuove opportunità di analisi.
Osserviamo la fig. 9:
Fig.9 Analisi della media mobile, EURUSD H4, grafico Three Line Break, costruzione classica, dal 01.01.2014 al 01.07.2014
La parte superiore della fig. 9 illustra una costruzione classica basata sui prezzi alti con una media mobile (il periodo di media è 90, il prezzo basso, la media livellata). La parte inferiore mostra una costruzione classica basata su prezzi bassi con media mobile (periodo medio 90, prezzo alto, media livellata).
Quindi, nella parte superiore della fig. 9 la media mobile può essere considerata una linea di supporto e nella parte inferiore, al contrario, una linea di resistenza. Se il prezzo su entrambi i grafici scende al di sotto della media allora c'è una tendenza al ribasso sul mercato, ed è meglio vendere. Quando il prezzo sale al di sopra della media è il momento di comprare. Uno svantaggio di questa strategia è che è pensata per un trading a lungo termine.
Conclusione
In conclusione posso dire che il Three Line Break dà costantemente buoni segnali o, nel peggiore dei casi, porta al pareggio. La pratica dimostra che è meglio applicarlo in un trend a lungo termine e, quindi, non consiglio di utilizzare questo grafico per un trading a breve termine. Se qualcuno ha nuove idee su come usarlo nel trading, sarei lieto di discuterne.
Come al solito, ho cercato di esplorare il codice in dettaglio. Anche in questo caso, se avete idee su come estenderlo, rielaborarlo o ottimizzarlo, scrivete nei commenti all'articolo.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/902
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso