Showing posts with label Signal calculation. Show all posts
Showing posts with label Signal calculation. Show all posts

Sunday, August 10, 2025

1. Introduction

The Commodity Channel Index Multi-Timeframe (CCI MTF) Indicator for MetaTrader 5 provides a comprehensive and compact way to read CCI momentum across all 21 standard timeframes (from M1 to MN1) on a single chart. Instead of switching charts and guessing whether shorter- or longer-term momentum supports your idea, this indicator calculates CCI on each timeframe independently and summarizes directional momentum with per-timeframe arrows plus a majority-based summary signal.

Each arrow corresponds to the directional assessment of the CCI for a particular timeframe:

  • 🟢 Green Arrow = Bullish momentum (CCI moving upward)
  • 🔴 Red Arrow = Bearish momentum (CCI moving downward)
  • Gold/Neutral Arrow = Neutral / weak/no dominant momentum

🚀 This tool is ideal for multi-timeframe traders, scalpers, and swing traders who want fast visual confirmation across the full timeframe (21 timeframes) spectrum before pulling the trigger.

2. About This Indicator

The Commodity Channel Index Multi-Timeframe Indicator for MT5 (CCI_MTF) utilizes a template and displays a panel on the chart.

Its function, operation, and usage are identical to the On Balance Volume Multi-Timeframe Indicator for MT5 (OBV_MTF) as detailed in the previous article. For a comprehensive guide on creating a multi-timeframe indicator, you can refer to the following resources: On Balance Volume Multi-Timeframe Indicator for MT5

🔁 Note: All multi-timeframe indicators developed by Forex Home Expert use this exact signal logic programs structure.

CCI_MTF

3. Key Features

✅ Full 21-timeframe CCI scanning (M1 → MN1) in one indicator.
✅ Per-timeframe arrow overlays for quick visual scanning.
✅ Majority-based summary signal that reduces noise (summary arrow appears when up > down + 1 or down > up + 1).
✅ Customizable parameters: CCI calculation period (BarCalc), arrow colors, fonts.
✅ On-screen alerts + optional email and push notifications.
✅ Lightweight and optimized for MT5 — uses indicator handles (iCCI) and CopyBuffer for efficient buffer reading.
✅ Non-repainting behavior — uses closed bar data via CopyBuffer() for stable historical signals.
✅ Graphical Interface Panel for Timeframe Switching (via `OnChartEvent`)

4. How It Works (Behind the Scenes)

Commodity Channel Index (CCI) in a Nutshell

CCI is a momentum oscillator that measures the difference between a typical price and its moving average, normalized by mean absolute deviation. Common interpretation:

  • CCI > +100 → strong bullish momentum / overbought region
  • CCI < -100 → strong bearish momentum / oversold region

5. Multi-Timeframe Signal Logic

The indicator operates in two main steps:

  1. Create a handle for the CCI on each timeframe using iCCI() and keep those handles in an array (one per timeframe).
  2. For each bar the indicator examines, read the most recent closed CCI value(s) using CopyBuffer() and determine whether the CCI is rising or falling on that timeframe. Count the timeframes that are rising (up) vs falling (down). When the count for one direction exceeds the other by more than one (up > down + 1 or down > up + 1) a summary arrow is shown.

6. Relevant Code Snippets

Technical Overview: How the Indicator Works


//--
enum YN
  {
   No,
   Yes
  };
//--
enum fonts
  {
   Verdana,
   Bodoni_MT_Black
  };
//--
//-- Input Parameter
//---
input group   "====  Indicator Period Calculation  ===="
input int                BarCalc = 14;                // Input Indicator Period
input group   "====  Indicator Color and Font   ===="
input color              ArrowUp = clrMediumSeaGreen; // Arrow Up Color
input color              ArrowDn = clrDeepPink;       // Arrow Down Color
input color              NTArrow = clrGold;           // Arrow No Signal
input fonts              f_model = Bodoni_MT_Black;   // Select Font Model
input group   "====  Input parameters for alerts  ===="
input YN                  alerts = Yes;               // Display Alerts Pop-up on Chart (Yes) or (No)
input YN           UseEmailAlert = No;                // Email Alert (Yes) or (No)
input YN           UseSendnotify = No;                // Send Notification (Yes) or (No)
//---

Timeframe Management

The indicator prepares and manages handles for all standard MT5 timeframes:


   virtual void      CCI_MTF_Config(void)
     {
      //--
      ENUM_TIMEFRAMES TFIx[]= {PERIOD_M1,PERIOD_M2,PERIOD_M3,PERIOD_M4,PERIOD_M5,PERIOD_M6,PERIOD_M10,PERIOD_M12,PERIOD_M15,
                               PERIOD_M20,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,
                               PERIOD_D1,PERIOD_W1,PERIOD_MN1};
      tfxar=ArraySize(TFIx);
      ArrayResize(TFId,tfxar,tfxar);
      ArrayResize(Arwcolor,tfxar,tfxar);
      ArrayCopy(TFId,TFIx,0,0,WHOLE_ARRAY);
      //--
      string TFxc[]= {"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1",                   "H2","H3","H4","H6","H8","H12","D1","W1","MN1"}; // 21 Timeframes
      //--
      ArrayResize(hCCI,tfxar,tfxar);
      ArrayResize(TFSc,tfxar,tfxar);
      ArrayCopy(TFSc,TFxc,0,0,WHOLE_ARRAY);
      //--
      if(BarCalc<1)
        {
         CCI_period=14;
         PrintFormat("Incorrect value for input variable BarCalc = %d. Indicator will use value %d for calculations.",
                  BarCalc,CCI_period);
        }
      else
         CCI_period=BarCalc;
      //--
      ttlbars=BarCalc*3+3;
      //--
      for(int x=0; x<tfxar; x++)
        hCCI[x]=iCCI(Symbol(),TFId[x],CCI_period,PRICE_TYPICAL); // Handle of iCCI Indicator on each timeframe
      //--
      DeletedCCIObject();
      CCIMovementCalculation(25);
      PositionCore();
      //--
      if(display)
         DrawCCIObject();
      //---
     }
   //---

Signal Extraction Logic

Each timeframe is scanned using:


   //---
   //---
   int               CCIDirectionScan(const ENUM_TIMEFRAMES stf,int shift) // Scan OBV Direction
     {
      //--
      int ret=0;
      int rise=1,
          down=-1;
      //--
      int br=shift+2;
      double res=0.0;
      UpdatePrice(stf);
      //--
      double CCI[];
      ArrayResize(CCI,br,br);
      ArraySetAsSeries(CCI,true);
      //--
      int xx=TFIndexArray(stf);
      CopyBuffer(hCCI[xx],0,0,br,CCI);
      //--
      if(CCI[shift]>CCI[shift+1]) ret=rise;
      if(CCI[shift]<CCI[shift+1]) ret=down;
      //--
      return(ret);
      //---
     } //-end CCIDirectionScan()
   //---

Consensus Calculation Logic.


   //---
   void              CCIMovementCalculation(int barCnt) // Scan the direction of iCCI on each timeframe
     {
      //--
      ArrayResize(PowerMove,barCnt,barCnt);
      ArraySetAsSeries(PowerMove,true);
      //--
      for(int i=barCnt-1; i>=0; i--)
        {
         up=0;
         dw=0;
         //--
         for(int x=0; x<tfxar; x++)
           {
            Arwcolor[x]=NTArrow;
            PowerMove[i]=0.0;
            int PPM=CCIDirectionScan(TFId[x],0);
            if(PPM>0)
              {
               up++;
               Arwcolor[x]=ArrowUp;
              }
            if(PPM<0)
              {
               dw++;
               Arwcolor[x]=ArrowDn;
              }
            if(x==tfxar-1)
              {
               if(up>dw+1)
                 {
                  PowerMove[i]=1.0;
                  TColor=ArrowUp;
                  curAlert=1;
                 }
               if(dw>up+1)
                 {
                  PowerMove[i]=-1.0;
                  TColor=ArrowDn;
                  curAlert=-1;
                 }
              }
           }
        }
      //--
      return;
      //---
     } //-end CCIMovementCalculation()
   //---
/*
This logic ensures that only dominant directional consensus (not slight differences) triggers a clear summary signal.
*/

Indicator signal calculation starts from OnCalculate(...)


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ResetLastError();
   //--
   int limit;
   limit=rates_total-prev_calculated;
   if(prev_calculated>0)
      limit++;
   if(limit>mi.ttlbars)
      limit=mi.ttlbars;
   if(limit-3<=1)
      limit=3;
   //--
   mi.CCIMovementCalculation(limit);
   //--
   if(alerts==Yes||UseEmailAlert==Yes||UseSendnotify==Yes)
     {
       mi.curmin=mi.ThisTime(mi.min);
       if(mi.curmin!=mi.prvmin && mi.curAlert==1 && mi.curAlert!=mi.prvAlert)
         {
           string AlertTxt="The strength of the CCI movement appears to be Rise.";
           mi.Do_Alerts(AlertTxt);
           mi.prvAlert=mi.curAlert;
           mi.prvmin=mi.curmin;
         }
       if(mi.curmin!=mi.prvmin && mi.curAlert==-1 && mi.curAlert!=mi.prvAlert)
         {
           string AlertTxt="The strength of the CCI movement appears to be Down.";
           mi.Do_Alerts(AlertTxt);
           mi.prvAlert=mi.curAlert;
           mi.prvmin=mi.curmin;
         }
     }
   //--
   if(mi.display)
     mi.DrawCCIObject();
   //---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//---------//

