Indicateur de construction d'un graphique à trois sauts de ligne
Introduction
Les articles précédents ont examiné les graphiques Point, et Figure,Kagi et Renko. Poursuivant la série d’articles sur les graphiques du 20ème siècle, cette fois nous allons parler de la graphique à trois sauts de ligne ou, pour être précis, de son implémentation à travers un code de programme. Il y a très peu d’informations sur l’origine de ce graphique. Je suppose que cela a commencé au Japon. Aux États-Unis, ils l’ont appris http://www.amazon.com/Beyond-Candlesticks-Japanese-Charting-Techniques/dp/047100720X« Beyond Candlesticks » de Steve Nison publié en 1994.
De même que dans les graphiques mentionnés ci-dessus, la plage de temps n’est pas prise en compte lors de la construction du graphique à trois sauts de ligne. Il est basé sur des cours de fermeture nouvellement formés d’une certaine période, ce qui permet de filtrer les fluctuations mineures d’un prix par rapport au mouvement précédent.
Steve Nison dans son livre « Beyond Candlesticks » décrit onze principes pour tracer ce tableau (p. 185). Je les ai regroupés en trois.
- Principe N°1: Pour la construction, sélectionnez un prix initial, puis, selon que le marché monte ou descend, tracez une ligne ascendante ou descendante. Il marquera un nouveau minimum ou maximum.
- Principe N°2: Lorsqu’un nouveau prix tombe en dessous du minimum ou dépasse le maximum, nous pouvons tracer une ligne descendante ou ascendante.
- Principe n°3: Pour tracer une ligne dans la direction opposée au mouvement précédent, le minimum ou le maximum doit être dépassé. En même temps, s’il y a plus d’une ligne identique, le minimum ou le maximum est calculé sur la base de deux (s’il y a deux lignes identiques consécutives) ou de trois (s’il y a trois lignes identiques consécutives ou plus) d’entre elles.
Examinons de plus près l’exemple d’une construction graphique classique basée sur des données historiques (fig. 1).
Fig.1 Exemple de construction d’un graphique à trois sauts de ligne (EURUSD H1 27.06.2014)
La Fig. 1 représente un graphique en chandelier sur le côté gauche et un graphique à trois sauts de ligne sur le côté droit. Ceci est un graphique de EURUSD, période H1. La date de début du graphique est le 27.06.2014 au prix 1.3613 (l’heure de fermeture de la chandelle est 00:00), puis la chandelle (01:00) ferme à 1.3614, formant la première ligne ascendante du graphique à trois sauts de ligne La bougie suivante de la direction baissière (02h00) forme une ligne ascendante, clôturant à 1,3612 (le prix de fermeture est inférieur au minimum précédent).
Ensuite, les chandeliers haussiers déplacent le prix vers la marque 1.3619 (03:00), formant un nouveau maximum et une ligne. La chandelle à 04h00 n’est pas tombée en dessous du minimum et cela n’a pas affecté la construction. La chandelle à 05:00 ferme à 1.3623, marquant un nouveau maximum (nouvelle ligne ascendante).
Maintenant, pour prolonger la tendance baissière, nous devons passer deux minimums (1,3613), mais les hausses ne vont pas abandonner leur position et former un nouveau maximum de 1,3626 (06:00). Ensuite, les haussiers tentent d’inverser la tendance haussière pendant deux heures, mais la même tendance se poursuit avec un nouveau maximum atteint à 1,3634 (09h00). Les haussiers sont en tête. Maintenant, pour tracer une ligne ascendante, trois minimums doivent être passés (1,3626; 1,3623 et 1,3619).
Comme nous pouvons le voir, dans les trois heures qui suivent, les ours s’emparent du marché, le descendant au point de 1,3612 (12h00). Elle se traduit par une nouvelle ligne ascendante. Cependant, les cinq heures suivantes montrent que les haussiers reconquirent leur position et ramènent le marché au point de 1,3641, dépassant le maximum précédent à 1,3626 et formant une nouvelle ligne ascendante à 17h00. Les ours ne parviennent pas à dépasser le minimum précédent à 18h00 et pendant les cinq heures suivantes, les taureaux amènent le marché au point de 1,3649, formant une nouvelle ligne ascendante toutes les heures.
Principes de base de la construction de graphiques
Avant d’arriver au code, nous allons parler de l’indicateur lui-même et déterminer ce qui le rend différent des autres et comment. Il est évident que le trois sauts de ligne, comme d’autres indicateurs, a été conçu pour faciliter une analyse efficace du marché et la recherche de nouvelles stratégies. Je suis sûr que vous voulez savoir s’il y a des nouveautés. En fait, il y en a quelques-uns. L’indicateur permet de changer le type de prix pour le calcul. Il couvre les quatre prix des bars standard. Le type classique est conçu pour construire des graphiques pour un seul type de prix lorsque le type modernisé prend en charge l’utilisation des quatre types de prix (ouvert, élevé, bas и fermer). Il modifie l’apparence de la construction classique du graphique en ajoutant des « ombres » aux lignes et en les faisant ressembler à des chandeliers japonais, ce qui ajoute à la perception visuelle du graphique.
La version modernisée propose également des paramètres permettant de synchroniser les données de prix à temps avec la substitution des prix manquants aux prix prioritaires.
Le type modernisé de construction de graphiques est présenté à la fig. 2:
Fig.2 Graphique modifié basé sur quatre types de prix
Comme la construction modernisée combine quatre graphiques à trois sauts de ligne de différents types de prix, il est naturel de trouver des écarts entre les prix. Pour l’éviter, la synchronisation des données à temps est nécessaire. La synchronisation des prix a été réalisée en deux variantes : complète (fig. 2 à droite) et partielle (fig. 2 à gauche). La synchronisation complète représente une synchronisation partielle filtrée, où toutes les données sont dessinées sur le graphique et les données manquantes sont remplacées par les prix de priorité spécifiés dans les paramètres. Dans le mode de synchronisation complète, les données manquantes sont simplement omises et seuls les chandeliers avec un ensemble complet de données sont dessinés.
Une autre innovation est un séparateur de période, introduit pour la commodité des signaux de fractionnement. Comme vous le savez bien, le séparateur de période peut être activé dans les paramètres du graphique. Dans l’indicateur, ils changent en fonction de la période, spécifiée dans les paramètres. Contrairement aux graphiques https://www.metatrader5.com/enMetaTrader 5, où les périodes sont séparées par une ligne pointillée verticale, dans cet indicateur, une nouvelle période est représentée en changeant une couleur de ligne (chandelles, fig. 3):
Fig.3 Séparateurs de période dans l’indicateur
Un autre ajout est la mise en œuvre d’un indicateur technique iMA, qui est construit sur la base des prix du graphique principal, mais est synchronisé avec les données de l’indicateur à temps. Ainsi, les données sont filtrées par la moyenne mobile (fig. 4) :
Fig.4 Moyenne mobile interne
L’indicateur dispose également d’une fonction permettant de définir un mouvement minimum en points pour tracer une ligne et le nombre de lignes requises pour une inversion. Il a également un rôle de filtre.
Code de l’indicateur
L’algorithme de l’indicateur est plutôt simple et comporte trois étapes : copie des données, calcul basé sur les données copiées et remplissage des tampons de l’indicateur (construction d’un graphique basé sur les données reçues). Le code est divisé en fonctions qui sont interconnectées entre elles ou avec les données d’entrée. Examinons de près le code.
1. Paramètres d'entrée du script
Le préambule de l’indicateur contient une déclaration de constructions graphiques. Il y en a deux dans l’indicateur: le graphique « ABCTB » (DRAW_COLOR_CANDLES) et la moyenne mobile supplémentaire « LINE_TLB » (DRAW_LINE). En conséquence, il y a six tampons. Suivent ensuite les données de type enum pour améliorer les paramètres de l’interface et les paramètres eux-mêmes:
- magic_numb - Le nombre magique a le type long. C’est un nombre unique pour désigner l’indicateur. Si la nécessité s’en fait sentir, peut être converti en chaîne de type avec quelques modifications ;
- time_frame - Plage de temps de calcul, type ENUM_TIMEFRAMES, est le paramètre principal (la période de l’indicateur) ;
- time_redraw - Période de mise à jour du graphique, tapez ENUM_TIMEFRAMES. Il s’agit de la période pendant laquelle un nouveau calcul graphique a lieu. Pour un redécoupage rapide du graphique, appuyez sur la touche « R » du clavier - un contrôle intégré de l’indicateur;
- first_date_start - Date de début, tapez datetime. C’est le paramètre principal qui est le point de départ de la copie des données et de la cartographie ;
- chart_price - Type de prix pour le calcul (0-Close, 1-Ouvert, 2-Haut, 3-Bas). Pour une construction graphique classique, un type de prix doit être sélectionné. Comme déjà mentionné, ce paramètre est ignoré lorsque la construction modifiée est activée ;
- step_min_f - Pas minimum pour une nouvelle colonne (>0, tapez int) ou un saut requis pour tracer une ligne ;
- line_to_back_f - Nombre de lignes pour afficher une inversion (>0, tapez int). Le type classique suggère trois lignes pour montrer un renversement ;
- chart_type - Type de construction de graphique (0-classique, 1-modifié), tapez sélectionner. Il s’agit d’un changement entre les types de construction ;
- chart_color_period - Modification de la couleur lors du démarrage d’une nouvelle période (type booléen). Utilisé pour changer la couleur de la ligne au début d’une nouvelle période ;
- chart_synchronization - Construction d’un graphique uniquement une fois la synchronisation terminée (tapezbooléen, si vrai, une synchronisation complète se produit avec la suppression de toutes les valeurs manquantes avant la construction d’un graphique) ;
- chart_priority_close - Priorité du cours de fermeture (tapez sélectionner, a quatre variantes. Il pointe vers la priorité du cours de fermeture à la synchronisation partielle et est ignoré à la synchronisation complète ;
- chart_priority_open - Priorité du prix d’ouverture. Il en va de même ici ;
- chart_priority_high - Priorité du prix maximum. Il en va de même ici ;
- chart_priority_low - Priorité du prix minimum. Il en va de même ici ;
- ma_draw - Dessinez la moyenne (tapezbooléen, si vrai, puis dessinez la moyennemobile) ;
- ma_price - Type de prix pour la construction de la moyenne, peut être l’un de ENUM_APPLIED_PRICE;
- ma_method - Type de construction, peut être l’un de ENUM_MA_METHOD;
- ma_period - Période de calcul de la moyennemobile ;
Ensuite, nous déclarons les tableaux tampons, les variables et les structures nécessaires au calcul.
//+------------------------------------------------------------------+ //| 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. Fonction OnInit
Tous les tampons indicateurs sont déclarés dans la fonction OnInit et l’indication de tableau est configurée comme dans une série chronologique.
Ensuite, nous définissons les valeurs de l’indicateur qui ne seront pas reflétées sur le graphique, définissons le nom,, spécifions la précision et supprimons les valeurs actuelles car elles surchargent le graphique. Ici, nous définissons également la poignée de l’indicateur iMA et vérifions l’exactitude des données saisies. En cas d’erreur, un message approprié est imprimé et la valeur est modifiée au minimum.
//+------------------------------------------------------------------+ //| 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. Fonction de copie de données
Comme l’indicateur est conçu pour fonctionner avec les quatre types de prix, il est essentiel de copier toutes les données, y compris le temps. Dans MQL5, il existe une structure nommée MqlRates. Il est utilisé pour stocker des informations sur l’heure du début d’une session de trading, les prix, les volumes et la marge.
Les paramètres d’entrée de la fonction sont la date de début et de fin, la période et le tableau cible du type MqlRates. La fonction renvoie vrai si la copie réussit. Les données sont copiées dans un tableau intermédiaire. Les données manquantes calculées plus une session y sont copiées et les données sont renouvelées en permanence. Si la copie dans le tableau intermédiaire a réussi, les données sont copiées dans le tableau, transmises pour garantir le bon fonctionnement de la fonction.
//+------------------------------------------------------------------+ //| 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. Fonction de calcul des données
Cette fonction est un prototype de calcul de données pour une construction classique du graphique à trois sauts de ligne. Comme déjà mentionné, la fonction calcule uniquement les données et les forme dans un tableau spécial du type de structure line_info, déclaré au début du code.
Cette fonction contient deux autres fonctions : func_regrouping (fonction de regroupement) et func_insert (fonction d’insertion). Pour commencer, nous allons les examiner :
4.1. Fonction de regroupement
Cette fonction regroupe des informations sur des lignes consécutives de la même direction. Il est limité par la taille du tableau qui y est passé ou, pour être précis, par le paramètre line_to_back_f (nombre de lignes pour afficher une inversion) des paramètres de l’indicateur. Ainsi, chaque fois que le contrôle est transféré à la fonction, toutes les données reçues sur des lignes identiques se déplacent d’un point vers le bas à la fin et l’index 0 est rempli par une nouvelle valeur.
C’est ainsi que les informations sur les lignes requises pour une pause sont stockées (dans le cas d’une construction classique, la rupture comporte trois lignes).
//+------------------------------------------------------------------+ // 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. Fonction d’insertion
La fonction effectue l’insertion des valeurs dans le tableau de réponses. Le code est simple et ne nécessite pas d’explication détaillée.
//+------------------------------------------------------------------+ // 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 fonction de calcul des données était classiquement divisée en trois parties. La première partie copie les données en cours d’analyse sur un réseau intermédiaire à l’aide de la touchede l’opérateur. Seul le prix concerné est copié. La deuxième partie effectue une série de tests pour calculer l’espace requis dans le tableau de données. Ensuite, le tableau de données line_main_array[], initialement transmis à la fonction pour réponse, subit une modification. La troisième partie, à son tour, remplit le tableau de données ajusté.
//+------------------------------------------------------------------+ //| 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. Fonction de construction de graphique
Le but de cette fonction est de calculer les données d’un graphique en fonction du paramètre de construction sélectionné (classique ou modifié) et de remplir le tampon de l’indicateur avec des données à afficher. En plus de la fonction précédente, la fonction de construction de graphiques a trois fonctions supplémentaires. Ce sont la fonction de couleur, la fonction de synchronisation et la fonction de la moyenne mobile. Discutons-en plus en détail.
5.1. Fonction de couleur
Cette fonction n’a qu’un seul paramètre d’entrée - le temps. La réponse de la fonction est une variable booléenne. Si les données transmises sont la bordure de la période, la fonction renvoie vraie. Comme les périodes dépendent de la période sélectionnée, la fonction a une séparation de période intégrée par l’opérateur conditionnel si. Une fois la période sélectionnée, elle fait l’objet d’une vérification si une nouvelle période a déjà commencé. Cela se fait en convertissant une date en structure MqlDateTime et en comparaison. Pour la période allant jusqu’à H2 inclus, les changements dans la valeur de la date indiquent le début d’une nouvelle période. Les périodes de H12 à D1 inclus indiquent les changements en mois et entre W1 et MN, nous vérifions le changement dans l’année.
Malheureusement, la structure MqlDateTime ne contient pas d’informations sur la semaine en cours. Ce problème a été résolu en créant un point initial représenté par la variable time_variable. Plus loin sur la ligne, un nombre de secondes dans une semaine est déduit de cette date.
//+------------------------------------------------------------------+ // 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. Fonction de synchronisation
La fonction de synchronisation comporte six paramètres d’entrée : quatre d’entre eux sont la priorité des prix, le paramètre booléen de synchronisation complète ou partielle et le tableau en cours d’analyse lui-même. La fonction est divisée en deux parties : un cas de synchronisation complète et partielle.
La synchronisation complète s’effectue en trois étapes :
- Calcul des éléments du tableau, satisfaisant à la condition de contenir des données sur les quatre types de prix.
- Copie d’éléments dans un tableau intermédiaire dans les mêmes conditions.
- Copie du tableau intermédiaire vers celui transmis par les paramètres.
La synchronisation partielle est plus complexe.
Le tableau de structure unidimensionnelle passé est converti en un tableau bidimensionnel, où le premier indice indique l’ordre et le second - le type de prix. Ensuite, introduit est un tableau unidimensionnel avec quatre éléments. Les niveaux de priorité de prix sont copiés dans ce tableau, puis le tableau est trié pour identifier l’ordre de priorité. Après cela, nous effectuons la distribution en fonction des priorités en utilisant la boucle pour et l’opérateur conditionnel si. Dans le même temps, si les priorités sont égales, la séquence des prix est la suivante: fermer, ouvrir, haut, bas. Dès que l’opérateur trouve la première valeur hiérarchisée, la boucle remplace toutes les données nulles du tableau bidimensionnel créé précédemment par les données prioritaires, etc.
//+------------------------------------------------------------------+ // 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. Fonction de la moyenne mobile
C’est la fonction la plus simple. En utilisant la poignée d’indicateur, reçue dans la fonction OnInit, nous copions la valeur, correspondant à la date passée dans les paramètres de la fonction. Ensuite, cette valeur est renvoyée en réponse à cette fonction.
//+------------------------------------------------------------------+ // Func MA | //+------------------------------------------------------------------+ double func_ma(datetime date) { double x[1]; CopyBuffer(handle,0,date,1,x); return(x[0]); }
La fonction de traçage d’un graphique est classiquement divisée en deux parties: le tracé classique et le tracé modifié. La fonction a deux paramètres d’entrée: le type de prix pour la construction (ignoré lors de la construction modifiée) et le type de construction (classique et modifié).
Au tout début, les tampons indicateurs sont nettoyés puis, selon le type de construction, divisés en deux parties. La première partie (nous parlons de la construction modifiée) commence par appeler la fonction de calcul des quatre types de prix. Ensuite, nous créons un tableau de données commun où nous copions les données utilisées, reçues lors de l’appel de la fonction de calcul des données. Ensuite, le tableau de données reçues est trié et effacé des données répliquées. Après cela, le tableau data_for_buffer[], déclaré au niveau global, est rempli en fonction de dates consécutives avec la synchronisation des données suivante. Le remplissage des tampons indicateurs est la dernière étape de la construction modifiée.
La deuxième partie (construction classique) est beaucoup plus simple. Au début, la fonction de calcul des données est appelée, puis les tampons d’indicateurs sont remplis.
//+------------------------------------------------------------------+ //| 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. Fonction de consolidation
Cette fonction unit tous les éléments indicateurs de contrôle. Au début, la date actuelle est définie, puis la fonction de copie des données et la fonction de construction de graphique sont appelées.
//+------------------------------------------------------------------+ //| 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. Fonction de construction contrôlée par clé et automatiquement
Ces fonctions sont conçues pour un redécoupage de l’indicateur en appuyant sur la touche « R » (OnChartEvent) du clavier ou en le faisant automatiquement en fonction de la plage de temps sélectionnée (OnCalculate). Cette dernière est analysée par la nouvelle fonction barre (func_new_bar) qui est une version simplifiée de la fonction décrite dans 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); }
À ce stade, nous allons terminer la description du code de l’indicateur et parler des façons de l’utiliser.
Exemples d’utilisation de l’indicateur et d’une stratégie de trading
Commençons par les principales stratégies d’analyse basées sur la construction graphique classique.
1. les lignes blanches et noires comme signaux d’achat et de vente
En gros, nous pouvons parler de deux règles:
- Règle N°1: Acheter, quand il y a trois lignes ascendantes consécutives et vendre, quand il y a trois lignes descendantes consécutives. Trois lignes consécutives indiquent une tendance à apparaître.
- Règle N°2: Vendre, lorsque la ligne d’inversion tombe en dessous de trois lignes ascendantes consécutives, acheter, lorsque la ligne d’inversion est supérieure à trois lignes descendantes consécutives.
Regardons la fig.6, représentant une construction classique pour EURUSD H1 en début de 2013 (la plage de temps analysée est illustrée à la fig.5).
Fig.5 Plage de temps analysée EURUSD H1
Fig.6 Construction classique du graphique à trois sauts de ligne pour EURUSD H1, début 2013, cours de fermeture
Sur le graphique (fig. 6), nous pouvons clairement voir le signal (règle N° 1) entre les points 1 et 2, qui est un point de départ pour la vente. Dans ce cas, le gain est supérieur à 200 points pour quatre chiffres décimaux. Le point 4 suivant indique une situation favorable à l’achat (comme dans la règle N° 2). À la fermeture au point 5, le bénéfice était de 40 points et nous sommes au seuil de rentabilité à la fermeture au point 6.
Au point 6, nous pouvons voir un signal de vente (règle N° 2). Nous obtenons 10 points de profit lors de la fermeture au point 7 et le seuil de rentabilité à la fermeture au point 8. Les points 8 et 9 ne peuvent être considérés comme des signaux car ils ne satisfont ni à la règle N° 1, ni à la règle N° 2. Nous pouvons acheter au point 10 (règle N° 1); nous pouvons également obtenir un bénéfice de 20 points à la clôture au point 11 ou au seuil de rentabilité au point 12. Tous les chiffres ont été arrondis.
Dans le meilleur des cas, en utilisant cette stratégie, nous pourrions générer un profit de 270 points, ce qui est impressionnant. Dans le même temps, dans la plage de temps spécifiée, il y a un mouvement intense qui affecte le profit. Dans le pire des cas, le trading peut entraîner un seuil de rentabilité, ce qui n’est pas mal non plus.
Il convient de mentionner que lorsqu’une situation répond à la règle N° 1 ou à la règle N° 2, nous devons attendre une confirmation d’inversion de tendance représentée par une ligne dans la même direction que la tendance.
2. Canal équidistant, support et lignes résistantes
Une autre stratégie de trading consiste à appliquer une analyse technique au graphique à trois sauts de ligne. Jetons un coup d’œil à la fig. 7:
Fig. 7 Canal équidistant, support et lignes résistantes, GBPUSD H1, plage de temps du 01.03.2014 au 01.05.2014
Dans la Fig. 7, vous pouvez voir que le canal équidistant descendant est dessiné en lignes rouges, le canal ascendant est dessiné en bleu et les lignes de support et de résistance sont dessinées en noir. Il est clair que la première ligne de résistance se transforme en ligne de support.
3. Motifs de chandeliers
Un graphique modifié (deux sauts de ligne) sur la période M30 pour la paire USDCAD au début de 2013 semble plutôt intéressant.
On peut distinguer les motifs de chandeliers japonais qui justifiaient leurs signaux (fig. 8).
Fig. 8 Graphique à trois sauts de ligne modifié, USDCAD M30, début 2013, deux sauts de ligne
Au début du graphique, nous pouvons voir un modèle d’inversion de « Engloutissement » sous le N° 1. Il se compose de deux chandelles: rouge et la précédente bleue. Après la ligne de tendance à la hausse, le marché descend au numéro 2 qui est un motif d’inversion à une chandelle « Marteau ». À ce stade, le marché change de direction. La même chose se produit dans le modèle No3 (« La toupie »). Le motif d’inversion suivant « Kharami » (No4) est représenté par le chandelier 4 et le grand ascendant à côté. Le motif No6 se compose également de deux chandeliers (motif « Engulfing ») mais contrairement au premier modèle similaire, il fait tourner le marché dans la direction opposée.
Ainsi, on peut conclure que l’utilisation de l’indicateur dans ce type d’analyse est acceptable, mais qu’elle présente des inconvénients tels que l’apparition rare de signaux et la possibilité d’un retrait significatif. Cette stratégie doit certainement être approfondie.
4. Moyenne mobile
Une modification partielle, comme l’ajout d’une moyenne mobile uniquement aux lignes tracées, offre de nouvelles possibilités d’analyse.
Regardons la fig. 9:
Fig.9 Analyse de la moyenne mobile, EURUSD H4, le graphique à trois sauts de ligne, construction classique, du 01.01.2014 au 01.07.2014
La partie supérieure de la fig. 9 illustre une construction classique basée sur les prix élevés avec une moyenne mobile (la période de moyenne est de 90, le prix bas, la moyenne lissée). La partie inférieure montre une construction classique basée sur des prix bas avec une moyenne mobile (la période moyenne est de 90, le prix élevé, la moyenne lissée).
Ainsi, dans la partie supérieure de la fig. 9, la moyenne mobile peut être considérée comme une ligne de support et dans la partie inférieure, au contraire, une ligne de résistance. Si le prix sur les deux graphiques tombe en dessous de la moyenne, il y a une tendance à la baisse sur le marché et il est préférable de vendre. Lorsque le prix dépasse la moyenne, il est temps d’acheter. Un inconvénient de cette stratégie est qu’elle est destinée à un trading à long terme.
Conclusion
En conclusion, je peux dire que le trois sauts de ligne donne constamment de bons signaux ou, dans le pire des cas, conduit à l’équilibre. La pratique montre qu’il est préférable de l’appliquer dans une tendance à long terme et, par conséquent, je ne recommande pas d’utiliser ce graphique pour un trading à court terme. Si quelqu’un a de nouvelles idées sur la façon de l’utiliser dans le trading, je serais heureux d’en discuter.
Comme d’habitude, j’ai essayé d’explorer le code en détail. Encore une fois, s’il y a des idées sur la façon de l’étendre, de le retravailler ou de l’optimiser, veuillez écrire dans les commentaires de l’article.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/902
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation