
Modèles prêts à l'emploi pour inclure des indicateurs dans les Expert Advisors (Partie 3) : Indicateurs de tendance
Sommaire
- Introduction
- Moyenne Mobile Adaptative
- Average Directional Movement Index
- Average Directional Movement Index Wilder
- Bandes de Bollinger®
- Moyenne Mobile Exponentielle Double
- Enveloppes
- Moyenne Mobile Adaptative Fractale
- Ichimoku Kinko Hyo
- Moyenne Mobile
- SAR Parabolique
- Écart-type (Standard Deviation)
- Moyenne Mobile Exponentielle Triple
- Variable Index Dynamic Average
- Conclusion
Introduction
L'article poursuit le thème des modèles prêts à l'emploi pour l'utilisation d'indicateurs dans les EA. Nous avons déjà examiné les modèles permettant de connecter les oscillateurs et les indicateurs de volume et de Bill Williams aux EA.
Nous nous intéresserons ici à la connexion aux EA et à l'utilisation des indicateurs de tendance. Comme dans les articles précédents, nous afficherons les données reçues des indicateurs sur le tableau de bord créé dans le premier article de cette série.
L'article ne diffère en rien des précédents en termes de présentation : une brève vue d'ensemble de chaque indicateur de tendance et des codes concis pour la connexion et l'utilisation des indicateurs dans les EA.
L'article présentera des modèles prêts à l'emploi à utiliser dans des programmes personnalisés pour chaque indicateur :
- Variables d'entrée et variables globales.
- Initialisation des variables et création d'une poignée sur l’indicateur.
- Dé-initialisation.
- Récupération des données de l'indicateur dans l'EA.
- Exemple d'affichage des données obtenues sur le tableau de bord.
L'article permet de copier-coller les codes.
Moyenne Mobile Adaptative
L'indicateur technique Adaptive Moving Average (AMA), Moyenne Mobile Adaptative en français, est utilisé pour construire une moyenne mobile peu sensible aux bruits de la série de prix et se caractérise par un décalage minimal pour la détection de la tendance. Cet indicateur a été développé et décrit par Perry Kaufman dans son livre "Smarter Trading".
L'un des inconvénients des différents algorithmes de lissage pour les séries de prix est que des sauts de prix accidentels peuvent entraîner l'apparition de faux signaux de tendance. Le lissage entraîne également le décalage inévitable d'un signal d'arrêt ou de changement de tendance. Cet indicateur a été développé pour éliminer ces deux inconvénients.
Paramètres
La fonction iAMA() est utilisée pour créer la poignée de l'indicateur :
Retourne le handle de l'indicateur de Moyenne Mobile Adaptative. Un seul buffer.
int iAMA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ama_period, // AMA period int fast_ma_period, // fast Moving Average period int slow_ma_period, // slow Moving Average period int ama_shift, // horizontal shift of the indicator ENUM_APPLIED_PRICE applied_price // price type or handle );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ama_period
[in] Période de calcul du taux d'efficacité.
fast_ma_period
[in] Période rapide pour le calcul du taux de lissage lorsque le marché évolue rapidement.
slow_ma_period
[in] Période lente pour le calcul du taux de lissage en l'absence de tendance.
ama_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendAMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 9; /* Period */ input uint InpPeriodFast = 2; /* Fast EMA Period*/ input uint InpPeriodSlow = 30; /* Slow EMA Period*/ input int InpShift = 0; /* AMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // AMA calculation period int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
L'énumération ENUM_LINE_STATE a été créée pour simplifier l'obtention de l'état d'une ligne d'indicateur - sa forme et sa position par rapport à la ligne d'un autre indicateur ou d'un autre niveau.
Pour en savoir plus sur l'énumération, consultez l'article sur les oscillateurs dans la section des paramètres de l'indicateur ATR.
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendAMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 9; /* Period */ input uint InpPeriodFast = 2; /* Fast EMA Period*/ input uint InpPeriodSlow = 30; /* Slow EMA Period*/ input int InpShift = 0; /* AMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // AMA calculation period int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 9 : InpPeriod); period_fast=int(InpPeriodFast<1 ? 2 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 30 : InpPeriodSlow); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("AMA(%lu,%lu,%lu)",period,period_fast,period_slow); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iAMA(Symbol(),PERIOD_CURRENT,period,period_fast,period_slow,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 9 : InpPeriod); period_fast=int(InpPeriodFast<1 ? 2 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 30 : InpPeriodSlow); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("AMA(%lu,%lu,%lu)",period,period_fast,period_slow); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iAMA(Symbol(),PERIOD_CURRENT,period,period_fast,period_slow,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Les fonctions générales permettant d'obtenir des données à l'aide de la poignée de l'indicateur sont présentées ci-dessous. Les fonctions ont été passées en revue dans l'article sur la connexion des oscillateurs aux EA. Les fonctions présentées peuvent être utilisées "telles quelles" dans des programmes personnalisés :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter le test EA TestTrendAMA.mq5 dans les fichiers joints à l'article.
Average Directional Movement Index
Le Average Directional Movement Index (ADX), ou indice de mouvement directionnel, permet de déterminer s'il existe une tendance des prix. Il a été développé et décrit en détail par Welles Wilder dans son livre "New concepts in technical trading systems".
La méthode de trading la plus simple basée sur le système de mouvement directionnel implique la comparaison de deux indicateurs de direction : l'indicateur +DI à 14 périodes et l'indicateur -DI à 14 périodes. Pour cela, soit on superpose les graphiques des indicateurs, soit on soustrait +DI de -DI. W. Wilder recommande d'acheter lorsque le +DI est supérieur au -DI, et de vendre lorsque le +DI est inférieur au -DI.
À ces règles simples de trading, Wells Wilder a ajouté "une règle des points extrêmes". Il est utilisé pour éliminer les faux signaux et réduire le nombre de transactions. Selon le principe des points d'extremum, le "point d'extremum" est le point où +DI et -DI se croisent. Si le +DI est plus élevé que le -DI, ce point sera le prix maximum de la journée lorsqu'ils se croiseront. Si +DI est inférieur à -DI, ce point sera le prix minimum du jour où ils se croisent.
Le point d'extremum est alors utilisé comme niveau d'entrée du marché. Ainsi, après le signal d'achat (+DI est supérieur à -DI), il faut attendre que le prix ait dépassé le point d'extremum, et seulement ensuite acheter. Mais si le prix ne parvient pas à dépasser le niveau du point de l'extremum, il convient de conserver la position courte.
Paramètres
La fonction iADX() est utilisée pour créer le handle de l'indicateur :
Retourne la poignée de l'indicateur Average Directional Movement Index.
int iADX( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int adx_period // averaging period );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
adx_period
[in] Période de calcul de l'indice.
Index des buffers : 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendADX.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ADX calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendADX.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ADX calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ADX(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iADX(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ADX(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iADX(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the ADX line data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,MAIN_LINE); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the +DI line data from the specified bar on the panel in table 1 panel.DrawText("+DI", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double value_dip=IndicatorValue(handle,index,PLUSDI_LINE); string value_dip_str=(value_dip!=EMPTY_VALUE ? DoubleToString(value_dip,ind_digits) : ""); panel.DrawText(value_dip_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,100); //--- Display the -DI line data from the specified bar on the panel in table 1 panel.DrawText("-DI", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); double value_dim=IndicatorValue(handle,index,MINUSDI_LINE); string value_dim_str=(value_dim!=EMPTY_VALUE ? DoubleToString(value_dim,ind_digits) : ""); panel.DrawText(value_dim_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clrNONE,100); //--- Display a description of +DI and -DI lines ratio panel.DrawText("+DI vs -DI", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state=LineStateRelative(handle,index,1,value_dim,IndicatorValue(handle,index+1,2)); string state_di_str=LineStateDescription(state); color clr=clrNONE; if(state==LINE_STATE_ABOVE) { state_di_str="+DI > -DI"; clr=clrGreen; } if(state==LINE_STATE_CROSS_UP) clr=clrGreen; if(state==LINE_STATE_UNDER) { state_di_str="+DI < -DI"; clr=clrRed; } if(state==LINE_STATE_CROSS_DOWN) clr=clrRed; panel.DrawText(state_di_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
En plus de ces lignes d'indicateur, le panneau affiche une description de la relation entre les lignes +DI et -DI, qui sont essentiellement des lignes de signal de l'indicateur.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendADX.mq5 dans les fichiers joints à l'article.
Average Directional Movement Index Wilder
Le Average Directional Movement Index Wilder (ADX Wilder), ou indice de mouvement directionnel de Wilder, permet de déterminer s'il existe une tendance des prix. Cet indicateur technique est construit en stricte correspondance avec l'algorithme décrit par Welles Wilder dans son livre "New concepts in technical trading systems".
Les règles de trading pour cet indicateur sont décrites dans la section Average Directional Movement Index.
Paramètres
La fonction iADXWilder() est utilisée pour créer la poignée de l'indicateur :
Return the handle of the Average Directional Movement Index by Welles Wilder. int iADXWilder( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int adx_period // averaging period );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
adx_period
[in] Période de calcul de l'indice.
Index des buffers : 0 - MAIN_LINE, 1 - PLUSDI_LINE, 2 - MINUSDI_LINE.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendADXWilder.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ADX Wilder calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendADXWilder.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ADX Wilder calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ADX Wilder(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iADXWilder(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ADX Wilder(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iADXWilder(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the ADX line data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,MAIN_LINE); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the +DI line data from the specified bar on the panel in table 1 panel.DrawText("+DI", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double value_dip=IndicatorValue(handle,index,PLUSDI_LINE); string value_dip_str=(value_dip!=EMPTY_VALUE ? DoubleToString(value_dip,ind_digits) : ""); panel.DrawText(value_dip_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,100); //--- Display the -DI line data from the specified bar on the panel in table 1 panel.DrawText("-DI", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); double value_dim=IndicatorValue(handle,index,MINUSDI_LINE); string value_dim_str=(value_dim!=EMPTY_VALUE ? DoubleToString(value_dim,ind_digits) : ""); panel.DrawText(value_dim_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clrNONE,100); //--- Display a description of +DI and -DI lines ratio panel.DrawText("+DI vs -DI", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state=LineStateRelative(handle,index,1,value_dim,IndicatorValue(handle,index+1,2)); string state_di_str=LineStateDescription(state); color clr=clrNONE; if(state==LINE_STATE_ABOVE) { state_di_str="+DI > -DI"; clr=clrGreen; } if(state==LINE_STATE_CROSS_UP) clr=clrGreen; if(state==LINE_STATE_UNDER) { state_di_str="+DI < -DI"; clr=clrRed; } if(state==LINE_STATE_CROSS_DOWN) clr=clrRed; panel.DrawText(state_di_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Le panneau affiche les données des lignes de l'indicateur et la description de la relation entre les lignes +DI et -DI, qui sont essentiellement des lignes de signal de l'indicateur.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendADXWilder.mq5 dans les fichiers joints à l'article.
Bandes de Bollinger®
Les Bandes de Bollinger (BB) sont similaires au Envelopes. La seule différence est que les bandes d'enveloppes sont tracées à une distance fixe (%) de la moyenne mobile, alors que les Bandes de Bollinger sont tracées à un certain nombre d'écarts types de celle-ci. L'écart-type (standard deviation en anglais) est une mesure de la volatilité, c'est pourquoi les Bandes de Bollinger s'adaptent aux conditions du marché. Lorsque les marchés deviennent plus volatils, les bandes s'élargissent et elles se contractent pendant les périodes moins volatiles.
Les Bandes de Bollinger sont généralement tracées sur le graphique des prix, mais elles peuvent également être ajoutées au graphique de l'indicateur. Tout comme pour les Envelopes, l'interprétation des Bandes de Bollinger est basée sur le fait que les prix ont tendance à rester entre la ligne supérieure et la ligne inférieure des bandes. L'indicateur de la Bande de Bollinger se distingue par sa largeur variable due à la volatilité des prix. En période de fortes variations de prix (c'est-à-dire de forte volatilité), les bandes s'élargissent, ce qui laisse une grande marge de manœuvre aux prix. Pendant les périodes de statu quo, ou les périodes de faible volatilité, les bandes se contractent en maintenant les prix dans leurs limites.
Les caractéristiques suivantes sont propres aux Bandes de Bollinger :
- Les changements brusques de prix ont tendance à se produire après la contraction des bandes, en raison de la diminution de la volatilité ;
- si les prix franchissent la bande supérieure, on peut s'attendre à une poursuite de la tendance actuelle ;
- si les pics et les creux à l'extérieur de la bande sont suivis par des pics et des creux à l'intérieur de la bande, un renversement de tendance peut se produire ;
- le mouvement de prix qui a commencé à partir de l'une des lignes de la bande atteint généralement la ligne opposée.
La dernière observation est utile pour les prévisions de prix.
Paramètres
La fonction iBands() est utilisée pour créer le handle de l'indicateur :
Retourne une poignée sur l'indicateur des Bandes de Bollinger®.
int iBands( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int bands_period, // central line calculation period int bands_shift, // horizontal shift of the indicator double deviation, // number of standard deviations ENUM_APPLIED_PRICE applied_price // price type or handle );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
bands_period
[in] Période de calcul de la moyenne de la ligne principale de l'indicateur.
bands_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
deviation
[in] Déviation par rapport à la ligne principale.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Index des buffers : 0 - BASE_LINE, 1 - UPPER_BAND, 2 - LOWER_BAND
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendBands.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 20; /* Period */ input double InpDeviation= 2.0; /* Deviation */ input int InpShift = 0; /* Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bollinger Bands calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendBands.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 20; /* Period */ input double InpDeviation= 2.0; /* Deviation */ input int InpShift = 0; /* Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bollinger Bands calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 20 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bands(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBands(Symbol(),PERIOD_CURRENT,period,InpShift,InpDeviation,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 20 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bands(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBands(Symbol(),PERIOD_CURRENT,period,InpShift,InpDeviation,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,225,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,110); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,110); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the Bands Upper line data from the specified bar on the panel in table 1 panel.DrawText(ind_title+" Upper", panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,UPPER_BAND); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the Bands Lower line data from the specified bar on the panel in table 1 panel.DrawText(ind_title+" Lower", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double value_dip=IndicatorValue(handle,index,LOWER_BAND); string value_dip_str=(value_dip!=EMPTY_VALUE ? DoubleToString(value_dip,ind_digits) : ""); panel.DrawText(value_dip_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,100); //--- Display the Bands Middle line data from the specified bar on the panel in table 1 panel.DrawText(ind_title+" Middle", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); double value_dim=IndicatorValue(handle,index,BASE_LINE); string value_dim_str=(value_dim!=EMPTY_VALUE ? DoubleToString(value_dim,ind_digits) : ""); panel.DrawText(value_dim_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clrNONE,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendBands.mq5 dans les fichiers joints à l'article.
Moyenne Mobile Exponentielle Double
La Moyenne Mobile Exponentielle Double (DEMA) a été développée par Patrick Mulloy et publiée en février 1994 dans le magazine "Technical Analysis of Stocks & Commodities". Elle est utilisée pour lisser les séries de prix et est appliquée directement sur un graphique de prix d'un titre financier. Elle peut également être utilisée pour lisser les valeurs d'autres indicateurs.
L'avantage de cet indicateur est qu'il élimine les faux signaux lors des mouvements de prix en dents de scie et permet de conserver une position lors d'une tendance forte.
Paramètres
La fonction iDEMA() est utilisée pour créer la poignée de l'indicateur :
Retourne le handle de l'indicateur Double Exponential Moving Average. Un seul buffer.
int iDEMA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // averaging period int ma_shift, // horizontal shift of the indicator ENUM_APPLIED_PRICE applied_price // price type or handle );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période (nombre de barres) pour le calcul de l'indicateur.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendDEMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input int InpShift = 0; /* DEMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // DEMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendDEMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input int InpShift = 0; /* DEMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // DEMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("DEMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iDEMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("DEMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iDEMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez voir l'EA de test TestTrendDEMA.mq5 dans les fichiers joints à l'article.
Enveloppes
L'indicateur technique Envelopes (Envelopes) est formé de 2 moyennes mobiles, dont l'une est décalée vers le haut et l'autre vers le bas. Le choix du nombre relatif optimal de décalage des bandes est déterminé par la volatilité du marché : plus celle-ci est élevée, plus le décalage est important.
Les enveloppes définissent les marges supérieure et inférieure de la fourchette de prix. Le signal de vente apparaît lorsque le prix atteint la marge supérieure de la bande ; le signal d'achat apparaît lorsque le prix atteint la marge inférieure.
La logique qui sous-tend les enveloppes est que les acheteurs et les vendeurs trop zélés poussent les prix vers les extrêmes (c'est-à-dire les bandes supérieure et inférieure), après quoi les prix se stabilisent souvent en passant à des niveaux plus réalistes. Ceci est similaire à l'interprétation des Bandes de Bollinger® (BB).
Paramètres
La fonction iEnvelopes() est utilisée pour créer la poignée de l'indicateur :
Retourne un handle sur l’indicateur Envelopes.
int iEnvelopes( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // central line calculation period int ma_shift, // horizontal shift of the indicator ENUM_MA_METHOD ma_method, // smoothing type ENUM_APPLIED_PRICE applied_price, // price type or handle double deviation // deviation of channel borders from the central line );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période de calcul de la moyenne de la ligne principale de l'indicateur.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
ma_method
[in] Méthode de calcul de la moyenne. Toute valeur de l'énumération ENUM_MA_METHOD.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
deviation
[in] Pourcentage de déviation par rapport à la ligne principale.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Index des buffers : 0 - UPPER_LINE, 1 - LOWER_LINE.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendEnvelopes.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpDeviation= 0.1; /* Deviation */ input int InpShift = 0; /* Shift */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Envelopes calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendEnvelopes.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpDeviation= 0.1; /* Deviation */ input int InpShift = 0; /* Shift */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Envelopes calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Envelopes(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iEnvelopes(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice,InpDeviation); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Envelopes(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iEnvelopes(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice,InpDeviation); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,257,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,126); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,126); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the Envelopes Upper line data from the specified bar on the panel in table 1 panel.DrawText(ind_title+" Upper", panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,UPPER_LINE); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the Envelopes Lower line data from the specified bar on the panel in table 1 panel.DrawText(ind_title+" Lower", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double value_dip=IndicatorValue(handle,index,LOWER_LINE); string value_dip_str=(value_dip!=EMPTY_VALUE ? DoubleToString(value_dip,ind_digits) : ""); panel.DrawText(value_dip_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendEnvelopes.mq5 dans les fichiers joints à l'article.
Moyenne Mobile Adaptative Fractale
La Moyenne Mobile Adaptative Fractale, ou Fractal Adaptive Moving Average (FRAMA), a été développée par John Ehlers. Cet indicateur est construit sur la base de l'algorithme de la moyenne mobile exponentielle, où le facteur de lissage est calculé sur la base de la dimension fractale actuelle de la fourchette de prix. L'indicateur FRAMA suit les mouvements de forte tendance et ralentit considérablement lors de la consolidation des prix.
Tous les types d'analyse utilisés pour travailler avec les moyennes mobiles peuvent également être appliqués à cet indicateur.
Paramètres
La fonction iFrAMA() est utilisée pour créer la poignée de l'indicateur :
Retourne le handle de l'indicateur Fractal Adaptive Moving Average. Un seul buffer.
int iFrAMA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // averaging period int ma_shift, // horizontal shift of the indicator ENUM_APPLIED_PRICE applied_price // price type or handle );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période (nombre de barres) pour le calcul de l'indicateur.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendFRAMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input int InpShift = 0; /* FRAMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // FRAMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendFRAMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input int InpShift = 0; /* FRAMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // FRAMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("FRAMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iFrAMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("FRAMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iFrAMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendFRAMA.mq5 dans les fichiers joints à l'article.
Ichimoku Kinko Hyo
L'indicateur technique Ichimoku Kinko Hyo est prédéfini pour caractériser la tendance du marché, les niveaux de support et de résistance, et pour générer des signaux d'achat et de vente. Cet indicateur fonctionne mieux sur les graphiques hebdomadaires et journaliers.
Lors de la définition de la dimension des paramètres, 4 intervalles de temps de longueur différente sont utilisés. Les valeurs des lignes individuelles composant cet indicateur sont basées sur ces intervalles :
- Tenkan-sen indique la valeur moyenne du prix pendant le premier intervalle de temps défini comme la somme du maximum et du minimum pendant cette période, divisée par 2 ;
- Kijun-sen indique la valeur moyenne du prix au cours du deuxième intervalle de temps ;
- Senkou Span A montre le milieu de la distance entre deux lignes précédentes décalé vers l'avant par la valeur du deuxième intervalle de temps ;
- Senkou Span B montre la valeur moyenne du prix pendant le troisième intervalle de temps décalé vers l'avant par la valeur du deuxième intervalle de temps.
Chikou Span montre le prix de clôture de la bougie actuelle décalé vers l'arrière par la valeur du deuxième intervalle de temps. La distance entre les lignes Senkou est hachurée d'une autre couleur et appelée "nuage". Si le prix se situe entre ces lignes, le marché doit être considéré comme sans tendance, et les marges du nuage forment alors les niveaux de support et de résistance.
- Si le prix est au-dessus du nuage, sa ligne supérieure forme le premier niveau de support, et la deuxième ligne forme le deuxième niveau de support ;
- Si le prix est inférieur au nuage, la ligne inférieure forme le premier niveau de résistance, et la ligne supérieure le deuxième niveau ;
- Si la ligne Chikou Span traverse le graphique de prix dans la direction du bas vers le haut, c'est un signal d'achat. Si la ligne Chikou Span traverse le graphique dans le sens descendant, il s'agit d'un signal de vente.
Le Kijun-sen est utilisé comme indicateur de l'évolution du marché. Si le prix est supérieur à cet indicateur, il est probable que les prix continueront à augmenter. Lorsque le prix traverse cette ligne, un nouveau changement de tendance est possible. Une autre façon d'utiliser le Kijun-sen est de donner des signaux. Le signal d'achat est généré lorsque la ligne Tenkan-sen croise la ligne Kijun-sen en haut. L'orientation descendante est le signal de vente. Le Tenkan-sen est utilisé comme indicateur de la tendance du marché. Si cette ligne augmente ou diminue, la tendance existe. Lorsqu'il passe à l'horizontale, cela signifie que le marché est entré dans le canal.
Paramètres
La fonction iIchimoku() est utilisée pour créer le handle de l'indicateur :
Renvoie le handle de l'indicateur Ichimoku Kinko Hyo.
int iIchimoku( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int tenkan_sen, // Tenkan-sen period int kijun_sen, // Kijun-sen period int senkou_span_b // Senkou Span B period );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
tenkan_sen
[in] Période de calcul de la moyenne de Tenkan Sen.
kijun_sen
[in] Période de calcul de la moyenne de Kijun Sen.
senkou_span_b
[in] Période de calcul de la moyenne de Senkou Span B.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Index des buffers : 0 - TENKANSEN_LINE, 1 - KIJUNSEN_LINE, 2 - SENKOUSPANA_LINE, 3 - SENKOUSPANB_LINE, 4 - CHIKOUSPAN_LINE.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendIchimoku.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodTenkan= 9; /* Tenkan-sen */ input uint InpPeriodKijun = 26; /* Kijun-sen */ input uint InpPeriodSpanB = 52; /* Senkou Span B */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_tenkan=0; // Tenkan-sen line calculation period int period_kijun=0; // Kijun-sen line calculation period int period_spanb=0; // Senkou Span B line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendIchimoku.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodTenkan= 9; /* Tenkan-sen */ input uint InpPeriodKijun = 26; /* Kijun-sen */ input uint InpPeriodSpanB = 52; /* Senkou Span B */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_tenkan=0; // Tenkan-sen line calculation period int period_kijun=0; // Kijun-sen line calculation period int period_spanb=0; // Senkou Span B line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_tenkan=int(InpPeriodTenkan<1 ? 9 : InpPeriodTenkan); period_kijun=int(InpPeriodKijun<1 ? 26 : InpPeriodKijun); period_spanb=int(InpPeriodSpanB<1 ? 52 : InpPeriodSpanB); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Ichimoku Kinko Hyo (%lu,%lu,%lu)",period_tenkan,period_kijun,period_spanb); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iIchimoku(Symbol(),PERIOD_CURRENT,period_tenkan,period_kijun,period_spanb); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_tenkan=int(InpPeriodTenkan<1 ? 9 : InpPeriodTenkan); period_kijun=int(InpPeriodKijun<1 ? 26 : InpPeriodKijun); period_spanb=int(InpPeriodSpanB<1 ? 52 : InpPeriodSpanB); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Ichimoku Kinko Hyo (%lu,%lu,%lu)",period_tenkan,period_kijun,period_spanb); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iIchimoku(Symbol(),PERIOD_CURRENT,period_tenkan,period_kijun,period_spanb); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,261); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,5,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Get the indicator buffers data double tenkan=IndicatorValue(handle,index,TENKANSEN_LINE); // Tenkan Sen line double kijun =IndicatorValue(handle,index,KIJUNSEN_LINE); // Kijun Sen line double spana =IndicatorValue(handle,index,SENKOUSPANA_LINE); // Senkou Span A line double spanb =IndicatorValue(handle,index,SENKOUSPANB_LINE); // Senkou Span B line double chikou=IndicatorValue(handle,index,CHIKOUSPAN_LINE); // Chikou Span line color clr=clrNONE; //--- Display the Tenkan Sen line data from the specified bar on the panel in table 1 string tenkan_str=StringFormat("Tenkan-sen(%lu)",period_tenkan); panel.DrawText(tenkan_str, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); string value_str=(tenkan!=EMPTY_VALUE ? DoubleToString(tenkan,ind_digits) : " "); ENUM_LINE_STATE state_tenkan=LineStateRelative(handle,index,TENKANSEN_LINE,kijun,IndicatorValue(handle,index+1,KIJUNSEN_LINE)); clr=(state_tenkan==LINE_STATE_CROSS_UP ? clrBlue : state_tenkan==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clr,100); //--- Display the Kijun Sen line data from the specified bar on the panel in table 1 string kijun_str=StringFormat("Kijun-sen(%lu)",period_kijun); panel.DrawText(kijun_str, panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); value_str=(kijun!=EMPTY_VALUE ? DoubleToString(kijun,ind_digits) : " "); ENUM_LINE_STATE state_kijun=LineState(handle,index,KIJUNSEN_LINE); clr= ( state_kijun==LINE_STATE_UP || state_kijun==LINE_STATE_TURN_UP ? clrBlue : state_kijun==LINE_STATE_DOWN || state_kijun==LINE_STATE_TURN_DOWN ? clrRed : clrNONE ); panel.DrawText(value_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100); //--- Display the Senkou Span A line data from the specified bar on the panel in table 1 panel.DrawText("Senkou Span A", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); value_str=(spana!=EMPTY_VALUE ? DoubleToString(spana,ind_digits) : " "); panel.DrawText(value_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clrNONE,100); //--- Display the Senkou Span B line data from the specified bar on the panel in table 1 string spanb_str=StringFormat("Senkou Span B(%lu)",period_spanb); panel.DrawText(spanb_str, panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); value_str=(spanb!=EMPTY_VALUE ? DoubleToString(spanb,ind_digits) : " "); panel.DrawText(value_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clrNONE,100); //--- Display the Chikou Span line data from the specified bar on the panel in table 1 panel.DrawText("Chikou Span", panel.CellX(1,4,0)+2, panel.CellY(1,4,0)+2); value_str=(chikou!=EMPTY_VALUE ? DoubleToString(chikou,ind_digits) : " "); panel.DrawText(value_str,panel.CellX(1,4,1)+2,panel.CellY(1,4,1)+2,clrNONE,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
La couleur des valeurs des lignes Tenkan-sen et Kijun-sen dépend de leur position relative et de leur direction.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA test TestTrendIchimoku.mq5 dans les fichiers joints à l'article.
Moyenne Mobile
La Moyenne Mobile (MA) indique la valeur moyenne du prix de l'instrument pour une certaine période de temps. Lorsque l'on calcule la moyenne mobile, on calcule la moyenne du prix de l'instrument pour cette période. Lorsque le prix varie, la moyenne mobile augmente ou diminue.
Il existe 4 types différents de moyennes mobiles : simple (également appelée arithmétique), exponentielle, lissée et pondérée. La moyenne mobile peut être calculée pour n'importe quel ensemble de données séquentielles, y compris les prix d'ouverture et de clôture, les prix les plus élevés et les plus bas, le volume des transactions ou tout autre indicateur. C'est souvent le cas lorsque des moyennes mobiles doubles sont utilisées.
Les moyennes mobiles de différents types ne divergent considérablement les unes des autres que lorsque les coefficients de pondération, qui sont attribués aux données les plus récentes, sont différents. Dans le cas de la Moyenne Mobile Simple, tous les prix de la période en question ont le même poids. La Moyenne Mobile Exponentielle et la Moyenne Mobile Pondérée Linéairement donnent plus de poids aux prix les plus récents.
La façon la plus courante d'interpréter la moyenne mobile des prix est de comparer sa dynamique à l'action des prix. Lorsque le prix de l'instrument passe au-dessus de sa moyenne mobile, un signal d'achat apparaît. Si le prix passe en dessous de sa moyenne mobile, il s'agit d'un signal de vente.
Ce système de trading, basé sur la moyenne mobile, n'est pas conçu pour entrer sur le marché au moment où il est le plus bas et pour en sortir au moment où il est le plus haut. Il permet d'agir selon la tendance suivante : acheter peu après que les prix ont atteint leur niveau le plus bas, et vendre peu après que les prix ont atteint leur niveau le plus élevé.
Les moyennes mobiles peuvent également être appliquées aux indicateurs. C'est là que l'interprétation des moyennes mobiles des indicateurs est similaire à celle des moyennes mobiles des prix : si l'indicateur passe au-dessus de sa moyenne mobile, cela signifie que le mouvement ascendant de l'indicateur est susceptible de se poursuivre ; si l'indicateur passe en dessous de sa moyenne mobile, cela signifie qu'il est susceptible de poursuivre son mouvement descendant.
Voici les types de moyennes mobiles sur le graphique :
- Moyenne Mobile Simple (SMA)
- Moyenne Mobile Exponentielle (EMA)
- Moyenne Mobile Lissée (SMMA)
- Moyenne Mobile Pondérée Linéaire (MMPL)
Paramètres
La fonction iMA() est utilisée pour créer la poignée de l'indicateur :
Return moving average indicator handle. Only one buffer. int iMA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // averaging period int ma_shift, // horizontal shift of the indicator ENUM_MA_METHOD ma_method, // smoothing type ENUM_APPLIED_PRICE applied_price // price type or handle );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période de calcul de la moyenne mobile.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
ma_method
[in] Méthode de calcul de la moyenne. Peut avoir n'importe quelle valeur de l'énumération ENUM_MA_METHOD.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 10; /* Period */ input int InpShift = 0; /* MA Shift */ input ENUM_MA_METHOD InpMethod= MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // MA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 10; /* Period */ input int InpShift = 0; /* MA Shift */ input ENUM_MA_METHOD InpMethod= MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // MA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 10 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("MA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 10 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("MA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Le panneau affiche les valeurs de l'indicateur et l'état de sa ligne.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendMA.mq5 dans les fichiers joints à l'article.
SAR Parabolique
Le Parabolic SAR a été développé pour analyser les marchés en tendance. L'indicateur est construit sur le graphique des prix. Cet indicateur est similaire à la Moyenne Mobile à la seule différence que le Parabolic SAR se déplace avec une plus grande accélération et peut changer sa position en termes de prix. L'indicateur se situe en dessous des prix lorsque le marché est haussier (tendance haussière), et au-dessus des prix lorsque le marché est baissier (tendance baissière).
Si le prix franchit la ligne SAR parabolique, l'indicateur se retourne et ses valeurs suivantes se situent de l'autre côté du prix. Lorsqu'un tel changement d'indicateur a lieu, le prix maximum ou minimum de la période précédente sert de point de départ. Lorsque l'indicateur effectue un virage, il donne un signal de fin de tendance (phase de correction ou plat), ou de virage.
Le SAR Parabolique est un indicateur remarquable pour fournir des points de sortie. Les positions longues doivent être fermées lorsque le prix descend en dessous de la ligne du SAR, et les positions courtes doivent être fermées lorsque le prix monte au-dessus de la ligne du SAR. En d'autres termes, il est nécessaire de suivre la direction du SAR Parabolique et de ne garder ouvertes que les positions qui sont dans la même direction. L'indicateur est souvent utilisé comme ligne de stop suiveur.
Si la position longue est ouverte (c'est-à-dire que le prix est au-dessus de la ligne du SAR), la ligne du SAR Parabolique montera, quelle que soit la direction prise par les prix. L'ampleur du mouvement de la ligne du SAR Parabolique dépend de la valeur du mouvement du prix.
Paramètres
La fonction iSAR() est utilisée pour créer la poignée de l'indicateur :
Retourne la poignée sur l’indicateur du système Parabolic Stop and Reverse. Un seul buffer.
int iSAR( string symbol, // symbol name ENUM_TIMEFRAMES period, // period double step, // price change step — acceleration factor double maximum // maximum step );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
step
[in ] Le pas de changement de prix, généralement 0,02.
maximum
[in] Le pas maximum, généralement 0,2.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendSAR.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input double InpStep = 0.02; /* Step */ input double InpMax = 0.2; /* Maximum */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // MA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendSAR.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input double InpStep = 0.02; /* Step */ input double InpMax = 0.2; /* Maximum */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // MA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set the indicator name and the number of decimal places ind_title=StringFormat("SAR(%.2f,%.2f)",InpStep,InpMax); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iSAR(Symbol(),PERIOD_CURRENT,InpStep,InpMax); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set the indicator name and the number of decimal places ind_title=StringFormat("SAR(%.2f,%.2f)",InpStep,InpMax); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iSAR(Symbol(),PERIOD_CURRENT,InpStep,InpMax); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the header of the indicator line state description panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); //--- Save Close value on 'index' bar to the variable double close0=rates[0].close; //--- If failed to get bar data by index+1, leave if(CopyRates(Symbol(),PERIOD_CURRENT,index+1,1,rates)!=1) return; //--- Save Close value on 'index+1' bar to the variable and get the indicator value on 'index+1' bar double close1=rates[0].close; double value1=IndicatorValue(handle,index+1,0); //--- Get and adjust the state of the indicator line ENUM_LINE_STATE state=LineState(handle,index,0); if(value<close0 && value1>close1) state=LINE_STATE_TURN_UP; if(state==LINE_STATE_STOP_DOWN) state=LINE_STATE_UP; if(value>close0 && value1<close1) state=LINE_STATE_TURN_DOWN; if(state==LINE_STATE_STOP_UP) state=LINE_STATE_DOWN; //--- Display a description of the indicator line state panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendSAR.mq5 dans les fichiers joints à l'article.
Écart-type (Standard Deviation)
L’Ecart-Type, ou Standard Deviation en anglais (StdDev), mesure la volatilité du marché. Cet indicateur décrit l'amplitude des fluctuations de prix par rapport à la Moyenne Mobile. Si la valeur de cet indicateur est élevée, le marché est donc volatile et les prix des barres sont plutôt étalés par rapport à la moyenne mobile. Si la valeur de l'indicateur est faible, le marché peut être décrit comme ayant une faible volatilité, et les prix des barres sont plutôt proches de la moyenne mobile.
Normalement, cet indicateur est utilisé comme élément constitutif d'autres indicateurs. Par exemple, lors du calcul des Bandes de Bollinger®, la valeur de l'écart-type du symbole est ajoutée à sa moyenne mobile.
La dynamique du marché est représentée par l'alternance de périodes de faible et de forte activité, de sorte que l'approche de cet indicateur est simple :
- si sa valeur est trop faible, c'est-à-dire si le marché est absolument inactif, il est logique de s'attendre à un pic à brève échéance ;
- sinon, s'il est extrêmement élevé, cela signifie très probablement que l'activité va bientôt diminuer.

Paramètres
La fonction iStdDev() est utilisée pour créer la poignée de l'indicateur :
Retourne la poignée de l'indicateur d'écart-type. Un seul buffer.
int iStdDev( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // averaging period int ma_shift, // horizontal shift of the indicator ENUM_MA_METHOD ma_method, // smoothing type ENUM_APPLIED_PRICE applied_price // price type or handle );
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période de calcul de la moyenne de l'indicateur.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
ma_method
[in] Méthode de calcul de la moyenne. Peut avoir n'importe quelle valeur de l'énumération ENUM_MA_METHOD.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendStdDev.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 20; /* Period */ input int InpShift = 0; /* StdDev Shift */ input ENUM_MA_METHOD InpMethod= MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Standard Deviation calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendStdDev.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 20; /* Period */ input int InpShift = 0; /* StdDev Shift */ input ENUM_MA_METHOD InpMethod= MODE_SMA; /* Method */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Standard Deviation calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 20 : InpPeriod<2 ? 2 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("StdDev(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iStdDev(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 20 : InpPeriod<2 ? 2 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("StdDev(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iStdDev(Symbol(),PERIOD_CURRENT,period,InpShift,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Le panneau affiche la valeur de la ligne indicatrice et son état.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter le test EA TestTrendStdDev.mq5 dans les fichiers joints à l'article.
Moyenne Mobile Exponentielle Triple
La Moyenne Mobile Exponentielle Triple, ou Triple Exponential Moving Average en anglais (TEMA), a été développée par Patrick Mulloy et publiée dans le magazine "Technical Analysis of Stocks & Commodities". Ses principes de calcul sont similaires à ceux de la DEMA (Double Exponential Moving Average). Le nom "Triple Exponential Moving Average" ne reflète pas très correctement son algorithme. Il s'agit d'un mélange unique de moyennes mobiles exponentielles simples, doubles et triples, offrant moins de latence que l'une ou l'autre seule.
La TEMA peut être utilisée à la place des moyennes mobiles traditionnelles. Elle peut être utilisée pour lisser les données sur les prix, ainsi que pour lisser d'autres indicateurs.
Paramètres
La fonction iTEMA() est utilisée pour créer la poignée de l'indicateur :
Retourne le handle de l'indicateur Triple Exponential Moving Average. Un seul buffer.
int iTEMA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int ma_period, // averaging period int ma_shift, // horizontal shift of the indicator ENUM_APPLIED_PRICE applied_price // price type or handle );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
ma_period
[in] Période (nombre de barres) pour le calcul de l'indicateur.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendTEMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input int InpShift = 0; /* TEMA Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Triple Exponential Moving Average calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendTEMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input int InpShift = 0; /* StdDev Shift */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Triple Exponential Moving Average calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("TEMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iTEMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("TEMA(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iTEMA(Symbol(),PERIOD_CURRENT,period,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Le panneau affiche les valeurs de la ligne d'indicateur et son état.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA de test TestTrendTEMA.mq5 dans les fichiers joints à l'article.
Variable Index Dynamic Average
Le Variable Index Dynamic Average (VIDYA) a été développé par Tushar Chande. Il s'agit d'une méthode originale de calcul de la Moyenne Mobile Exponentielle (EMA) avec une période de calcul de la moyenne qui change dynamiquement. La période de calcul de la moyenne dépend de la volatilité du marché ; le Chande Momentum Oscillator (CMO) a été choisi comme mesure de la volatilité. Cet oscillateur mesure le rapport entre la somme des incréments positifs et la somme des incréments négatifs pendant une certaine période (période CMO). La valeur du CMO est utilisée comme rapport pour le facteur de lissage de l’EMA. L'indicateur VIDYA dispose donc de 2 paramètres : la période de l'oscillateur CMO et la période de lissage de la moyenne mobile exponentielle (période de l’EMA).
Paramètres
La fonction iVIDyA() est utilisée pour créer la poignée de l'indicateur :
Renvoie le handle de l'indicateur Variable Index Dynamic Average. Un seul buffer.
int iVIDyA( string symbol, // symbol name ENUM_TIMEFRAMES period, // period int cmo_period, // Chande Momentum period int ema_period, // smoothing factor period int ma_shift, // horizontal shift of the indicator ENUM_APPLIED_PRICE applied_price // price type or handle );
symbol
[in] Le nom du symbole de l'instrument financier dont les données doivent être utilisées pour calculer l'indicateur. NULL signifie le symbole actuel.
period
[in] La valeur de la période peut être l'une des valeurs de l'énumération ENUM_TIMEFRAMES, 0 signifiant la période actuelle.
cmo_period
[in] Période (nombre de barres) pour le calcul du Chande Momentum Oscillator.
ema_period
[in] Période de l’EMA (nombre de barres) pour le calcul du facteur de lissage.
ma_shift
[in] Décalage de l'indicateur par rapport au graphique des prix.
applied_price
[in] Prix appliqué. Une des constantes de prix ENUM_APPLIED_PRICE ou un autre indicateur.
Renvoie le handle de l'indicateur technique spécifié. En cas d'échec, la fonction renvoie INVALID_HANDLE. Pour libérer la mémoire de l'ordinateur d'un indicateur inutilisé, utilisez la fonction IndicatorRelease() à laquelle le gestionnaire de l'indicateur est passé.
Déclarez les variables d'entrée et les variables globales dans l'EA pour créer l'indicateur :
//+------------------------------------------------------------------+ //| TestTrendVIDYA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodCMO= 9; /* CMO Period */ input int InpShift = 0; /* VIDYA Shift */ input uint InpPeriodEMA= 12; /* EMA Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_cmo=0; // CMO calculation period int period_ema=0; // EMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
Lorsque vous utilisez le tableau de bord dans l'EA, déclarez des variables globales et incluez le fichier de classe du panneau :
//+------------------------------------------------------------------+ //| TestTrendVIDYA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodCMO= 9; /* CMO Period */ input int InpShift = 0; /* VIDYA Shift */ input uint InpPeriodEMA= 12; /* EMA Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_cmo=0; // CMO calculation period int period_ema=0; // EMA calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
Initialisation
Définition des valeurs des variables globales de l'indicateur et création de son handle :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period_cmo=int(InpPeriodCMO<1 ? 9 : InpPeriodCMO); period_ema=int(InpPeriodEMA<1 ? 12 : InpPeriodEMA); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("VIDYA(%lu,%lu)",period_cmo,period_ema); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iVIDyA(Symbol(),PERIOD_CURRENT,period_cmo,period_ema,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
Si l'EA implique l'utilisation du tableau de bord, nous devons le créer :
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period_cmo=int(InpPeriodCMO<1 ? 9 : InpPeriodCMO); period_ema=int(InpPeriodEMA<1 ? 12 : InpPeriodEMA); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("VIDYA(%lu,%lu)",period_cmo,period_ema); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iVIDyA(Symbol(),PERIOD_CURRENT,period_cmo,period_ema,InpShift,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,197,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,96); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,96); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
Dé-initialisation
Relâchez la poignée de l'indicateur dans la fonction OnDeinit() de l’EA :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
L'objet tableau de bord créé est supprimé lors de l'utilisation du tableau de bord :
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
Récupération des résultats
Fonctions générales pour l'obtention de données par la poignée de l'indicateur :
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
Lors de l'utilisation du tableau de bord, les données sont affichées sur le panneau à l'aide de la fonction :
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
Le panneau affiche les valeurs de la ligne d'indicateur et son état.
Lors de l'utilisation du tableau de bord, le gestionnaire d'événements du tableau de bord est également appelé dans le gestionnaire d'événements OnChartEvent() de l’EA, où sont gérés les événements de réception de l'indice de la barre sous le curseur :
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
Après avoir compilé l'EA et l'avoir lancé sur le graphique, nous pouvons surveiller l'état de la valeur et de la ligne de l'indicateur sur le panneau :
Vous pouvez consulter l'EA test TestTrendVIDYA.mq5 dans les fichiers joints à l'article.
Conclusion
Nous avons examiné tous les types d'indicateurs techniques disponibles dans le terminal MetaTrader 5, ainsi que leur connexion avec les indicateurs et les EA, et la récupération des données. La question de l'utilisation d'indicateurs multi-symboles et multi-périodes dans les EA et les indicateurs reste ouverte. Le prochain article sera consacré à la création d'outils permettant de connecter des indicateurs multi-symboles et multi-périodes à des EA et des indicateurs, ainsi que de recevoir des données et des signaux de leur part.
Vous pouvez copier tous les codes ci-dessus "tels quels" et les utiliser dans vos développements. Toutes les EA de test considérés sont attachés ci-dessous.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/13406
Avertissement: Tous les droits sur ces documents sont réservés par MetaQuotes Ltd. La copie ou la réimpression de ces documents, en tout ou en partie, est interdite.
Cet article a été rédigé par un utilisateur du site et reflète ses opinions personnelles. MetaQuotes Ltd n'est pas responsable de l'exactitude des informations présentées, ni des conséquences découlant de l'utilisation des solutions, stratégies ou recommandations décrites.





- 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
Nouvel article Modèles d'indicateurs prêts à l'emploi pour le trading d'EA (partie 3) : les indicateurs de tendance ont été publiés :
Par Artyom Trishkin