Function DrawCCIObject() – Drawing multi-timeframe CCI results.


   //---
   void              DrawCCIObject(void)
     {
      //--
CreateButtonTemplate(CI,ObjName+"Template",397,66,STYLE_SOLID,9,BORDER_RAISED,clrMistyRose,clrLavenderBlush,clrWhite,bcor,corx,cory,true);
      for(int x=0; x<tfhalf; x++)
        {
         CreateArrowLabel(CI,ObjName+"_win_arrow_"+string(x),CharToString((uchar)windchar),"Wingdings",windsize,Arwcolor[x],bcor,
                             txttf+horizL1+(x*scaleX)+offsetX+x,vertiL1,true,"Arrow_"+TFSc[x]);
         CreateButtonClick(CI,TFSc[x],27,15,font_mode,fontSize,BORDER_FLAT,TFSc[x],clrBurlyWood,clrSilver,clrBlue,
                              bcor,txttf+horizL2+(x*scaleA)+offsetX,vertiL2,true,
                              "Change Timeframe to : "+TFSc[x]);
        }
      for(int x=tfhalf, x2=0; x<tfxar; x++, x2++)
        {
         CreateArrowLabel(CI,ObjName+"_win_arrow_"+string(x),CharToString((uchar)windchar),"Wingdings",windsize,Arwcolor[x],bcor,
                             txttf+horizL3+(x2*scaleX)+offsetX+x2,vertiL3,true,"Arrow_"+TFSc[x]);
         CreateButtonClick(CI,TFSc[x],27,15,font_mode,fontSize,BORDER_FLAT,TFSc[x],clrBurlyWood,clrSilver,clrBlue,
                              bcor,txttf+horizL4+(x2*scaleA)+offsetX,vertiL4,true,
                              "Change Timeframe to : "+TFSc[x]);
         //--
         if(x==20)
           {
            int arrowChar=TColor==ArrowUp ? 200 : TColor==ArrowDn ? 202 : windchar;
            CreateArrowLabel(CI,ObjName+"_tfx_arrow_"+string(x+1),"Move",font_mode,fontSize,clrBlue,bcor,
                                519+horizL5,vertiL5,true,"Move");
            CreateArrowLabel(CI,ObjName+"_win_arrow_"+string(x+1),CharToString((uchar)arrowChar),"Wingdings",15,TColor,bcor,
                                522+horizL6,vertiL6,true,"Arrow Indicator Movement");
           }
        }
      DisplayButtonClick("X");
      CreateButtonTemplate(CI,ObjName+"TemplateName1",17,15,STYLE_SOLID,1,BORDER_FLAT,clrMistyRose,clrLavenderBlush,clrWhite,bcor,TNamex,TNamey1,true);
      CreateButtonTemplate(CI,ObjName+"TemplateName2",17,15,STYLE_SOLID,1,BORDER_FLAT,clrMistyRose,clrLavenderBlush,clrWhite,bcor,TNamex,TNamey2,true);
      CreateButtonTemplate(CI,ObjName+"TemplateName3",17,15,STYLE_SOLID,1,BORDER_FLAT,clrMistyRose,clrLavenderBlush,clrWhite,bcor,TNamex,TNamey3,true);
      CreateArrowLabel(CI,ObjName+"_name1",hName1,font_mode,fontSize+1,clrBlue,bcor,TNamexn,TNamey1n,true,hName1);
      CreateArrowLabel(CI,ObjName+"_name2",hName2,font_mode,fontSize+1,clrBlue,bcor,TNamexn,TNamey2n,true,hName2);
      CreateArrowLabel(CI,ObjName+"_name3",hName3,font_mode,fontSize+1,clrBlue,bcor,TNamexn,TNamey3n,true,hName3);
      //--
      if(corpos==postop)
        {
          DisplayButtonClick("cstar");
          DisplayButtonClick("arbot");
        }
      if(corpos==posbot)
        {
          DisplayButtonClick("cstar");
          DisplayButtonClick("artop");
        }
      //--
      return;
      //---
     } //-end DrawCCIObject()
   //---
 //- This function is responsible for creating labels on the chart for each timeframe, with colors according to Overbought (green), Oversold (red), or No Signal (gold) Neutral conditions.

Dynamic Timeframe Panel OnChartEvent() Fuction

The indicator creates a clickable panel on the chart containing labels for all 21 timeframes. When a label (e.g., "H4") is clicked, the internal reference timeframe for analysis is updated, and the timeframe is changed to H4.

This makes it easy for the user to interact with the indicator dynamically.


//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
//--
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- if "X" button is click
      if(sparam=="X")
        {
         mi.DeletedCCIObject();
         //--- unpress the button
         ObjectSetInteger(mi.CI,"X",OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,"X",OBJPROP_ZORDER,0);
         //--
         mi.display=false;
         ObjectDelete(mi.CI,"X");
         mi.DisplayPanelButton();
        }
      //--- if "cstar" button is click
      if(sparam==mi.cstar)
        {
         mi.DeletedCCIObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         if(mi.corpos==mi.posbot) ObjectDelete(mi.CI,mi.arbot);
         if(mi.corpos==mi.postop) ObjectDelete(mi.CI,mi.artop);
         mi.DrawCCIObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "artop" button is click
      if(sparam==mi.artop)
        {
         mi.DeletedCCIObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.artop);
         mi.PanelPosChange(mi.postop);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("arbot");
         mi.DrawCCIObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "arbot" button is click
      if(sparam==mi.arbot)
        {
         mi.DeletedCCIObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.arbot);
         mi.PanelPosChange(mi.posbot);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("artop");
         mi.DrawCCIObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if TF button is click
      //--
      if(sparam==mi.TFSc[0])
        {
         mi.ChangeChartSymbol(mi.TFSc[0],mi.TFId[0]);
        }
      //--
      if(sparam==mi.TFSc[1])
        {
         mi.ChangeChartSymbol(mi.TFSc[1],mi.TFId[1]);
        }
      //--
      if(sparam==mi.TFSc[2])
        {
         mi.ChangeChartSymbol(mi.TFSc[2],mi.TFId[2]);
        }
      //--
      if(sparam==mi.TFSc[3])
        {
         mi.ChangeChartSymbol(mi.TFSc[3],mi.TFId[3]);
        }
      //--
      if(sparam==mi.TFSc[4])
        {
         mi.ChangeChartSymbol(mi.TFSc[4],mi.TFId[4]);
        }
      //--
      if(sparam==mi.TFSc[5])
        {
         mi.ChangeChartSymbol(mi.TFSc[5],mi.TFId[5]);
        }
      //--
      if(sparam==mi.TFSc[6])
        {
         mi.ChangeChartSymbol(mi.TFSc[6],mi.TFId[6]);
        }
      //--
      if(sparam==mi.TFSc[7])
        {
         mi.ChangeChartSymbol(mi.TFSc[7],mi.TFId[7]);
        }
      //--
      if(sparam==mi.TFSc[8])
        {
         mi.ChangeChartSymbol(mi.TFSc[8],mi.TFId[8]);
        }
      //--
      if(sparam==mi.TFSc[9])
        {
         mi.ChangeChartSymbol(mi.TFSc[9],mi.TFId[9]);
        }
      //--
      if(sparam==mi.TFSc[10])
        {
         mi.ChangeChartSymbol(mi.TFSc[10],mi.TFId[10]);
        }
      //--
      if(sparam==mi.TFSc[11])
        {
         mi.ChangeChartSymbol(mi.TFSc[11],mi.TFId[11]);
        }
      //--
      if(sparam==mi.TFSc[12])
        {
         mi.ChangeChartSymbol(mi.TFSc[12],mi.TFId[12]);
        }
      //--
      if(sparam==mi.TFSc[13])
        {
         mi.ChangeChartSymbol(mi.TFSc[13],mi.TFId[13]);
        }
      //--
      if(sparam==mi.TFSc[14])
        {
         mi.ChangeChartSymbol(mi.TFSc[14],mi.TFId[14]);
        }
      //--
      if(sparam==mi.TFSc[15])
        {
         mi.ChangeChartSymbol(mi.TFSc[15],mi.TFId[15]);
        }
      //--
      if(sparam==mi.TFSc[16])
        {
         mi.ChangeChartSymbol(mi.TFSc[16],mi.TFId[16]);
        }
      //--
      if(sparam==mi.TFSc[17])
        {
         mi.ChangeChartSymbol(mi.TFSc[17],mi.TFId[17]);
        }
      //--
      if(sparam==mi.TFSc[18])
        {
         mi.ChangeChartSymbol(mi.TFSc[18],mi.TFId[18]);
        }
      //--
      if(sparam==mi.TFSc[19])
        {
         mi.ChangeChartSymbol(mi.TFSc[19],mi.TFId[19]);
        }
      //--
      if(sparam==mi.TFSc[20])
        {
         mi.ChangeChartSymbol(mi.TFSc[20],mi.TFId[20]);
        }
      //--
     }
//---
  } //-end OnChartEvent()
//---------//

