Showing posts with label Automated Trading Alerts. Show all posts
Showing posts with label Automated Trading Alerts. Show all posts

Monday, December 16, 2024

This FiboPivotCandleBar Multi-Currency Expert Advisor for MT5 has the same concept and signal strategy as the single-currency FiboPivotCandleBar as I explained in the previous article A Comprehensive Guide to FiboPivotCandleBar: Functions and Performance of the Expert Advisor for MT5 (single-currency)

FiboPivotCandleBar is a sophisticated trading tool designed to provide trading signals by combining several technical indicators, including Fibonacci levels, Pivot Points, ZigZag, MACD, and Moving Averages. Below is a breakdown of the main components and their functions:

FiboPivotCandleBar Expert Advisor that trades Multi-Currency for MT5

Fibonacci Levels:

Function: Identify potential support and resistance levels based on the Fibonacci retracement levels. These levels are derived from the Fibonacci sequence and are used by traders to predict potential reversal points in the market.

Pivot Points:

Function: Calculate key price levels that are expected to act as support or resistance. These levels are computed from the high, low, and close prices of the previous trading period. Pivot Points help traders to anticipate the likely market turning points.

ZigZag Indicator:

Function: Highlight significant price changes, filtering out smaller movements and noise in the market. The ZigZag indicator connects significant tops and bottoms to identify the prevailing trend and potential reversal points.

MACD (Moving Average Convergence Divergence):

Function: Determine the momentum and trend direction by comparing different timeframes of moving averages. MACD consists of two exponential moving averages (EMA) and a histogram that indicates the difference between the MACD line and the signal line. It helps traders identify bullish and bearish market conditions.

Moving Averages:

Function: Smooth out price data to identify the trend direction over a specified period. Moving averages are used to filter out short-term fluctuations and provide a clearer view of the underlying trend.

By integrating these indicators, the FiboPivotCandleBar Multi-Currency EA generates trading signals that guide traders on when to enter and exit trades. The combination of these technical tools allows for a comprehensive analysis of the market, aiming to enhance trading accuracy and profitability.

Therefore, in this article I will not explain each function because you can see the explanation in the article A Comprehensive Guide to FiboPivotCandleBar: Functions and Performance of the Expert Advisor for MT5.

The differences in function and program writing between multi-currency and single-currency can be illustrated in the function example below:

In Multi-Currency Expert Advisor:


void MCEA::CurrentSymbolSet(const string symbol)
  {
//---
   mc_symbol.Name(symbol);
   mc_symbol.CheckMarketWatch();
   mc_symbol.IsSynchronized();
   mc_trade.SetTypeFillingBySymbol(symbol);
   mc_symbol.Refresh();
   mc_symbol.RefreshRates();
   //--
   return;
//---
  } //-end CurrentSymbolSet()
//---------//

In Single-Currency Expert Advisor:


void SFPCB::CurrentSymbolSet(void)
  {
//---
   sc_symbol.Name(SPC);
   sc_symbol.CheckMarketWatch();
   sc_symbol.IsSynchronized();
   sc_trade.SetTypeFillingBySymbol(SPC);
   sc_symbol.Refresh();
   sc_symbol.RefreshRates();
   //--
   return;
//---
  } //-end CurrentSymbolSet()
//---------//

Detailed explanation of the differences between the two functions:

In Multi-Currency Expert Advisor:

void MCEA::CurrentSymbolSet(const string symbol)

This function is designed for a Multi-Currency Expert Advisor. It takes a single parameter, symbol, which is a string representing the symbol of the financial instrument. Here are the steps it follows:

1. Set Symbol Name: It sets the name of the symbol using mc_symbol.Name(symbol)

2. Check Market Watch: It ensures the symbol is in the market watch using mc_symbol.CheckMarketWatch().

3. Synchronization: It checks if the symbol is synchronized with the server using mc_symbol.IsSynchronized().

4. Set Trade Type: It sets the trade type filling by symbol using mc_trade.SetTypeFillingBySymbol(symbol).

5. Refresh Symbol Data:It refreshes the symbol's data using mc_symbol.Refresh().

6. Refresh Rates: It refreshes the rates for the symbol using mc_symbol.RefreshRates().

In Single-Currency Expert Advisor:

void SFPCB::CurrentSymbolSet(void)

This function is designed for a Single-Currency Expert Advisor. It does not take any parameters. Instead, it uses a predefined symbol, SPC. Here are the steps it follows:

1. Set Symbol Name: It sets the name of the symbol using sc_symbol.Name(SPC).

2. Check Market Watch: It ensures the symbol is in the market watch using sc_symbol.CheckMarketWatch().

3. Synchronization: It checks if the symbol is synchronized with the server using sc_symbol.IsSynchronized().

4. Set Trade Type: It sets the trade type filling by symbol using sc_trade.SetTypeFillingBySymbol(SPC).

5. Refresh Symbol Data: It refreshes the symbol's data using sc_symbol.Refresh().

6. Refresh Rates: It refreshes the rates for the symbol using sc_symbol.RefreshRates().

Key Differences

  • 1. Parameter Input:
    • MCEA::CurrentSymbolSet takes a parameter symbol as input, allowing dynamic setting of symbols.
    • SFPCB::CurrentSymbolSet does not take any parameters and uses a predefined symbol SPC.
  • 2. Usage Context:
    • MCEA::CurrentSymbolSet is used in a Multi-Currency environment where the symbol can change dynamically based on the input parameter.
    • SFPCB::CurrentSymbolSet is used in a Single-Currency environment where the symbol is fixed and predefined.
  • 3. Flexibility:
    • MCEA::CurrentSymbolSet offers more flexibility by allowing different symbols to be set at runtime.
    • SFPCB::CurrentSymbolSet is less flexible as it always operates on the same predefined symbol.