7. How to Use It

  1. Attach the Indicator — Add CCI_MTF to any chart (e.g., EURUSD H1).
  2. Configure Settings — Open the indicator inputs to set BarCalc, choose arrow colors, font, and turn alerts on/off.
  3. Indicator wiil Interpret Signals — Look for alignment across timeframes and the summary arrow.
  4. Confirm with Price Action — Validate with swing structure, support/resistance, or another momentum/confirmation indicator (moving averages, RSI, etc.).
  5. Trend-following entry: — enter in direction of majority summary arrow on a pullback in your execution timeframe.
  6. Counter-trend: — trade only with defined risk and confluence (e.g., bullish divergence on CCI + summary turning bullish).

8. FAQ

Q1: What does the indicator measure?
A1: It measures the direction of the CCI on each timeframe — whether the recent closed CCI values are moving upward or downward — then aggregates those direction votes into a majority-based summary.

Q2: How is the summary arrow calculated?
A2: The indicator counts how many timeframes show “up” vs “down.” If up > down + 1, a summary up arrow is shown. If down > up + 1, a summary down arrow is shown. This reduces false signals from single-timeframe noise.

Q3: Does this indicator repaint?
A3: No. It uses CopyBuffer() to read closed-bar values from iCCI handles, which prevents repainting and ensures stable historical signals.

Q4: Which CCI period does it use?
A4: The default BarCalc (period) is configurable. Many traders use 14 as a starting point, but you can change it to suit your strategy.

Q5: Can I get alerts when the summary changes?
A5: Yes. The indicator includes on-screen alerts and optional email and push notifications (controlled by alerts, UseEmailAlert, and UseSendnotify inputs).

Q6: Is it resource heavy?
A6: No. The indicator uses MT5 indicator handles (iCCI) and CopyBuffer() calls efficiently. It is designed to be lightweight even while scanning 21 timeframes.

Q7: Can I change which timeframes are scanned?
A7: The indicator creates a clickable panel on the chart containing labels for all 21 timeframes (M1 → MN1). When a label (e.g., "H8") is clicked, the internal reference timeframe for analysis is updated, and the timeframe is changed to H8.

Q8: How to combine it with other indicators?
A8: Good compliment indicators are moving averages (for trend direction), RSI (for momentum confirmation), or price action signals for entry timing.

Q9: Suitable for which instruments?
A9: Works on forex, indices, commodities, stocks, and crypto — any instrument supported by MT5.

9. Conclusion

The Commodity Channel Index Multi-Timeframe (CCI_MTF) Indicator for MT5 gives traders an organized, low-noise way to read momentum across the entire range of MT5 timeframes. By using a majority-vote method and reliable closed-bar buffer reads, it delivers practical signals for both scalpers and swing traders. Combine it with price-action validation or a complementary indicator to refine entries and exits.

We hope that this article and the CCI_MTF or Commodity Channel Index Multi-Timeframe Indicator for MT5 program will be useful for traders in learning and generating new ideas for trading, who can ultimately make money from home by trading forex.

Thanks for reading this article.

Please download the CCI_MTF indicator: Commodity Channel Index Multi-Timeframe Indicator for MT5

If you are subscribed to my YouTube Channel, and would like to receive the source program of this article, please send a request via the Contact Us form page, and I will send it to your email, source code: Commodity Channel Index Multi-Timeframe Indicator for MT5

Don't forget to stop by and subscribe to Forex Home Experts YouTube Channel:

YouTube Channel: @ForexHomeExperts

YouTube Playlist: @ForexHomeExperts YouTube Playlist

Thursday, August 7, 2025

Introduction

The Average Directional Movement Index Multi-Timeframe (ADX MTF) Indicator for MetaTrader 5 provides directional signals from all 21 standard timeframes, ranging from M1 to MN1.

For each timeframe, it displays a directional arrow object (`OBJ_ARROW`) using Wingdings character 108:

🟢 Green arrow = upward ADX signal
🔴 Red arrow = downward ADX signal

After gathering these signals, the indicator calculates a consensus summary using a unique logic:
If the number of **up** signals is greater than **down + 1**, the indicator plots a larger **Wingdings 217** upward arrow * If the number of **down** signals is greater than **up + 1**, it plots a larger **Wingdings 218** downward arrow

This enables traders to view a high-confidence trend direction based on multi-timeframe ADX analysis directly on the main chart.

🔁 Note: All multi-timeframe indicators developed by Forex Home Expert use this exact signal logic structure.

The Average Directional Movement Index Multi-Timeframe indicator for MT5 (ADX_MTF) utilizes a template and displays a panel on the chart. Its function, operation, and usage are identical to the Strength of Price Movement Multi Timeframe indicator (SPM_MTF) as detailed in the previous article. For a comprehensive guide on creating a multi-timeframe indicator, you can refer to the following resources: Strength of Price Movement Multi Timeframe indicator for MT5

Average Directional Movement Index Multi-Timeframe indicator for MT5

Key Features:

✅ 21-Timeframe Directional ADX Scanning
✅ Wingdings Arrows Overlay (per timeframe)
✅ Summary Arrow with Up/Down Consensus Calculation
✅ Color Customization for Each Signal
✅ Built-in Alerts (pop-up, email, mobile)
✅ Graphical Interface Panel for Timeframe Switching (via `OnChartEvent`)

Inputs and Parameters

| Input | Description | | --------------- | ------------------------------------------ |
| `BarCalc` | Bars used for ADX signal scan |
| `ArrowUp` | Color of up signal arrow |
| `ArrowDn` | Color of down signal arrow |
| `NTArrow` | Color of neutral arrow (default) |
| `f_model` | Font type for arrows (usually "Wingdings") |
| `alerts` | Enable/disable alert popups |
| `UseEmailAlert` | Enable email alerts |
| `UseSendnotify` | Enable push notification alerts |

Why Multi-Timeframe ADX Matters?

The ADX is powerful for identifying **trend strength** but lacks insight into **trend consistency** across timeframes. This custom ADX_MTF indicator solves that:

📈 Confirm short-term trades with long-term trend backing
⚠️ Avoid sideways or weak markets using visual confirmation
🚨 Detect powerful breakouts supported by multiple timeframe trends

Using **all 21 timeframes** (from M1 to MN1) ensures broad trend consistency in your decision-making process.

Technical Overview: How the Indicator Works

Timeframe Management

The indicator prepares and manages handles for all standard MT5 timeframes:


ENUM_TIMEFRAMES TFId[] = {PERIOD_M1, PERIOD_M2, ..., PERIOD_MN1};
int tfxar = ArraySize(TFId);  // total 21 timeframes
/* Handles for all timeframe-specific ADX indicators are stored in `hADXp[]` and initialized inside `OnInit()` using `iADX()` for each timeframe. */

Signal Extraction Logic

Each timeframe is scanned using:


   //---
   int ADXDirectionScan(const ENUM_TIMEFRAMES stf,int shift) // Scan ADX Direction
     {
      //--
      int ret=0;
      int rise=1,
          down=-1;
      //--
      int br=shift+2;
      double res=0.0;
      UpdatePrice(stf);
      //--
      double ADXp[];
      ArrayResize(ADXp,br,br);
      ArraySetAsSeries(ADXp,true);
      //--
      int xx=TFIndexArray(stf);
      CopyBuffer(hADXp[xx],1,0,br,ADXp); // We will use ADX indicator buffer for DI+
      //--
      if(ADXp[shift]&gt;ADXp[shift+1]) ret=rise;
      if(ADXp[shift]&lt;ADXp[shift+1]) ret=down;
      //--
      return(ret);
      //---
     } //-end ADXDirectionScan()
   //---
   
/*
This compares DI+ values (buffer 1) to detect rising or falling strength.
*/

Consensus Calculation Logic.


   //---
   void ADXMovementCalculation(int barCnt) // Scan the direction of iADX on each timeframe
     {
      //--
      ArrayResize(PowerMove,barCnt,barCnt);
      ArraySetAsSeries(PowerMove,true);
      //--
      for(int i=barCnt-1; i>=0; i--)
        {
         up=0;
         dw=0;
         //--
         for(int x=0; x<tfxar; x++)
           {
            Arwcolor[x]=NTArrow;
            PowerMove[i]=0.0;
            int PPM=ADXDirectionScan(TFId[x],0);
            if(PPM>0)
              {
               up++;
               Arwcolor[x]=ArrowUp;
              }
            if(PPM<0)
              {
               dw++;
               Arwcolor[x]=ArrowDn;
              }
            if(x==tfxar-1)
              {
               if(up>dw+1)
                 {
                  PowerMove[i]=1.0;
                  TColor=ArrowUp;
                  curAlert=1;
                 }
               if(dw>up+1)
                 {
                  PowerMove[i]=-1.0;
                  TColor=ArrowDn;
                  curAlert=-1;
                 }
              }
           }
        }
      //--
      return;
      //---
     } //-end ADXMovementCalculation()
   //---

/*
This logic ensures that only dominant directional consensus (not slight differences) triggers a clear summary signal.
*/

Dynamic Timeframe Panel (OnChartEvent)

The indicator creates a clickable panel on the chart containing labels for all 21 timeframes. When a label (e.g., "H4") is clicked, the internal reference timeframe for analysis is updated.

This makes it easy for the user to interact with the indicator dynamically.


void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- handling CHARTEVENT_CLICK event ("Clicking the chart")
   ResetLastError();
//--
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- if "X" button is click
      if(sparam=="X")
        {
         mi.DeletedADXObject();
         //--- unpress the button
         ObjectSetInteger(mi.CI,"X",OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,"X",OBJPROP_ZORDER,0);
         //--
         mi.display=false;
         ObjectDelete(mi.CI,"X");
         mi.DisplayPanelButton();
        }
      //--- if "cstar" button is click
      if(sparam==mi.cstar)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.cstar,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         if(mi.corpos==mi.posbot) ObjectDelete(mi.CI,mi.arbot);
         if(mi.corpos==mi.postop) ObjectDelete(mi.CI,mi.artop);
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "artop" button is click
      if(sparam==mi.artop)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.artop,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.artop);
         mi.PanelPosChange(mi.postop);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("arbot");
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if "arbot" button is click
      if(sparam==mi.arbot)
        {
         mi.DeletedADXObject();
         mi.DisplayPanelButton();
         //--- unpress the button
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_STATE,false);
         ObjectSetInteger(mi.CI,mi.arbot,OBJPROP_ZORDER,0);
         if(!mi.display)
            mi.display=true;
         ObjectDelete(mi.CI,mi.arbot);
         mi.PanelPosChange(mi.posbot);
         //--
         ObjectDelete(mi.CI,"X");
         mi.DisplayButtonClick("artop");
         mi.DrawADXObject();
         //--
         ChartRedraw(mi.CI);
        }
      //--- if TF button is click
      //--
      if(sparam==mi.TFSc[0])
        {
         mi.ChangeChartSymbol(mi.TFSc[0],mi.TFId[0]);
        }
      //--
      if(sparam==mi.TFSc[1])
        {
         mi.ChangeChartSymbol(mi.TFSc[1],mi.TFId[1]);
        }
      //--
      if(sparam==mi.TFSc[2])
        {
         mi.ChangeChartSymbol(mi.TFSc[2],mi.TFId[2]);
        }
      //--
      if(sparam==mi.TFSc[3])
        {
         mi.ChangeChartSymbol(mi.TFSc[3],mi.TFId[3]);
        }
      //--
      if(sparam==mi.TFSc[4])
        {
         mi.ChangeChartSymbol(mi.TFSc[4],mi.TFId[4]);
        }
      //--
      if(sparam==mi.TFSc[5])
        {
         mi.ChangeChartSymbol(mi.TFSc[5],mi.TFId[5]);
        }
      //--
      if(sparam==mi.TFSc[6])
        {
         mi.ChangeChartSymbol(mi.TFSc[6],mi.TFId[6]);
        }
      //--
      if(sparam==mi.TFSc[7])
        {
         mi.ChangeChartSymbol(mi.TFSc[7],mi.TFId[7]);
        }
      //--
      if(sparam==mi.TFSc[8])
        {
         mi.ChangeChartSymbol(mi.TFSc[8],mi.TFId[8]);
        }
      //--
      if(sparam==mi.TFSc[9])
        {
         mi.ChangeChartSymbol(mi.TFSc[9],mi.TFId[9]);
        }
      //--
      if(sparam==mi.TFSc[10])
        {
         mi.ChangeChartSymbol(mi.TFSc[10],mi.TFId[10]);
        }
      //--
      if(sparam==mi.TFSc[11])
        {
         mi.ChangeChartSymbol(mi.TFSc[11],mi.TFId[11]);
        }
      //--
      if(sparam==mi.TFSc[12])
        {
         mi.ChangeChartSymbol(mi.TFSc[12],mi.TFId[12]);
        }
      //--
      if(sparam==mi.TFSc[13])
        {
         mi.ChangeChartSymbol(mi.TFSc[13],mi.TFId[13]);
        }
      //--
      if(sparam==mi.TFSc[14])
        {
         mi.ChangeChartSymbol(mi.TFSc[14],mi.TFId[14]);
        }
      //--
      if(sparam==mi.TFSc[15])
        {
         mi.ChangeChartSymbol(mi.TFSc[15],mi.TFId[15]);
        }
      //--
      if(sparam==mi.TFSc[16])
        {
         mi.ChangeChartSymbol(mi.TFSc[16],mi.TFId[16]);
        }
      //--
      if(sparam==mi.TFSc[17])
        {
         mi.ChangeChartSymbol(mi.TFSc[17],mi.TFId[17]);
        }
      //--
      if(sparam==mi.TFSc[18])
        {
         mi.ChangeChartSymbol(mi.TFSc[18],mi.TFId[18]);
        }
      //--
      if(sparam==mi.TFSc[19])
        {
         mi.ChangeChartSymbol(mi.TFSc[19],mi.TFId[19]);
        }
      //--
      if(sparam==mi.TFSc[20])
        {
         mi.ChangeChartSymbol(mi.TFSc[20],mi.TFId[20]);
        }
      //--
     }
//---
  } //-end OnChartEvent()
//---------//

How to Use

1. **Attach to Any Chart** (e.g., EURUSD H1)
2. **Adjust the Inputs**
3. **Observe Directional Arrows** per timeframe on your chart
4. **Watch Summary Signal Arrow** (center chart)
5. **Click Timeframe Labels** to change timeframe view instantly

Frequently Asked Questions (FAQ)

**Q1: What makes this ADX MTF indicator different from the built-in ADX in MetaTrader 5?**
**A1:** The built-in ADX only analyzes the current chart timeframe. This ADX MTF indicator scans and displays directional strength across **21 timeframes**, giving you a full-spectrum view of the market’s trend dynamics. It also features consensus-based summary signals and interactive controls.

**Q2: What do the green and red arrows mean on the chart?**
**A2:**
**Green arrow** (Wingdings 108): Indicates that ADX is rising (positive DI > previous value) on that specific timeframe
**Red arrow** (Wingdings 108): Indicates ADX is falling (trend weakening)
The **large green (217)** or **red (218)** summary arrow shows dominant direction when more than one timeframe agrees

**Q3: How is the final summary signal calculated?**
**A3:** The indicator loops through all timeframes and counts up and down signals.
** If `up > down + 1`, it plots a large **up arrow** (Wingdings 217)
** If `down > up + 1`, it plots a **down arrow** (Wingdings 218)
** If neither, no summary arrow is drawn

**Q4: Can I change the timeframe used for analysis dynamically?**
**A4:** Yes. The indicator includes an interactive panel with all 21 timeframes (M1 to MN1). Just click on any label (like “H4” or “D1”) to switch the analysis source without reattaching the indicator. This is handled via the `OnChartEvent()` function in MQL5.

**Q5: Is this indicator repainting?**
**A5:** No. The indicator uses `CopyBuffer()` with proper indexing and does **not repaint** past signals. All calculations are based on closed candles and historical values.

**Q6: What symbols or assets can I use this on?**
**A6:** This indicator works with all MT5 instruments:
* Forex pairs (e.g., EURUSD, GBPJPY)
* Indices (e.g., DAX, S&P 500)
* Commodities (e.g., gold, oil)
* Crypto (e.g., BTCUSD)

**Q7: Does this indicator send alerts?**
**A7:** Yes. It supports:
* Popup alerts
* Email alerts
* Push notifications
These can be toggled on/off in the input settings.

**Q8: Can this be used inside Expert Advisors (EAs)?**
**A8:** While this is a custom visual indicator, its signal logic can be adapted into EAs. You may extract the consensus signal via `PowerMove[]` or implement a similar formula directly in your EA code.

**Q9: Can I use this for scalping or only for swing trading?**
**A9:** It’s suitable for **both**. Scalpers can confirm short-term moves with higher timeframe trends. Swing traders benefit from trend strength alignment across D1, H4, etc.

**Q10: Do I need to install any external libraries to use it?**
**A10:** No. Just download the `.ex5` file, place it in `MQL5/Indicators`, and run.

Conclusion

The **ADX Multi-Timeframe Indicator for MT5** offers a complete solution for traders who want to understand trend strength across all timeframes simultaneously. Using a unique formula that scans and weighs up/down movement across 21 timeframes, it delivers a summary arrow signal that simplifies complex data into an actionable visual.

With features like dynamic chart interaction, visual arrows, alerts, and a lightweight design, this tool is ideal for discretionary and algorithmic traders alike.

We hope that this article and the ADX_MTF or Average Directional Movement Index Multi-Timeframe Indicator for MT5 program will be useful for traders in learning and generating new ideas for trading, who can ultimately make money from home by trading forex.

Thanks for reading this article.

Please download the ADX_MTF indicator: Average Directional Movement Index Multi-Timeframe Indicator

If you are subscribed to my YouTube Channel, and would like to receive the source program of this article, please send a request via the Contact Us form page, and I will send it to your email, source code: Average Directional Movement Index Multi-Timeframe Indicator for MT5

Don't forget to stop by and subscribe to Forex Home Experts YouTube Channel:

YouTube Channel: @ForexHomeExperts

YouTube Playlist: @ForexHomeExperts YouTube Playlist

Monday, December 2, 2024

In this article, I'll explain how to create a standard and simple Expert Advisor (EA) or forex robot by applying Buy or Sell signals from the FiboPivotCandleBar indicator for MetaTrader 4.

First, let me explain that the FiboPivotCandleBar indicator for MetaTrader 4 is an indicator I created and have been sharing for free in the MQL5 Library since 2015. However, I have never applied the signals inan Expert Advisor or forex robot until now. This article won't delve into the Fibonacci and Pivot Point strategies, as they require a dedicated and lengthy discussion.