By understanding these differences, you can appreciate how each function is tailored to its specific use case within the context of multi-currency versus single-currency trading strategies.

Let's break down the ExpFPCB_MCEA_Config function of FiboPivotCandleBar Expert Advisor for MT5.

void MCEA::ExpFPCB_MCEA_Config(void)

This function configures an Expert Advisor (EA) for multi-currency trading. Below are the step-by-step processes within this function:


//+------------------------------------------------------------------+
//| Expert Configuration                                             |
//+------------------------------------------------------------------+
void MCEA::ExpFPCB_MCEA_Config(void) 
  {
//---
    //--
    HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded
    //--
    TFT05=PERIOD_M5;
    TFT15=PERIOD_M15;
    TFT30=PERIOD_M30;
    TFT60=PERIOD_H1;
    ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
    int arTFs=ArraySize(TFs);
    //--
    for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x]; // TF for calculation signal
    //--
    //-- Indicators handle for all symbol
    for(int x=0; x<arrsymbx; x++) 
      {
        hMATrF[x]=iMA(DIRI[x],TFt,2,0,MODE_LWMA,PRICE_WEIGHTED);
        hMATrS[x]=iMA(DIRI[x],TFt,20,0,MODE_SMA,PRICE_MEDIAN);
        hiMA02[x]=iMA(DIRI[x],TFT15,2,0,MODE_EMA,PRICE_MEDIAN);
        hiMA20[x]=iMA(DIRI[x],TFT15,20,0,MODE_SMA,PRICE_MEDIAN);
        hiMACD[x]=iMACD(DIRI[x],TFT60,12,26,9,PRICE_CLOSE);
        hZZm30[x]=iCustom(DIRI[x],TFT30,indiname,depth,devia,backs);
        hZZm60[x]=iCustom(DIRI[x],TFT60,indiname,depth,devia,backs);
        hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);       //-- Handle for the iSAR indicator for M5 Timeframe
        //--
      }
    //--
    minprofit=NormalizeDouble(TSmin/100.0,2);
    //--
    ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
    if(Close_by_Opps==No) 
      {
        if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2;
        else 
        ALO=(int)(mc_account.LimitOrders()/2);
      }
    //--
    LotPS=(double)ALO;
    maxSpread=maxsprd;
    if(MQLInfoInteger(MQL_TESTER))
      maxSpread=(int)SymbolInfoInteger(Symbol(),SYMBOL_SPREAD);
    //--
    mc_trade.SetExpertMagicNumber(magicEA);
    mc_trade.SetDeviationInPoints(slip);
    mc_trade.SetMarginMode();
    Set_Time_Zone();
    //--
    return;
//---
  } //-end ExpFPCB_MCEA_Config()
//---------//

Function Explanation

Detailed Breakdown:

1. Handling Symbol Arrays:

  • HandlingSymbolArrays(); This function manages all the pairs that will be traded. This will be explained in more detail in the paragraphs below.

2. Timeframe Setup:

  • TFT05=PERIOD_M5;, TFT15=PERIOD_M15;, TFT30=PERIOD_M30;, TFT60=PERIOD_H1; Sets up several timeframe constants for later use.

3. Dynamic Timeframe Selection:

  • Creates an array of different timeframes: ENUM_TIMEFRAMES TFs[]=PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1};
  • Determines the size of the array: int arTFs=ArraySize(TFs);
  • Loops through the array to set the calculation timeframe (TFt) based on a condition: for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x];

4. Indicators Handling for All Symbols:

  • Iterates through each symbol in arrsymbx to initialize various indicators for each symbol:
        
      //-- Indicators handle for all symbol
        for(int x=0; x<arrsymbx; x++) 
          {
            hMATrF[x]=iMA(DIRI[x],TFt,2,0,MODE_LWMA,PRICE_WEIGHTED);
            hMATrS[x]=iMA(DIRI[x],TFt,20,0,MODE_SMA,PRICE_MEDIAN);
            hiMA02[x]=iMA(DIRI[x],TFT15,2,0,MODE_EMA,PRICE_MEDIAN);
            hiMA20[x]=iMA(DIRI[x],TFT15,20,0,MODE_SMA,PRICE_MEDIAN);
            hiMACD[x]=iMACD(DIRI[x],TFT60,12,26,9,PRICE_CLOSE);
            hZZm30[x]=iCustom(DIRI[x],TFT30,indiname,depth,devia,backs);
            hZZm60[x]=iCustom(DIRI[x],TFT60,indiname,depth,devia,backs);
            hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);
            //--
          }
        //--
    

5. Profit Calculation:

  • Normalizes the minimum profit value: minprofit=NormalizeDouble(TSmin/100.0,2);

6. Account Limit Orders:

  • Sets the allowable limit orders (ALO) based on the account's limit and certain conditions:
    
        //--
        ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders();
        if(Close_by_Opps==No) 
          {
            if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2;
            else 
            ALO=(int)(mc_account.LimitOrders()/2);
          }
        //--
    

7. Lot and Spread Settings:

  • Sets the lot size per symbol: LotPS=(double)ALO;
  • Defines the maximum spread allowed:
    
      maxSpread=maxsprd;
        if(MQLInfoInteger(MQL_TESTER))
          maxSpread=(int)SymbolInfoInteger(Symbol(),SYMBOL_SPREAD);
    

8. Trade Settings:

  • Sets various trading parameters, such as the magic number, deviation in points, and margin mode:
     
        //--
        mc_trade.SetExpertMagicNumber(magicEA);
        mc_trade.SetDeviationInPoints(slip);
        mc_trade.SetMarginMode();
        Set_Time_Zone();
        //--
    

Summary