To create this Expert Advisor, I used the latest Event Handling Functions from MQL4 and several key properties and attributes that adhere to good MQL4 programming standards.

FiboPivotCandleBar Expert Advisor for MetaTrader 4

Now, I'll explain each function, the use of variables, and the algorithm's logic one by one.

Standard Include Files.

For creating this Expert Advisor, I used the standard include files (mqh files):

  • 1.- #include MovingAverages.mqh: Used for writing the MovingAverage indicator signal.
  • 2.- #include stderror.mqh: Contains standard errors returned from the trade server.
  • 3.- #include stdlib.mqh: Contains the Error Description from standard library.

You can find these three include files in the MQL4/Include folder.

Custom Enumerations.

YN Enum Function: I use this for Yes or No options. Most programmers prefer boolean variables (True or False), but I prefer using Yes or No for clarity.

MMT Enum Function: This function is used for determining the Lot Size (Money Management).

  • If FixedLot is selected, the expert advisor will use the value of the Lots variable entered by the user. By default, the Lots size variable is set to 0.01.
  • If AutoLot is selected, the expert advisor will calculate the Lot size according to the specified money management requirements.

//---
input string           grs0 = "=== Global Strategy EA Parameters ==="; // Global Strategy EA Parameter
input ENUM_TIMEFRAMES  ExTF = PERIOD_H1;      // Select Expert TimeFrame, default PERIOD_H1
input YN            SrictTF = Yes;            // Strict to Change TimeFrame (Yes) or (No)
//---
input string           grs1 = "=== Money Management Lot Size Parameters ==="; // Money Management Lot Size Parameter
input mmt             mmlot = AutoLot;        // Money Management Type
input double           Risk = 5.0;            // Percent Equity Risk to Trade (Min=1.0% / Max=50.0%)
input double           Lots = 0.01;           // If Money Management Type FixedLot, input Fixed Lot Size
//---
input string           grs2 = "=== Close Order Option ==="; // Close Order Option
input YN      Close_by_Opps = Yes;            // Close Trade By Opposite Signal (Yes) or (No)
input YN             CSexit = Yes;            // Use Close In Signal Exit (Yes) or (No)
//---
input string           grs3 = "=== Stop Loss & Take Profit Parameters ==="; // Stop Loss  && Take Profit Parameter
input YN             Use_SL = No;             // Use Order SL (Yes) or (No)
input YN             Use_TP = No;             // Use Order TP (Yes) or (No)
//---
input string           grs4 = "=== Trailing Stop Loss / Take Profit Parameters ==="; // Trailing SL / TP Parameter
input YN          use_trail = Yes;            // Use Trailing Stop / Trailing Profit (Yes) or (No)
input int            trstrt = 1;              // Input Start value for Trailing Stop in Pips
input int            trstop = 6;              // Input Trailing Stop value in Pips
//---
input string           grs5 = "=== Others Expert Advisor Parameters ==="; // Others EA Parameter
input YN             alerts = Yes;            // Display Alerts on Chart (Yes) or (No)
input YN      UseEmailAlert = No;             // Email Alert (Yes) or (No)
input YN      UseSendnotify = No;             // Send Notification (Yes) or (No)
input YN       Usechartcomm = Yes;            // Display Setting on Chart (Yes) or (No)
input int           magicEA = 20241202;        // Expert ID (Magic Number)
//---

Select Expert TimeFrame (default: PERIOD_H1): This parameter defines the Expert Timeframe for signal calculation. It prevents the EA from recalculating signals based on the chart's last changed timeframe by user, which could lead to premature order closures.

Strict to Change Timeframe (Yes or No): By default, this is set to Yes, preventing traders from changing timeframe charts directly in the MetaTrader 4 terminal. Timeframe changes can only be made through the Select Expert Timeframe input property. Set to No if the user wants to change the timeframe manually.

Money Management Lot Size Parameters.

Money Management Type: By default, this is set to AutoLot. The EA calculates the Lot Size based on the Percent Equity Risk to Trade, which is set at 5% by default (min 1.0%, max 50.0%). For trading on 20 pairs or more, consider increasing the risk to 20% or 30%. If FixedLot is selected, input the desired FixedLot Size.

Close Order Options.

Close Trade By Opposite Signal (Yes or No): By default, this is set to Yes. If there's an open BUY order and the signal reverses to SELL, the EA will close the BUY order and open a SELL order, and vice versa.

Use Close In Signal Exit (Yes or No): By default, this is set to Yes. If the BUY signal weakens but is still profitable, the EA will close the BUY order. If set to No, the EA won't close the order based on signal exit.

Stop Loss and Take Profit Parameters.

Use Order SL (Yes or No): By default, this is set to No. Despite this, the EA will automatically close orders if there's a reverse signal, thanks to the Close Trade By Opposite Signal parameter.

Use Order TP (Yes or No): By default, this is set to No, allowing for greater profits during long trends.

Trailing Stop Loss or Take Profit Parameters.

Use Trailing Stop or Trailing Profit (Yes or No): By default, this is set to Yes. If not preferred, set this parameter to No. The trailing start is set at 1 pip from the Order Open Price, with a trailing stop value of 6 pips. These values can be adjusted as desired.

Other Expert Advisor Parameters.

Display Alerts on Chart (Yes or No): By default, this is set to Yes, activating alerts, email, and push notification functions through the DoAlerts function.

Email Alert (Yes or No): By default, this is set to No. For email alerts, users must configure their email settings in MetaTrader 4:

  • 1. Click the Tools menu.
  • 2. Select Options.
  • 3. Click Email.

Configure the settings with your email identity:

  • SMTP server: e.g., smtp.gmail.com:587 for Gmail.
  • SMTP login: Your email address.
  • SMTP password: Your email password.
  • From: Your email address.
  • To: Recipient's email address (can be the same as the sender).

After configuring, click the Test button and check the Journal Tab for any errors.

Send Notification (Yes or No): By default, this is set to No. For push notifications, users must configure their MetaQuotes ID in MetaTrader 4:

  • 1. Click the Tools menu.
  • 2. Select Options.
  • 3. Click the Notifications tab.
  • 4. Check Enable Push Notification.
  • 5. Enter YOUR MetaQuotes ID.

Class Function.

In this Expert Advisor, I use a class function named "EXP", listing all main variables and functions used. This class serves as the blueprint of the Expert Advisor. However, this article won't delve into the class function's details, assuming readers are familiar with it.


//+------------------------------------------------------------------+
//| Class for working Expert Advisor                                 |
//+------------------------------------------------------------------+
class EXP 
  {
//---
    private:
    //---
    //--
    int           slip,bartotal;
    int           ldig,checkacc,cdb,cds;
    //--
    double        mSL,mTP,mPft;
    double        pip,xpip,trs;
    double        profitb,profits,floatprofit;
    //--
    double        OPEN[],HIGH[],LOW[],CLOSE[];
    double        trval,trstart,trstoptp,aapct;
    double        PvtS,POpen,PLow1,PHigh1,PClose1;
    //--
    bool          posBUY,posSELL;
    //--
    string        expname,
                  exsymbol,
                  trade_mode;
    //-- 
    long          chart_id;
    ENUM_TIMEFRAMES BnC;
    //------------
     
    //------------
    int           LotsDigit(void);
    int           DirectionMove(ENUM_TIMEFRAMES xtf,int shift);
    int           FiboPivotCB(void);
    int           AllowOpen(void);
    int           SignalCondition(void);
    //--
    string        TF2Str(int period);
    string        GetCommentForOrder(void)                  { return(expname); }    
    string        ReturnsOrderType(ENUM_ORDER_TYPE ordtype);
    string        AccountMode(void);
    //--
    double        NonZeroDiv(double val1,double val2);
    double        MLots(void);
    //--   
    void          CopyPrices(void);
    void          RefreshPrice(string symbx,ENUM_TIMEFRAMES xtf,int bars);
    //--
    bool          ModifyStopTP(double mStop,double mProfit) { return(OrderModify(OrderTicket(),OrderOpenPrice(),mStop,mProfit,0,CLR_NONE)); }
    bool          SameAs(double v1,double v2)               { if((double)v1==(double)v2) return(true); return(false); }
    bool          CloseAllOrder(void);
    //------------

    public:
    //---
    //--
    int           utr,ALO,cB,cS,checktml;
    int           oBm,oSm,hBm,hSm,tto;
    //--
    bool          IfTradeAllowed;
    //--
    datetime      PbarB,TbarB,PbarS,TbarS;
    //------------
     
    //------------
    void          FPCB_Config(void);
    void          GetOpenPosition(void);
    void          CheckOpen(void);
    void          CheckClose(void);
    void          TrailingPositionsBuy(void);
    void          TrailingPositionsSell(void);
    void          CloseBuyPositions(void);
    void          CloseSellPositions(void);
    void          Do_Alerts(string msgText);
    void          ChartComm(void);
    void          SignalExit(void);
    //--
    bool          takeBuyPositions(void);
    bool          takeSellPositions(void);
    bool          OpenBuy(void);
    bool          OpenSell(void);
    bool          CloseAllOrdersProfit(void);
    bool          IFNewBarsB(string symb);
    bool          IFNewBarsS(string symb);
    //--
    string        getUninitReasonText(int reasonCode);
    //--
    //------------
//---
  }; //-end class fxt
//---------//
 
EXP fx;

OnInit: Here, I create an algorithm where if SrictTF enumeration is set to Yes, it utilizes the Strict to Change TimeFrame parameter. This function calls "FPCBConfig" function for setting the default configuration used in the Expert Advisor.


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//----
   Comment("");
   //--
   if(SrictTF==Yes)
     {
       if(!ChartSetSymbolPeriod(ChartID(),Symbol(),ExTF))
         {ChartSetSymbolPeriod(ChartID(),Symbol(),ExTF);}
     }
   //--
   fx.FPCB_Config();
   //--
//--- initialization done
   return(INIT_SUCCEEDED);
  }
//---------//

FPCB_Config() function.


void EXP::FPCB_Config(void)
  {
//---
   expname="@ExpFPCB-MT4";
   exsymbol=Symbol();
   //--
   slip=20;
   checktml=0;
   AccountMode();
   utr=use_trail;
   BnC=ExTF; 
   bartotal=108;
   chart_id=ChartID();
   ALO=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);
   //--
   //-- Checking the Digits Point
   slip=20;
   PbarB=iTime(Symbol(),BnC,1);
   PbarS=iTime(Symbol(),BnC,1);
   double point=SymbolInfoDouble(Symbol(),SYMBOL_POINT);
   mPft=0.5;
   //--
   if(exsymbol=="XAGUSD")
     {
       xpip=4; 
       pip=point*xpip;
       if(Use_SL==Yes) mSL=100*point;
       else mSL=0.0;
       if(Use_TP==Yes) mTP=50*point;
       else mTP=0.0;
       //--
       trstart=NormalizeDouble(trstrt*pip,Digits());
       trstoptp=NormalizeDouble(trstop*pip,Digits());
       trval=NormalizeDouble(trstart+trstoptp,Digits());
     }
   if(exsymbol=="XAUUSD")
     {
       xpip=10; 
       pip=point*xpip;
       if(Use_SL==Yes) mSL=250*point;
       else mSL=0.0;
       if(Use_TP==Yes) mTP=50*point;
       else mTP=0.0;
       //--
       trstart=NormalizeDouble(trstrt*pip,Digits());
       trstoptp=NormalizeDouble(trstop*pip,Digits());
       trval=NormalizeDouble(trstart+trstoptp,Digits());
     }
   if(exsymbol=="XBRUSD")
     {
       xpip=10; 
       pip=point*xpip;
       if(Use_SL==Yes) mSL=250*point;
       else mSL=0.0;
       if(Use_TP==Yes) mTP=50*point;
       else mTP=0.0;
       //--
       trstart=NormalizeDouble(trstrt*pip,Digits());
       trstoptp=NormalizeDouble(trstop*pip,Digits());
       trval=NormalizeDouble(trstart+trstoptp,Digits());
     }
   if(exsymbol=="XTIUSD")
     {
       xpip=10; 
       pip=point*xpip;
       if(Use_SL==Yes) mSL=250*point;
       else mSL=0.0;
       if(Use_TP==Yes) mTP=50*point;
       else mTP=0.0;
       //--
       trstart=NormalizeDouble(trstrt*pip,Digits());
       trstoptp=NormalizeDouble(trstop*pip,Digits());
       trval=NormalizeDouble(trstart+trstoptp,Digits());
     }
   else
     {
       xpip=10; 
       pip=point*xpip;
       if(Use_SL==Yes) mSL=25*pip;
       else mSL=0.0;
       if(Use_TP==Yes) mTP=5*pip;
       else mTP=0.0;
       //--
       trstart=NormalizeDouble(trstrt*pip,Digits());
       trstoptp=NormalizeDouble(trstop*pip,Digits());
       trval=NormalizeDouble(trstart+trstoptp,Digits());
     }
   //--
   IfTradeAllowed=IsTradeAllowed();
   CopyPrices();
   //--
   return;
//---
  } //-end FPCB_Config()
//---------//

OnDeinit: in this function, I call the getUninitReasonText function, which provides the description of the reason Code when the Expert Advisor calls the OnDeinit function.


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   Comment("");
   //--
   PrintFormat("%s: Deinitialization reason code=%d",__FUNCTION__,reason);
   Print(fx.getUninitReasonText(reason));
   //--
   return;
  } //-end OnDeinit()
//---------//

OnTick: This is where the Expert Advisor carries out trading activities based on the settings specified in the input properties parameter.


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick(void)
  {  
//---
   //Check Trading Terminal
   if(!fx.IfTradeAllowed && fx.checktml==0)
     {
       fx.Do_Alerts("Trading at "+Symbol()+" are NOT Allowed by Setting.");
       fx.checktml=1;
       return;
     }
   //--
   RefreshRates();
   fx.CheckOpen();
   if(fx.tto==0 && fx.hBm+fx.hSm>0) fx.CheckClose();
   //--
   if(Usechartcomm==Yes) fx.ChartComm();
   //--
   fx.GetOpenPosition();
   //Buy Condition
   if(fx.takeBuyPositions())
     {
       //--
       fx.CheckOpen();
       //--
       if(fx.oBm==0 && fx.IFNewBarsB(Symbol())) {fx.cB=1; fx.OpenBuy(); fx.PbarB=fx.TbarB;}
       else if(fx.oBm==0 && fx.oSm>0) {fx.cB=2; fx.OpenBuy(); fx.PbarB=fx.TbarB;}
       fx.CheckOpen();
       if(fx.oBm>0 && Close_by_Opps==Yes && fx.oSm>0) {fx.CloseSellPositions(); fx.PbarB=fx.TbarB;}
     }
   //--
   //Sell Condition
   if(fx.takeSellPositions())
     {
       //--
       fx.CheckOpen();
       //--
       if(fx.oSm==0 && fx.IFNewBarsS(Symbol())) {fx.cS=1; fx.OpenSell(); fx.PbarS=fx.TbarS;}
       else if(fx.oSm==0 && fx.oBm>0) {fx.cS=2; fx.OpenSell(); fx.PbarS=fx.TbarS;}
       fx.CheckOpen();
       if(fx.oSm>0 && Close_by_Opps==Yes && fx.oBm>0) {fx.CloseBuyPositions(); fx.PbarS=fx.TbarS;}
     }
   //--
   if(CSexit==Yes) fx.SignalExit();
   //--
   if(OrdersTotal()>=fx.ALO) fx.CloseAllOrdersProfit();
   //---
   //Trailing Stop / Take Profit Position
   if(fx.utr==Yes)
     {
       fx.CheckOpen();
       if(fx.oBm>0) fx.TrailingPositionsBuy();
       if(fx.oSm>0) fx.TrailingPositionsSell();
     }
   //--
   return;
//---
  } //-end OnTick()
//---------//

First, the Expert Advisor checks whether automatic trading on symbols and MetaTrader 4 is allowed. If is not, it alerts that "Trading on the symbol is NOT Allowed by Setting."

Especially for novice traders:

  • 1. Check if the "AutoTrading" button is red or green. If red, click it once to turn it green.
  • 2. Check if the Expert Advisor icon in the upper right corner of the chart shows a crying or laughing face. If crying:
    • 1. Click the Tools menu.
    • 2. Select Options.
    • 3. Click the Expert Advisors tab.
    • 4. Check "Allow automated trading." The icon will show a laughing face, and the "AutoTrading" button will turn green.

After that, the Expert Advisor starts trading activities by:

  • 1. Calling the CheckOpen function to check for open orders. If none, it calls the CheckClose function to reset the open buy or sell order count to zero.
  • 2. If Display Setting on Chart is Yes, it calls the ChartComm function to display settings on the chart.

CheckOpen function.

This is a function named CheckOpen in the EXP class, which seems to be used for checking the status of open trades. Here's a step-by-step explanation:

1. Initialization:

  • oBm and oSm are set to 0. These might represent the count of Buy and Sell orders, respectively.
  • profitb and profits are set to 0.0. These variables likely store the profit from Buy and Sell orders.
  • totalorder is set to OrdersTotal(), which retrieves the total number of orders.

2. Order Checking Loop:

  • A loop iterates through all orders (totalorder). The loop runs as long as opn is less than totalorder and the IsStopped() function returns false.
  • Inside the loop, OrderSelect(opn, SELECT_BY_POS, MODE_TRADES) selects the order at position opn.

3. Order Validation:

  • It checks if the selected order's symbol matches the current symbol (OrderSymbol() == Symbol()) and its magic number matches magicEA.
  • If these conditions are met, it proceeds to check the order type.

4. Order Type Checking:

  • If the order is a Buy order (OrderType() == OP_BUY):
    • oBm and hBm are incremented.
    • profitb is calculated as the sum of OrderProfit(), OrderCommission(), and OrderSwap().
  • If the order is a Sell order (OrderType() == OP_SELL):
    • oSm and hSm are incremented.
    • profits is calculated similarly.

5.Profit Calculation:

  • floatprofit is set to the sum of profitb and profits.

6.Total Orders:

  • tto is set to the sum of oBm and oSm, which likely represents the total number of Buy and Sell orders.

7.End of Function::

  • The function ends and returns..

The CheckOpen function essentially counts the number of Buy and Sell orders, calculates their respective profits, and totals them up. It handles trades by ensuring they match specific criteria (symbol and magic number) before processing.