The MCEA::ExpFPCB_MCEA_Config function is crucial for configuring a multi-currency Expert Advisor by setting up symbol arrays, timeframes, indicators, and trading parameters. It ensures that all required symbols and their respective indicators are prepared for trading, and it adjusts trading limits and parameters based on current market conditions and account settings.

This section of the function iterates through each symbol in the arrsymbx array to initialize various indicator handles for each symbol. The indicators used include Moving Averages (MA), Moving Average Convergence Divergence (MACD), Custom Indicator (ZZ), and Parabolic SAR (iSAR). Here’s a detailed breakdown:

1. Iteration Through Symbols:

  • The loop for(int x=0; x<arrsymbx; x++) iterates over all the symbols in the arrsymbx array.

2. Initializing Indicators:

  • Weighted Moving Average (LWMA):
    • hMATrF[x]=iMA(DIRI[x],TFt,2,0,MODE_LWMA,PRICE_WEIGHTED);
    • Initializes a 2-period LWMA with weighted prices for each symbol.
  • Simple Moving Average (SMA):
    • hMATrS[x]=iMA(DIRI[x],TFt,20,0,MODE_SMA,PRICE_MEDIAN);
    • Initializes a 20-period SMA with median prices for each symbol.
  • Exponential Moving Average (EMA):
    • hiMA02[x]=iMA(DIRI[x],TFT15,2,0,MODE_EMA,PRICE_MEDIAN);
    • Initializes a 2-period EMA with median prices for each symbol in the 15-minute timeframe.
    • hiMA20[x]=iMA(DIRI[x],TFT15,20,0,MODE_SMA,PRICE_MEDIAN);
    • Initializes a 20-period SMA with median prices for each symbol in the 15-minute timeframe.
  • Moving Average Convergence Divergence (MACD):
    • hiMACD[x]=iMACD(DIRI[x],TFT60,12,26,9,PRICE_CLOSE);
    • Initializes the MACD indicator with standard parameters (12, 26, 9) for the 60-minute timeframe.
  • Custom Indicator (ZigZag):
    • hZZm30[x]=iCustom(DIRI[x],TFT30,indiname,depth,devia,backs);
    • Initializes a custom indicator (e.g., ZigZag) for the 30-minute timeframe with specified parameters.
    • hZZm60[x]=iCustom(DIRI[x],TFT60,indiname,depth,devia,backs);
    • Initializes the same custom indicator for the 60-minute timeframe with specified parameters.
  • Parabolic SAR (iSAR):
    • hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi);
    • Initializes the Parabolic SAR indicator for the 5-minute timeframe with specified parameters (SARstep and SARmaxi).

Summary

The "Indicators Handling for All Symbols" loop is critical for setting up the necessary technical indicators for each symbol that the Expert Advisor will trade. By initializing these indicators, the function ensures that the EA has the required data to analyze market conditions and make informed trading decisions based on various timeframes and price calculations.

The "Trade on Specific Time" feature allows traders to align their trading activities with specific time zones. This is particularly useful for traders who want to focus on particular trading sessions, such as the London, New York, or Tokyo sessions.

By enabling this feature, the Expert Advisor can be configured to trade only during specific time frames, potentially reducing exposure to market volatility during less active periods.

Provides 2 options:

  • Trade on Specific Time = No;
  • Trade on Specific Time = Yes;

No Specific Time:

If "Trade on Specific Time Zone" is set to "No," the Expert Advisor will trade 24/5, from 00:15 to 23:59, based on the MT5 server time.

Specific Time Zones:

If "Trade on Specific Time Zone" is set to "Yes," the trader can select from the following options:

Custom Session:

  • Traders can specify custom start and end times for the trading session. The EA will only execute trades within this specified time.

Predefined Sessions:

  • New Zealand Session: Trades during New Zealand trading hours.
  • Australia Sydney Session: Trades during Australian trading hours.
  • Asia Tokyo Session: Trades during Asian trading hours.
  • Europe London Session: Trades during European trading hours.
  • America New York Session: Trades during US trading hours.

Trading Session Duration Calculation:

  • For trades initiated during the New Zealand to New York session, the Expert Advisor calculates the duration of the trade, which can be useful for various trading strategies and analysis.

Function: MCEA::GoodMarginTrade function of FiboPivotCandleBar Multi-Currency Expert Advisor for MT5.

The GoodMarginTrade function is designed to check whether an order can be placed based on the available free margin in the trading account. It evaluates if the account has sufficient free margin to open a trade with specified parameters and triggers an alert if the margin is insufficient.


bool MCEA::GoodMarginTrade(const string symbol,ENUM_ORDER_TYPE _cmd,double lotsz,double atprice)
  {
//---
   bool goodmrgn=true;
   //--
   if((mc_account.FreeMarginCheck(symbol,_cmd,lotsz,atprice)<=0.0)||(mc_account.FreeMargin()<(mc_account.Equity()*maxmrgn/100))) goodmrgn=false;
   //--
   if(!goodmrgn)
     {
       string nomargn="Account Free Margin minimum has reached the specified limit, Order will not opened";
       Do_Alerts(symbol,nomargn);
     }
   //--
   return(goodmrgn);
//---
  } //-end GoodMarginTrade()
//---------//

Parameters:

  • symbol: A string representing the trading symbol (e.g., "EURUSD").
  • _cmd: An enumeration (ENUM_ORDER_TYPE) indicating the type of order (e.g., buy, sell).
  • lotsz: A double value representing the lot size of the trade.
  • atprice: A double value indicating the price at which the order is to be placed.

Steps:

1. Initialize Margin Status:

  • bool goodmrgn=true;
  • A boolean variable goodmrgn is initialized to true, assuming the margin status is good by default.

2. Check Free Margin:

if((mc_account.FreeMarginCheck(symbol,_cmd,lotsz,atprice)<=0.0)||(mc_account.FreeMargin()<(mc_account.Equity()*maxmrgn/100))) goodmrgn=false;
  • The function checks two conditions to determine if the margin is insufficient:
    • a. If the free margin required to open the trade (FreeMarginCheck) is less than or equal to zero.
    • b. If the available free margin is less than a specified percentage (maxmrgn) of the account's equity.
  • If either condition is met, goodmrgn is set to false.

3. Alert if Margin is Insufficient:


//--
if(!goodmrgn)
  {
    string nomargn="Account Free Margin minimum has reached the specified limit, Order will not opened";
    Do_Alerts(symbol,nomargn);
  }
//--
  • If goodmrgn is false (meaning the margin is insufficient), an alert message is created and sent using the Do_Alerts function.

4. Return Margin Status:

return(goodmrgn);

  • The function returns the value of goodmrgn, indicating whether the margin is sufficient (true) or insufficient (false).

Summary

The GoodMarginTrade function is essential for ensuring that trades are only placed when there is sufficient free margin in the account. It helps prevent margin calls and potential losses by checking the margin requirements before executing any trade orders. If the margin is insufficient, it alerts the user and prevents the order from being opened.

Function: MCEA::CheckSpread

The CheckSpread function is designed to check whether the spread for a given trading symbol is within an acceptable limit. If the spread exceeds the maximum allowed spread, the function triggers an alert.

Parameters:

  • symbol: A string representing the trading symbol (e.g., "EURUSD").

Steps:

1. Initialize Spread Allowance:

  • bool allow_spread=false;
  • A boolean variable allow_spread is initialized to false, assuming the spread is not allowed by default.

2. Get Symbol Index:

  • int x=PairsIdxArray(symbol);
  • The function calls PairsIdxArray(symbol) to get the index of the symbol in the pairs array.

3. Set Current Symbol:

  • CurrentSymbolSet(symbol);
  • Calls CurrentSymbolSet(symbol) to set up the current symbol context for subsequent operations.

4. Calculate Spread:

  • spreadx[x]=mc_symbol.NormalizePrice(mc_symbol.Ask()-mc_symbol.Bid());
  • Calculates the spread for the symbol by subtracting the bid price from the ask price and normalizing the result.

5. Check Spread Against Maximum Allowed Spread:

  • allow_spread=spreadx[x] <= maxSpread*pip;
  • Compares the calculated spread (spreadx[x]) with the maximum allowed spread (maxSpread multiplied by pip).
  • Sets allow_spread to true if the spread is within the acceptable limit, otherwise false

6. Trigger Alert if Spread is Too High:

    
    //--
    if(!allow_spread)
      {
        string bigspread="Spread in "+symbol+" is greater than maximum spread limit.";
        Do_Alerts(symbol,bigspread);
      }
    //--
  • If allow_spread is false (meaning the spread is too high), an alert message is created and sent using the Do_Alerts function.

7. Return Spread Allowance Status:

  • return(allow_spread);
  • The function returns the value of allow_spread, indicating whether the spread is within the acceptable limit (true) or not (false).

Summary

The CheckSpread function is essential for ensuring that trades are only placed when the spread for a given symbol is within an acceptable limit. By checking the spread before executing any trade orders, the function helps to prevent trades with excessively high costs, thereby safeguarding the trading account. If the spread is too high, it alerts the user and prevents the order from being opened.

1. The Challenge of Multi-Currency Trading.

When dealing with a multi-currency Expert Advisor that trades multiple pairs on a single chart, managing and monitoring individual pair performance can be cumbersome.

The Solution: A Dedicated Button Panel.

A well-designed button panel can significantly enhance the trading experience. By providing quick access to different chart symbols and timeframes, traders can:

  • Monitor Individual Pair Performance: Easily switch between charts to assess the accuracy of entry and exit signals.
  • React to Market Changes: Quickly identify opportunities and risks in specific pairs.
  • Optimize Trading Strategies: Fine-tune strategies based on real-time market data.

Key Features of an Effective Button Panel:

  • Symbol Selection: A dropdown menu or a list of buttons to quickly switch between different currency pairs.
  • Timeframe Selection: Options to adjust the timeframe for each symbol, allowing for different time-frame analysis.
  • Chart Navigation: Buttons to navigate between charts.
  • Order Management: A clear overview of open and closed orders, including profit and loss information on that currency.

2. Manual Order Management.

Several manual buttons have been incorporated into this multi-currency expert advisor to enhance efficiency and effectiveness for traders in monitoring the advisor's operations.

  • Set SL / TP All Orders
    • This button is beneficial if the trader has initially set the parameters to Use Order Stop Loss (No) and/or Use Order Take Profit (No), but later decides to apply Stop Loss or Take Profit to all orders. By clicking the "Set SL / TP All Orders" button, all orders will be adjusted, and a Stop Loss and/or Take Profit will be implemented across the board.
  • Close All Orders
    • If a trader wants to close all orders, they can simply click on the "Close All Orders" button to close all open orders.
  • Close All Orders Profit
    • If a trader wishes to close all orders that are currently profitable, they can click on the "Close All Orders Profit" button to close all open orders that have generated profit.

3. Managing Orders and Chart Symbols.

For multi-currency expert advisors that trade 30 pairs using only one chart symbol, having a button panel for all symbols would be highly beneficial and convenient. This feature would allow traders to switch between chart timeframes or symbols with a single click, enabling them to quickly assess the accuracy of the indicator signal when the expert advisor opens or closes an order.

4. Expert Timeframe, Pair Selection, and Symbol Management