void EXP::CheckOpen(void) //-- function: CheckOpenTrade.
  {
//---
    oBm=0;
    oSm=0;
    profitb=0.0;
    profits=0.0;
    int totalorder=OrdersTotal();
    //--
    for(int opn=0; opn<totalorder && !IsStopped(); opn++)
      {
        if(OrderSelect(opn,SELECT_BY_POS,MODE_TRADES))
          {
            if(OrderSymbol()==Symbol() && OrderMagicNumber()==magicEA)
              {
                //--
                if(OrderType()==OP_BUY)  
                  {
                    oBm++; 
                    hBm++;
                    profitb=OrderProfit()+OrderCommission()+OrderSwap();                
                  }
                if(OrderType()==OP_SELL) 
                  {
                    oSm++; 
                    hSm++;
                    profits=OrderProfit()+OrderCommission()+OrderSwap();
                  }
                //--
                floatprofit=profitb+profits;
              }
            //--
          }
      }
    //--
    tto=oBm+oSm;
    //---
    return;
//---
  } //-end CheckOpen()
//---------//

CheckClose function.


void EXP::CheckClose(void) //-- function: CheckOrderClose.
  {
//----
    //--
    CheckOpen();
    datetime octm;
    int hyst=OrdersHistoryTotal();
    //--
    for(int b=hyst-1; b>=0; b--)
      {
        //--
        if(OrderSelect(b,SELECT_BY_POS,MODE_HISTORY))
          {
            if(OrderSymbol()==Symbol() && OrderMagicNumber()==magicEA)
              {
                //--
                if(OrderType()==OP_BUY)
                  {
                    octm=OrderCloseTime();
                    if(hBm>0 && oBm==0 && octm>0) hBm=0;                            
                  }
                //--
                if(OrderType()==OP_SELL)
                  {
                    octm=OrderCloseTime();
                    if(hSm>0 && oSm==0 && octm>0)  hSm=0;                              
                  }
              }
          }
        //--
      }
   //--
   //---
   return;
//----
  } //-end CheckClose()
//---------//

ChartComm function.


void EXP::ChartComm() // function: write comments on the chart
  {
//---
   string opnsignal=posBUY ? "BUY" : posSELL ? "SELL" : "Not Trade";
   //--
   Comment("n     :: Server Date Time : ",(string)Year(),".",(string)Month(),".",(string)Day(), "   ",TimeToString(TimeCurrent(),TIME_SECONDS), 
      "n     ------------------------------------------------------------", 
      "n      :: Broker             :  ",TerminalCompany(), 
      "n      :: Acc. Name       :  ",AccountName(), 
      "n      :: Acc, Number    :  ",(string)AccountNumber(),
      "n      :: Acc,TradeMode :  ",AccountMode(),
      "n      :: Acc. Leverage   :  1 : ",(string)AccountLeverage(), 
      "n      :: Acc. Balance     :  ",DoubleToString(AccountBalance(),2),
      "n      :: Acc. Equity       :  ",DoubleToString(AccountEquity(),2),
      "n      :: Timeframe        :  ",TF2Str(BnC),
      "n      :: Magic Number   :  ",string(magicEA),
      "n     --------------------------------------------",
      "n      :: Currency Pair    :  ",Symbol(),
      "n      :: Current Spread  :  ",IntegerToString(SymbolInfoInteger(Symbol(),SYMBOL_SPREAD),0),
      "n      :: Signal          : ",opnsignal,
      "n      :: Position BUY  : ",string(oBm),
      "n      :: Position SELL : ",string(oSm),
      "n      :: Current Profit : ",DoubleToString(floatprofit,2));
   //---
   ChartRedraw();
   return;
//----
  } //-end ChartComm()  
//---------//

Then, the Expert Advisor calls the GetOpenPosition function, which in turn calls the SignalCondition function. This function processes signals through:

  • 1. DirectionMove function: Checks if the Close Price is above (Buy Signal) or below (Sell Signal) the Open Price.
  • 2. AllowOpen function: Checks the Open Price position against the Moving Averages period 2 (LWMA Mode, Price Weighted).
  • 3. FiboPivotCB function: Calculates signal using four Moving Average indicators, standard ZigZag indicators for M30 and H1 Timeframes, and the MACD indicator.

SignalCondition function.


int EXP::SignalCondition(void) 
  {
//---
    int rise=1,
        down=-1;
    int InTRise=3;
    int InTDown=-3;
    int cond=0;
    //--   
    CheckOpen();
    int dmove=DirectionMove(BnC,0);
    int alopn=AllowOpen();
    int fbcb3=FiboPivotCB();
    //--
    int TrendIndi=fbcb3+dmove+alopn;
    //--
    if(TrendIndi==InTRise) {cond=rise; cdb=11;}
    if(TrendIndi==InTDown) {cond=down; cds=11;}
    if(oSm>0 && TrendIndi==InTRise) {cond=rise; cdb=12;}
    if(oBm>0 && TrendIndi==InTDown) {cond=down; cds=12;}
    //--
    return(cond);
//---
  } //-end SignalCondition()
//---------//

The SignalCondition function will call 4 functions:

  • CheckOpen();
  • DirectionMove();
  • AllowOpen();
  • FiboPivotCB();

DirectionMove function.


int EXP::DirectionMove(ENUM_TIMEFRAMES xtf,int shift) // Bar Direction 
  {
//---
    int ret=0;
    int rise=1,
        down=-1;
    int br=shift+1;
    RefreshPrice(Symbol(),xtf,br);
    //--
    double diff=iClose(Symbol(),xtf,shift)-iOpen(Symbol(),xtf,shift);
    if( diff>0.0) ret=rise;
    if (diff<0.0) ret=down;
    //--
    return(ret);
//---
  } //-end DirectionMove()
//---------//

AllowOpen function.


int EXP::AllowOpen(void)
  {
//---
    int res=0;
    int rise=1,
        down=-1;
    //--
    int MAWper02=2;
    double MAFast[];
    //--
    ArrayResize(MAFast,bartotal,bartotal);
    ArraySetAsSeries(MAFast,true);
    //--
    CopyPrices();
    //--
    for(int x=bartotal-1; x>=0; x--)
      MAFast[x]=iMA(Symbol(),BnC,MAWper02,0,MODE_LWMA,PRICE_WEIGHTED,x);
    //--
    bool OpenUp=(OPEN[0]<MAFast[0]);
    bool OpenDn=(OPEN[0]>MAFast[0]);
    //--
    if(OpenUp) res=rise;
    if(OpenDn) res=down;
    //--
    //Print(Symbol()+" : AllowOpen res = "+string(res));
    //--
    return(res);
//---
  } //-end AllowOpen()
//---------//

FiboPivotCB function.