Expert Timeframe.

  • The Expert Timeframe setting determines the timeframe on which the Expert Advisor will calculate indicators and generate trading signals. By default, it's set to PERIOD_H1, meaning the EA will analyze hourly data.
  • Adjusting this setting can influence the sensitivity of the strategy to market movements. A shorter timeframe, like PERIOD_M15 or PERIOD_M30, can lead to more frequent signals, while a longer timeframe, like PERIOD_H4 or PERIOD_D1, can produce fewer, but potentially more reliable signals.

Pair Selection.

  • The Select Pairs to Trade property allows traders to choose from a predefined list of currency pairs. The default option is typically to trade all 30 pairs, but traders can customize this selection based on their preferences and risk tolerance.
  • Symbol Management with HandlingSymbolArrays The HandlingSymbolArray function plays a crucial role in managing the symbols that the Expert Advisor will trade.
    • To perform the following tasks:
      • Symbol Initialization: Initializes an array to store the selected symbols.
      • Symbol Filtering: Filters the selected symbols based on market conditions or other criteria.
      • Symbol Validation: Ensures that the selected symbols are valid and supported by the trading platform.
      • Symbol Assignment: Assigns the selected symbols to the Expert Advisor's internal variables.
    • By effectively managing symbols, the EA can optimize its performance and reduce the risk of errors.

Validating Pair (Symbol) Names and Error Handling.

  • The Expert Advisor's ability to validate pair names is a critical feature to ensure smooth operation and prevent potential errors. Here's a breakdown of how this process might work:
    • User Input: The trader enters a list of desired pairs in the Expert Advisor's input parameters.
      • Symbol Check: The EA iterates through each pair name and checks its validity:
      • Symbol Existence: The EA verifies if the specified symbol exists in the trading platform's symbol
      • Symbol Format: The EA ensures that the symbol adheres to the correct format (e.g., EURUSD, GBPUSD, XAUUSD).
    • Error Handling:
      • If a symbol is invalid, the EA generates a warning message in the journal or displays an alert to the trader and the EA will removed from the chart.
      • By incorporating robust symbol validation and error handling, the Expert Advisor can maintain its reliability and prevent unexpected issues.

Function: OnChartEvent

The OnChartEvent function handles various chart events, particularly focusing on click events for specific buttons on the chart. This allows for interactive actions based on user input.

Parameters:

  • id: An integer representing the event ID.
  • lparam: A long parameter associated with the event.
  • dparam: A double parameter associated with the event.
  • sparam: A string parameter associated with the event.