int EXP::FiboPivotCB(void) // Signal BUY / SELL Indicator FiboPivotCandleBar
  {
//---
    int res=0;
    int rise=1,
        down=-1;
    //--
    int zzh1=0;
    int zzl1=0;
    int zhm1=0;
    int zlm1=0;
    bool ArrUp=false;
    bool ArrDn=false;
    bool opsup=false;
    bool opsdn=false;
    bool opsnt=false;
    //--   
    ENUM_TIMEFRAMES
       cprz=PERIOD_M15,
       prhh=PERIOD_M30,
       prh1=PERIOD_H1;
    ENUM_MA_METHOD mmeth1=MODE_EMA;
    ENUM_MA_METHOD mmeth2=MODE_SMA;
    ENUM_APPLIED_PRICE aprice=PRICE_MEDIAN;
    //--
    double ema02m[];
    double sma20m[];
    double maon10[];
    double maon62[];
    //--
    ArrayResize(ema02m,bartotal);
    ArrayResize(sma20m,bartotal);
    ArrayResize(maon10,bartotal);
    ArrayResize(maon62,bartotal);
    ArraySetAsSeries(ema02m,true);
    ArraySetAsSeries(sma20m,true);
    ArraySetAsSeries(maon10,true);
    ArraySetAsSeries(maon62,true);
    //--
    RefreshPrice(Symbol(),cprz,bartotal);
    //--
    for(int j=bartotal-1; j>=0; j--)
      {ema02m[j]=iMA(Symbol(),cprz,2,0,mmeth1,aprice,j);}
    for(int k=bartotal-1; k>=0; k--)
      {sma20m[k]=iMA(Symbol(),cprz,20,0,mmeth2,aprice,k);}
    //--
    SimpleMAOnBuffer(bartotal,0,0,10,sma20m,maon10);
    SimpleMAOnBuffer(bartotal,0,0,62,sma20m,maon62);
    //--
    double ma10620=maon10[0]-maon62[0];
    double ma10621=maon10[1]-maon62[1];
    double ma20100=sma20m[0]-maon10[0];
    double ma20101=sma20m[1]-maon10[1];
    //--
    bool ma5xupn=(ema02m[0]>ema02m[1])&&(sma20m[0]>sma20m[1])&&(ma10620>=ma10621)&&((maon10[2]<maon62[2])&&(maon10[0]>maon62[0]));
    bool ma5xupc=(ema02m[0]>ema02m[1])&&(sma20m[0]>sma20m[1])&&(ma10620>=ma10621)&&(maon10[0]>maon62[0])&&(maon10[0]>maon10[1]);
    bool ma5xupb=(ema02m[0]>ema02m[1])&&(sma20m[0]>sma20m[1])&&(ma20100>ma20101)&&(maon62[0]>maon62[1])&&(sma20m[0]>maon10[0]);
    bool ma5xdnn=(ema02m[0]<ema02m[1])&&(sma20m[0]<sma20m[1])&&(ma10620<=ma10621)&&((maon10[2]>maon62[2])&&(maon10[0]<maon62[0]));
    bool ma5xdnc=(ema02m[0]<ema02m[1])&&(sma20m[0]<sma20m[1])&&(ma10620<=ma10621)&&(maon10[0]<maon62[0])&&(maon10[0]<maon10[1]);
    bool ma5xdna=(ema02m[0]<ema02m[1])&&(sma20m[0]<sma20m[1])&&(ma20100<ma20101)&&(maon62[0]<maon62[1])&&(sma20m[0]<maon10[0]);
    //--
    RefreshPrice(Symbol(),prhh,bartotal);
    for(int zz=bartotal-1; zz>=0; zz--) //- for(zz)
      {
        if(iHigh(Symbol(),prhh,zz)==iCustom(Symbol(),prhh,"ZigZag",12,5,3,1,1,zz))
          {zhm1=zz;}
        if(iLow(Symbol(),prhh,zz)==iCustom(Symbol(),prhh,"ZigZag",12,5,3,1,2,zz))
          {zlm1=zz;}
      } //-end for(zz m30)
    //--
    RefreshPrice(Symbol(),prh1,bartotal);
    for(int zz=bartotal-1; zz>=0; zz--) //- for(zz)
      {
        if(iHigh(Symbol(),prh1,zz)==iCustom(Symbol(),prh1,"ZigZag",12,5,3,1,zz))
          {zzh1=zz;}
        if(iLow(Symbol(),prh1,zz)==iCustom(Symbol(),prh1,"ZigZag",12,5,3,1,2,zz))
          {zzl1=zz;}
      } //-end for(zz h1)
    //--
    double macd0=iMACD(Symbol(),prh1,12,26,9,0,MODE_MAIN,0)-iMACD(Symbol(),prh1,12,26,9,0,MODE_SIGNAL,0);
    double macd1=iMACD(Symbol(),prh1,12,26,9,0,MODE_MAIN,1)-iMACD(Symbol(),prh1,12,26,9,0,MODE_SIGNAL,1);
    double mcdm0=iMACD(Symbol(),prh1,12,26,9,0,MODE_MAIN,0);
    double mcdm1=iMACD(Symbol(),prh1,12,26,9,0,MODE_MAIN,1);
    double mcds0=iMACD(Symbol(),prh1,12,26,9,0,MODE_SIGNAL,0);
    double mcds1=iMACD(Symbol(),prh1,12,26,9,0,MODE_SIGNAL,1);
    //--
    if((((zzl1<zzh1)&&(zzl1>0)&&(zzl1<4)&&(zlm1<zhm1)))||((macd0>macd1)&&(mcdm0>mcdm1))) {ArrUp=true;}
    //--
    if((((zzl1>zzh1)&&(zzh1>0)&&(zzh1<4)&&(zlm1>zhm1)))||((macd0<macd1)&&(mcdm0<mcdm1))) {ArrDn=true;}
    //--
    if(((ArrUp==true)&&(zzl1>4))||((mcdm0<mcdm1)&&(macd0<macd1))) {ArrDn=true; ArrUp=false;}
    if(((ArrDn==true)&&(zzh1>4))||((mcdm0>mcdm1)&&(macd0>macd1))) {ArrUp=true; ArrDn=false;}
    if((mcdm0>=mcdm1)&&(mcdm0>mcds0)&&(mcds0>mcds1)) {ArrUp=true; ArrDn=false;}
    if((mcdm0<=mcdm1)&&(mcdm0<mcds0)&&(mcds0<mcds1)) {ArrDn=true; ArrUp=false;}
    if(ma5xupn||ma5xupc||ma5xupb) {ArrUp=true; ArrDn=false;}
    if(ma5xdnn||ma5xdnc||ma5xdna) {ArrDn=true; ArrUp=false;}
    //--
    double fpCls0=(iHigh(Symbol(),prh1,0)+iLow(Symbol(),prh1,0)+iClose(Symbol(),prh1,0)+iClose(Symbol(),prh1,0))/4;
    double fpCls1=(iHigh(Symbol(),prh1,1)+iLow(Symbol(),prh1,1)+iClose(Symbol(),prh1,1)+iClose(Symbol(),prh1,1))/4;
    double hlcc0=fpCls0-iMA(Symbol(),prh1,20,0,mmeth2,aprice,0);
    double hlcc1=fpCls1-iMA(Symbol(),prh1,20,0,mmeth2,aprice,1);
    //--
    if((ArrUp==true)&&(hlcc0>hlcc1)) {opsup=true; opsdn=false; opsnt=false;}
    //--
    if((ArrDn==true)&&(hlcc0<hlcc1)) {opsdn=true; opsup=false; opsnt=false;}
    //--
    if((!opsup)&&(!opsdn)) {opsnt=true; opsup=false; opsdn=false;}
    //--
    //---
    if(ArrUp && opsup) res=rise;
    //--
    if(ArrDn && opsdn) res=down;
    //--
    //---
    return(res);
//---
  } //-end FiboPivotCB()
//---------//

The FiboPivotCB() that utilizes a combination of technical analysis indicators and Fibonacci Pivot Points to generate buy and sell signals.

1. Variable Declaration:

  • Various integer and boolean variables are declared to store intermediate calculations and signal flags.
  • Timeframe variables cprz, prhh, and prh1 are defined to specify different timeframes for calculations.
  • Arrays ema02m, sma20m, maon10, and maon62 are declared to store calculated moving averages.

2. Calculating Moving Averages:

  • The code calculates several moving averages using the iMA() function.
  • It also calculates differences between moving averages to identify potential trend changes.

3. Fibonacci Pivot Points:

  • The code calculates Fibonacci Pivot Points using the iHigh(), iLow(), and iClose() functions.
  • It identifies potential support and resistance levels based on these pivot points.

4. Trend Identification:

  • The code uses a combination of moving average crossovers and Fibonacci Pivot Points to identify potential uptrends and downtrends.
  • Boolean variables ArrUp and ArrDn are used to indicate upward and downward trends, respectively.

5. Signal Generation:

  • The final if conditions check the values of the trend indicators and Fibonacci Pivot Points to generate buy or sell signals.
  • res variable is set to rise for a buy signal and down for a sell signal.

Key Points to Note:

  • Timeframe Importance: The choice of timeframes (e.g., cprz, prhh, prh1) significantly impacts the sensitivity and accuracy of the signals.
  • Indicator Combination: The code combines multiple indicators to generate more robust signals, reducing the risk of false signals.

Buy Orders condition:

  • takeBuyPositions function is true.
  • No existing Buy order (one order per direction signal).
  • On a new bar (no previous Buy order or Close Buy order on that bar).
  • If a Sell order exists and Close Trade By Opposite Signal is Yes, it opens a Buy order and closes the Sell order.
  • If Close Trade By Opposite Signal is No, it opens a Buy order and leaves the Sell order open.

Sell Orders condition:

  • takeSellPositions function is true.
  • No existing Sell order (one order per direction signal).
  • On a new bar (no previous Sell order or Close Sell order on that bar).
  • If a Buy order exists and Close Trade By Opposite Signal is Yes, it opens a Sell order and closes the Buy order.
  • If Close Trade By Opposite Signal is No, it opens a Sell order and leaves the Buy order open.

If Use Close In Signal Exit is Yes, the Expert Advisor calls the SignalExit function to close orders if the signal is not significant.

If the Orders Total is greater than or equal to the ACCOUNT LIMIT ORDERS set by the broker, the Expert Advisor calls the CloseAllOrdersProfit function to close profitable orders, keeping the total open orders below the broker's limit.

If Use Trailing Stop and Trailing Profit is Yes, the Expert Advisor performs trailing stop and trailing profit using TrailingPositionsBuy for Buy orders and TrailingPositionsSell for Sell orders.

For additional functions, you can explore and learn from the Expert Advisor program it self. If you have any questions, feel free to write in the comments or email me.

I recommend testing this expert advisor directly on the trading terminal using a demo account. While you can use the StrategyTester, keep in mind that its results depend heavily on the complete history of price data in your MetaTrader 4. This expert advisor integrates multiple indicators, including a 6-period Moving Average, ZigZag indicator (two timeframes), and MACD indicator.

I've tested this expert advisor on the MT4 trading terminal using a demo account to evaluate its performance. As you can see, the expert advisor has opened orders according to the FiboPivotCandleBar for the MT4 indicator signal, which indicates that it is functioning well.

Thank you for reading this article.

See you in the next article on Expert Advisor programs or indicators for MetaTrader 4 and MetaTrader 5.

Please download the Expert Advisor: ExpFPCB-MT4 and Indicator: FiboPivotCandleBar

If you are subscribed to my YouTube Channel, and would like to receive the source program of this article, please send a request via the Contact Us form page, and I will send it to your email, source code:

Expert Advisor: ExpFPCB-MT4.mq4

Indicator: FiboPivotCandleBar.mq4

Don't forget to stop by and subscribe to Forex Home Experts YouTube Channel:

YouTube Channel: @ForexHomeExperts

YouTube Playlist: @ForexHomeExperts YouTube Playlist

Featured Post

How to create a simple Multi-Currency Expert Advisor using MQL5 with Zigzag and RSI Indicators Signal

Introduction The Expert Advisor discussed in this article is a multi-currency trading robot that uses the Zigzag and RSI indicators. It fol...