Steps:

  • 1. Reset Error State:
    • ResetLastError();
    • Resets any previous error states to start fresh.
  • 2. Set Current Timeframe:
    • ENUM_TIMEFRAMES CCS=mc.TFt;
    • Retrieves the current timeframe setting from the mc object.
  • 3. Handle Object Click Events:
    • Checks if the event ID is CHARTEVENT_OBJECT_CLICK, indicating a click on a chart object.
    • if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam);
  • 4. Button Click Handling:
    • "Set SL/TP All Orders" Button:
      • If this button is clicked, it sets Stop Loss (SL) and Take Profit (TP) for all orders.
      • 
        //--- if "Set SL All Orders" button is click
        if(sparam=="Set SL/TP All Orders") 
          { 
            mc.SetSLTPOrders();
            Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders");
            //--- unpress the button 
            ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false);
            ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0);
            CreateManualPanel();
          }
        
    • "Close All Order" Button:
      • If this button is clicked, it closes all open orders.
      • 
        //--- if "Close All Order" button is click
        if(sparam=="Close All Order") 
          { 
            mc.CloseAllOrders();
            Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders");
            //--- unpress the button 
            ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false);
            ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0);
            CreateManualPanel();
          }
        
    • "Close All Profit" Button:
      • If this button is clicked, it closes all profitable orders.
      •         
        //--- if "Close All Profit" button is click
        if(sparam=="Close All Profit") 
          { 
            mc.ManualCloseAllProfit();
            Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit");
            //--- unpress the button 
            ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false);
            ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0);
            CreateManualPanel();
          }
        
    • "X" Button:
      • If this button is clicked, it deletes all button, label, and rectangle label objects and resets the panel state.
      • 
        //--- if "X" button is click
        if(sparam=="X") 
          { 
            ObjectsDeleteAll(0,0,OBJ_BUTTON);
            ObjectsDeleteAll(0,0,OBJ_LABEL);
            ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL);
            //--- unpress the button 
            ObjectSetInteger(0,"X",OBJPROP_STATE,false);
            ObjectSetInteger(0,"X",OBJPROP_ZORDER,0);
            //--
            DeleteButtonX();
            mc.PanelExtra=false;
            DisplayManualButton();
          }
        
    • "M" Button:
      • If this button is clicked, it toggles the manual panel.
      • 
        //--- if "M" button is click
        if(sparam=="M") 
          { 
            //--- unpress the button 
            ObjectSetInteger(0,"M",OBJPROP_STATE,false);
            ObjectSetInteger(0,"M",OBJPROP_ZORDER,0);
            mc.PanelExtra=true;
            CreateManualPanel();
          }     
        
    • "C" Button:
      • If this button is clicked, it creates the symbol panel.
      •    
        //--- if "C" button is click
        if(sparam=="C") 
          { 
            //--- unpress the button 
            ObjectSetInteger(0,"C",OBJPROP_STATE,false);
            ObjectSetInteger(0,"C",OBJPROP_ZORDER,0);
            mc.PanelExtra=true;
            CreateSymbolPanel();
          }        
        
    • "R" Button:
      • If this button is clicked, it removes the Expert Advisor from the chart.
      •           
        //--- if "R" button is click
        if(sparam=="R") 
          { 
            Alert("-- "+mc.expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart.");
            ExpertRemove();
            //--- unpress the button 
            ObjectSetInteger(0,"R",OBJPROP_STATE,false);
            ObjectSetInteger(0,"R",OBJPROP_ZORDER,0);
            if(!ChartSetSymbolPeriod(0,Symbol(),Period()))
              ChartSetSymbolPeriod(0,Symbol(),Period());
            DeletePanelButton();
            ChartRedraw(0);
          }
        
  • 5. Symbol Button Click:
    • If the length of sparam matches the length of the symbol name, it validates the symbol and changes the chart symbol.
    •         
      //--- if Symbol button is click
      if(lensparam==lensymbol)
        {
          int sx=mc.ValidatePairs(sparam);
          ChangeChartSymbol(mc.AS30[sx],CCS);
          mc.PanelExtra=false;
        }
      
  • 6. Return Statement:
    • Ensures the function exits cleanly.
    • return;

Summary

The OnChartEvent function is crucial for handling user interactions with the chart. By managing clicks on specific buttons, it allows for dynamic actions such as setting SL/TP, closing orders, toggling panels, and changing symbols. This enhances the usability and interactivity of the trading platform.

ChangeChartSymbol Function.

The ChangeChartSymbol function is designed to change the symbol and timeframe of the current chart in the MetaTrader platform. This function also handles resetting and redrawing the chart by unpressing buttons and deleting specific objects.

Parameters:

  • c_symbol: A string representing the new trading symbol (e.g., "EURUSD") to be set on the chart.
  • cstf: An enumeration (ENUM_TIMEFRAMES) indicating the new timeframe to be set for the chart.

Steps:

  • 1. Unpress the Button:
    • ObjectSetInteger(0, c_symbol, OBJPROP_STATE, false); ObjectSetInteger(0, c_symbol, OBJPROP_ZORDER, 0);
    • Unpresses the button associated with the given symbol by setting its state (OBJPROP_STATE) to false and its Z-order (OBJPROP_ZORDER) to 0.
  • 2. Delete Chart Objects:
    • ObjectsDeleteAll(0, 0, OBJ_BUTTON); ObjectsDeleteAll(0, 0, OBJ_LABEL); ObjectsDeleteAll(0, 0, OBJ_RECTANGLE_LABEL);
    • Deletes all objects of type button (OBJ_BUTTON), label (OBJ_LABEL), and rectangle label (OBJ_RECTANGLE_LABEL) from the chart to reset the chart's visual elements.
  • 3. Set Chart Symbol and Timeframe:
    • ChartSetSymbolPeriod(0, c_symbol, cstf);
    • Changes the chart's symbol to c_symbol and sets the timeframe to cstf.
  • 4. Redraw the Chart:
    • ChartRedraw(0);
    • Forces the chart to redraw to reflect the changes made, ensuring the new symbol and timeframe are properly displayed.
  • 5. Return Statement:
    • return;
    • Ensures the function exits cleanly.

Summary

The ChangeChartSymbol function is a crucial utility for dynamically changing the trading symbol and timeframe of a chart in MetaTrader. By unpressing buttons, deleting specific objects, setting the new symbol and timeframe, and redrawing the chart, it ensures a smooth transition and clear presentation of the updated chart.

Thank you for reading this article How to create a FiboPivotCandleBar Expert Advisor that trades Multi-Currency for MT5.

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

Please download the Expert Advisor: ExpFPCB_MCEA

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: ExpFPCB_MCEA.mq5.

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

YouTube Channel: @ForexHomeExperts

YouTube Playlist: @ForexHomeExperts YouTube Playlist

Sunday, November 24, 2024

In this article I will discuss how to add alerts to indicator programs or Expert Advisors using MQL5.

The alerts that will be discussed include sound and pop-up alerts on MT5 or MT4, notification alerts and email alerts.

But before discussing the creation of the program, we need to know what the benefits of alerts in indicator or expert advisor programs actually are?

the benefits of alerts in indicator or expert advisor programs

What are the benefits of alerts in indicator or expert advisor programs in MT4 or MT5?

Alerts in MT4 and MT5 indicators and expert advisors (EAs) are invaluable tools for traders. They provide timely notifications about specific market conditions, allowing traders to react quickly and make informed decisions.

Here are the key benefits of using alerts:

1.Timely Notifications:

  • Real-time alerts: Receive immediate notifications when a specific condition is met, such as a price crossing a moving average or a support/resistance level being breached.
  • No Constant Monitoring: You don't have to constantly stare at charts to catch these opportunities. Alerts can notify you even when you're away from your computer.

2. Improved Decision-Making:

  • Quick Reaction: Alerts allow you to react promptly to market changes, potentially leading to better entry and exit points.
  • Reduced Emotional Trading: By automating notifications, you can avoid impulsive decisions based on fear or greed.

3. Enhanced Risk Management:

  • Stop-Loss and Take-Profit Alerts: Set up alerts to trigger when your positions reach predefined profit or loss levels.
  • Risk Management Strategies: Automate risk management strategies, such as trailing stop-loss orders, to protect your profits.

4. Increased Efficiency:

  • Automation: Automate repetitive tasks like monitoring indicators and placing orders.
  • Focus on Other Tasks: Spend more time on other aspects of your trading strategy, such as fundamental analysis or portfolio management.

5. Scalping and Day Trading:

  • Quick Entry and Exit: Alerts can help you capitalize on short-term price movements and scalping opportunities.

Remember:

While alerts can be a powerful tool, it's important to use them wisely. Overreliance on alerts can lead to impulsive decisions and potential losses. Always combine alerts with sound risk management practices and thorough analysis.

In this article I will demonstrate the implementation of alerts using the modified MACD indicator by adding alerts.

First of all, I will create a template that is usually used to add alerts to indicators or expert advisors in MQL5.

Template program alerts:


//+------------------------------------------------------------------+
//|                                                  MACD_Alerts.mq5 |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com ||
//|                              https://www.mql5.com/en/users/3rjfx |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2000-2024, MetaQuotes Ltd."
#property link        "https://www.mql5.com"
#property link        "https://www.mql5.com/en/users/3rjfx"
#property description "Moving Average Convergence/Divergence"
#property version     "1.00"
#property description "Modify by: Roberto Jacobs (3rjfx) ~ Date: 2024-11-24"

#property indicator_separate_window
//---


//-- Enumeration
enum YN
 {
   No,  
   Yes
 };
//---
//--- 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)

//---Variables used in alerts
double MACDAlert[];
string AlertTxt;
string _name;
int curAlert;
int prvAlert;
//--
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
   
   //--
   _name="Your Indicator Name";
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   
   
   
   //--
   double priceB=0.0;
   double priceS=0.0;
   datetime dtB=0;
   datetime dtS=0;
   //--
   if(alerts==Yes||UseEmailAlert==Yes||UseSendnotify==Yes)
     {
       if(curAlert==1 && curAlert!=prvAlert)
         {
           AlertTxt="Your Alerts Text here";
           Do_Alerts(AlertTxt,dtB);
           prvAlert=curAlert;
         }
       if(curAlert==-1 && curAlert!=prvAlert)
         {
           AlertTxt="Your Alerts Text here";
           Do_Alerts(AlertTxt,dtS);
           prvAlert=curAlert;
         }
     }
   //--
   
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

string TF2Str(int period)
  {
   switch(period)
     {
       //--
       case PERIOD_M1:   return("M1");
       case PERIOD_M2:   return("M2");
       case PERIOD_M3:   return("M3");
       case PERIOD_M4:   return("M4");
       case PERIOD_M5:   return("M5");
       case PERIOD_M6:   return("M6");
       case PERIOD_M10:  return("M10");
       case PERIOD_M12:  return("M12");
       case PERIOD_M15:  return("M15");
       case PERIOD_M20:  return("M20");
       case PERIOD_M30:  return("M30");
       case PERIOD_H1:   return("H1");
       case PERIOD_H2:   return("H2");
       case PERIOD_H3:   return("H3");
       case PERIOD_H4:   return("H4");
       case PERIOD_H6:   return("H6");
       case PERIOD_H8:   return("H8");
       case PERIOD_H12:  return("H12");
       case PERIOD_D1:   return("D1");
       case PERIOD_W1:   return("W1");
       case PERIOD_MN1:  return("MN");
       //--
     }
   return(string(period));
  }  
//---------//

void Do_Alerts(string msgText,datetime Altime)
  {
//---
    //--
    Print("--- "+Symbol()+": "+msgText+
          "\n --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert("--- "+Symbol()+": "+msgText+
              " --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(_name," --- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                       "\n--- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(_name+"--- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                      "\n --- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//

Enumeration.

An enum (short for "enumeration") is a distinct type that consists of a set of named values called elements or members. Enums are used to represent a collection of related constants in a more readable and maintainable way.

Enums are particularly useful for representing a series of constants or actions that are related in a fixed manner, and this will make our code more readable and less error-prone.

The YN enum we've defined contains two possible values: No and Yes.

Breakdown:

  • enum YN: This defines a new enumeration type named YN.
  • { No, Yes }: These are the members of the enum, representing two possible states or values: No and Yes.

Then we use that enumeration in the indicator input properties.


//--- 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)

In order not to disturb the MACD buffer calculation, we add a buffer variable named MACDAlert. In this MACDAlert buffer we will copy all values from the MACD buffer.

Then below are some variables that will be used in the alerts that we must place on the global scope of the indicator or expert advisor.

  • string AlertTxt: For the alert text to be created.
  • string _name: Name of the indicator or program that will provide the alert.
  • int curAlert: Current alert value, with a value of 1 for an Up or Buy Alert and minus 1 for a Down or Sell Alert.
  • int prvAlert: This variable is to hold the current alert value, to prevent the alert from repeating without interruption.

Explanation

Variables Initialization:


datetime dtB=0;
datetime dtS=0;
double priceB=0.0;
double priceS=0.0;

These variables store the date and price when a Moving Average Convergence Divergence (MACD) signal occurs. dtB and dtS store the date for the Buy and Sell signals, respectively. priceB and priceS store the prices at those times.

Array Manipulation:


ArraySetAsSeries(time, true);
ArraySetAsSeries(close, true);
ArrayCopy(MACDAlert, ExtMacdBuffer, 0, 0, WHOLE_ARRAY);
ArraySetAsSeries(MACDAlert, true);

These lines set up the arrays for time, closing prices, and MACD values to be used as series (reverse the array indexing). ArrayCopy copies the ExtMacdBuffer into MACDAlert.

Loop to Detect MACD Crossings:


for (int x = calculated - 2; x >= 0; x--)
{
    if (MACDAlert[x+1] <= 0.0 && MACDAlert[x] > 0.0)
    {
        curAlert = 1;
        dtB = time[x];
        priceB = close[x];
    }
    if (MACDAlert[x+1] >= 0.0 && MACDAlert[x] < 0.0)
    {
        curAlert = -1;
        dtS = time[x];
        priceS = close[x];
    }
}

This loop iterates over the MACDAlert array to detect crossings of the MACD line over the zero line.

  • If the MACD value crosses from negative to positive (MACDAlert[x+1] <= 0.0 && MACDAlert[x] > 0.0), a buy signal is generated, and the current time and price are recorded.
  • If the MACD value crosses from positive to negative (MACDAlert[x+1] >= 0.0 && MACDAlert[x] < 0.0), a sell signal is generated, and the current time and price are recorded.

Alerts:


if (alerts == Yes || UseEmailAlert == Yes || UseSendnotify == Yes)
{
    if (curAlert == 1 && curAlert != prvAlert)
    {
        AlertTxt = "MACD cross from below to above zero : " + DoubleToString(priceB, Digits()) + " @ bar shift: " + (string)iBarShift(Symbol(), 0, dtB, false);
        Do_Alerts(AlertTxt, dtB);
        prvAlert = curAlert;
    }
    if (curAlert == -1 && curAlert != prvAlert)
    {
        AlertTxt = "MACD cross from above to below zero : " + DoubleToString(priceS, Digits()) + " @ bar shift: " + (string)iBarShift(Symbol(), 0, dtS, false);
        Do_Alerts(AlertTxt, dtS);
        prvAlert = curAlert;
    }
}

If any alerts are enabled (regular alerts, email alerts, or notifications), the code sends an alert whenever a new MACD crossing signal is detected.

  • If a buy signal is detected (curAlert == 1) and it differs from the previous signal (curAlert != prvAlert), an alert message is constructed and sent.
  • If a sell signal is detected (curAlert == -1) and it differs from the previous signal, a similar alert message is constructed and sent.

Summary:

The code primarily focuses on detecting MACD zero-line crossings and issuing alerts when these crossings occur. This is useful in trading algorithms where MACD crossings can indicate buy or sell signals.


string TF2Str(int period)
  {
   switch(period)
     {
       //--
       case PERIOD_M1:   return("M1");
       case PERIOD_M2:   return("M2");
       case PERIOD_M3:   return("M3");
       case PERIOD_M4:   return("M4");
       case PERIOD_M5:   return("M5");
       case PERIOD_M6:   return("M6");
       case PERIOD_M10:  return("M10");
       case PERIOD_M12:  return("M12");
       case PERIOD_M15:  return("M15");
       case PERIOD_M20:  return("M20");
       case PERIOD_M30:  return("M30");
       case PERIOD_H1:   return("H1");
       case PERIOD_H2:   return("H2");
       case PERIOD_H3:   return("H3");
       case PERIOD_H4:   return("H4");
       case PERIOD_H6:   return("H6");
       case PERIOD_H8:   return("H8");
       case PERIOD_H12:  return("H12");
       case PERIOD_D1:   return("D1");
       case PERIOD_W1:   return("W1");
       case PERIOD_MN1:  return("MN");
       //--
     }
   return(string(period));
  }  
//---------//

This code defines a function TF2Str that converts a time period constant into a string representation. It uses a switch statement to match different period constants and returns the corresponding string.

Explanation:

  • 1. Function Signature: string TF2Str(int period): The function returns a string and takes an int parameter named period.
  • 2. Switch Statement: The switch statement evaluates the period and returns a corresponding string for each case.
  • 3. Case Statements: case PERIOD_M1: return("M1");: If period equals PERIOD_M1, the function returns the string "M1". This pattern is repeated for each predefined period constant, such as PERIOD_M2, PERIOD_M3, etc.
  • Default Case: If the period does not match any of the predefined cases, the function converts the period integer to a string and returns it. This ensures that the function always returns a valid string.

Use Case: This function is useful in scenarios where you need to convert time period constants (used in trading software or financial applications) to their string representations for display or logging purposes.

Function Alerts:

Function Definition:


void Do_Alerts(string msgText,datetime Altime)
  {
//---
    //--
    Print("--- "+Symbol()+": "+msgText+
          "\n --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(alerts==Yes)
      {
        Alert(_name," --- "+Symbol()+": "+msgText+
              " --- at: ",TimeToString(Altime,TIME_DATE|TIME_MINUTES));
      }
    //--
    if(UseEmailAlert==Yes) 
      SendMail(_name," --- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                       "\n--- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    if(UseSendnotify==Yes) 
      SendNotification(_name+"--- "+Symbol()+" "+TF2Str(Period())+": "+msgText+
                      "\n --- at: "+TimeToString(Altime,TIME_DATE|TIME_MINUTES));
    //--
    return;
    //--
//---
  } //-end Do_Alerts()
//---------//

This function, Do_Alerts, sends different types of alerts (print messages, alerts, emails, notifications) based on MACD signal crosses detected. Here's a detailed breakdown:

  • 1. Print Message: This line prints the alert message along with the time of the alert. The Symbol() function returns the current symbol (currency pair or instrument), and TimeToString converts the datetime to a human-readable string format.
  • 2. Conditional Alerts:
    • Regular Alerts: If alerts are enabled (Yes), it sends an alert message.
    • Email Alerts: If UseEmailAlert is enabled, it sends an email with the alert message. The TF2Str(Period()) function converts the period to a string representation.
    • Push Notifications: If UseSendnotify is enabled, it sends a push notification with the alert message.
  • 3. Return Statement: The function ends here. The return statement ensures the function exits after executing the necessary alert commands.

Summary:

This function is designed to handle various types of alerts based on market conditions or trading signals. It ensures that you are notified through different channels (console print, alert, email, and push notification) whenever an important event occurs in your trading strategy.

The programs and functions in the template that I show above are just examples, they can be applied to both custom indicators and expert advisors with MQL5 and MQL4.

If the function template is applied to MQL4, then you must delete the timeframe periods that do not exist in MQL4, because MQL5 uses 21 timeframes while MQL4 only uses 9 timeframes.

You can adjust and modify the handling according to your needs.

MACD_Alerts indicator test results:

MACD_Alerts indicator test results

That's all for the article How to add Alerts to MT4 and MT5 programs, hopefully it's useful.

Thank you for reading.

Please download the MACD Indicator Alert: MACD Alert

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: MACD_Alerts Indicator.

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...