//+------------------------------------------------------------------+
//|                                                         MACD.mq4 |
//|                                Copyright © 2005, David W. Thomas |
//|                                           mailto:davidwt@usa.net |
//+------------------------------------------------------------------+
// This is the correct computation and display of MACD.
#property copyright "Copyright © 2005, David W. Thomas"
#property link      "mailto:davidwt@usa.net"
#property description "MACD True"
#property strict
//---
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots 3
//--- macd & signal lines
#property indicator_color1 clrBlue
#property indicator_color2 clrRed
//--- macd histogram
#property indicator_color3 clrForestGreen,clrFireBrick
#property indicator_width3 2
//--- input parameters
input string  str2zs = "================================================"; //---
input string  str5sj = "==== MACD Settings ===="; //---
input string  str2el = "================================================"; //---
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;
input int     FastMAPeriod = 12;
input int     SlowMAPeriod = 26;
input int     SignalMAPeriod = 9;
input ENUM_MA_METHOD MAMethod = MODE_EMA;
input ENUM_APPLIED_PRICE AppliedPrice = PRICE_CLOSE;
//--- signal line
input string  str6as = "================================================"; //---
input string  str3yf = "==== Arrows & Alerts For Signal Line Cross ===="; //---
input string  str7kp = "================================================"; //---
input bool    ShowSignalLineCrossArrows = true;
input bool    SendSignalLineCrossAlert = false;
input bool    SendSignalLineCrossText = false;
input double  SignalLineGap = 3.5; //gap needed to trigger alert, 0=off
input color   BullishSignalLineCrossArrowColor = clrGreen;
input int     BullishSignalLineCrossArrowCode = 233;
input int     BullishSignalLineCrossArrowWidth = 2;
input color   BearishSignalLineCrossArrowColor = clrRed;
input int     BearishSignalLineCrossArrowCode = 234;
input int     BearishSignalLineCrossArrowWidth = 2;
//--- zero line
input string  str6st = "================================================"; //---
input string  str3yk = "==== Arrows & Alerts For Zero Line Cross ===="; //---
input string  str7im = "================================================"; //---
input bool    ShowZeroLineCrossArrows = true;
input bool    SendZeroLineCrossAlert = false;
input bool    SendZeroLineCrossText = false;
input double  ZeroLineGap = 2.5; //gap needed to trigger alert, 0=off
input color   BullishZeroLineCrossArrowColor = clrGreen;
input int     BullishZeroLineCrossArrowCode = 139;
input int     BullishZeroLineCrossArrowWidth = 2;
input color   BearishZeroLineCrossArrowColor = clrRed;
input int     BearishZeroLineCrossArrowCode = 139;
input int     BearishZeroLineCrossArrowWidth = 2;
//--- arrow spacing
input string  str6dv = "================================================"; //---
input string  str3hf = "==== Arrow Spacing ===="; //---
input string  str7hp = "================================================"; //---
input int     ATRPeriodArrows = 20;
input double  ATRMultiplierArrows = 1.25;
////////////////////////////////////////////////////////////////////////////////////////
double ArrowSpacing;
string ObjDel="_macdta"; // unique to this indicator
double ATR[];
////////////////////////////////////////////////////////////////////////////////////////

//--- buffers
double MACDLineBuffer[];
double SignalLineBuffer[];
double HistogramHighBuffer[];
double HistogramLowBuffer[];
double HistogramColorBuffer[];

//--- MA handles
int handleFastMa;
int handleSlowMa;
int handleATR;

//--- variables
double alpha = 0;
double alpha_1 = 0;
bool isBullishSignalLineCrossActive=false;
bool isBearishSignalLineCrossActive=false;
bool isBullishZeroLineCrossActive=false;
bool isBearishZeroLineCrossActive=false;
double fastMA[], slowMA[];
bool arrowsWereDrawnInHistory=false;

/////////////////////////////////////////////////////////////////////////////////////////////
//Calculating the factor needed to turn pip values into their correct points value to accommodate different Digit size.
//Thanks to Lifesys for providing this code. Coders, you need to briefly turn off Wrap and turn on a mono-spaced font to view this properly and see how easy it is to make changes.
string pipFactor[]  = {"JPY","XAG","SILVER","BRENT","WTI","XAU","GOLD","SP500","S&P","UK100","WS30","DAX30","DJ30","NAS100","CAC400"};
double pipFactors[] = { 100,  100,  100,     100,    100,  10,   10,    10,     10,   1,      1,     1,      1,     1,       1};
double factor;//For pips/points stuff. Set up in int init()
/////////////////////////////////////////////////////////////////////////////////////////////

//Time frame arrays
string          TFstr[]  = {"Current","M1","M2","M3","M4","M5","M6","M10","M12","M15",
                            "M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN1"};
ENUM_TIMEFRAMES TFenum[] = {PERIOD_CURRENT,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};
int             TFint[]  = {0,1,2,3,4,5,6,10,12,15,20,30,16385,16386,16387,16388,16390,16392,16396,16408,32769,49153};

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- name for DataWindow and indicator subwindow label
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
   string short_name=StringFormat("MACD(%s/%s, %d, %d, %d)",_Symbol,TFEnumToStr(TimeFrame),
                           FastMAPeriod,SlowMAPeriod,SignalMAPeriod);
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   
//--- macd line
   SetIndexBuffer(0,MACDLineBuffer,INDICATOR_DATA);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,SlowMAPeriod);
   PlotIndexSetString(0,PLOT_LABEL,"MACD Line");
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   
//--- signal line
   SetIndexBuffer(1,SignalLineBuffer,INDICATOR_DATA);
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_DOT);
   PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,SlowMAPeriod+SignalMAPeriod);
   PlotIndexSetString(1,PLOT_LABEL,"Signal Line");
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
   
//--- Histogram 
   SetIndexBuffer(2,HistogramHighBuffer,INDICATOR_DATA); 
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_COLOR_HISTOGRAM2);
   PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,SlowMAPeriod+SignalMAPeriod);
   PlotIndexSetString(2,PLOT_LABEL,"MACD Histogram");
   
//--- Histogram color    
   SetIndexBuffer(3,HistogramLowBuffer,INDICATOR_DATA);   
   SetIndexBuffer(4,HistogramColorBuffer,INDICATOR_COLOR_INDEX);
   
//--- get MA handles
   handleFastMa=iMA(_Symbol,TimeFrame,FastMAPeriod,0,MAMethod,AppliedPrice);
   //--- if the handle is not created
   if(handleFastMa==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA Fast indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(_Period),
                  GetLastError());
      //--- the indicator is stopped early
      return(INIT_FAILED);
     }
   
   handleSlowMa=iMA(_Symbol,TimeFrame,SlowMAPeriod,0,MAMethod,AppliedPrice);
   //--- if the handle is not created
   if(handleSlowMa==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iMA Slow indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(_Period),
                  GetLastError());
      //--- the indicator is stopped early
      return(INIT_FAILED);
     }
     
//--- ATR handle   
   handleATR = iATR(_Symbol,_Period,ATRPeriodArrows);
   //--- if the handle is not created
   if(handleATR==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the ATR indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(_Period),
                  GetLastError());
      //--- the indicator is stopped early
      return(INIT_FAILED);
     }
     
//---
	alpha = 2.0 / (SignalMAPeriod + 1.0);
	alpha_1 = 1.0 - alpha;
	
//--- pips factor
   factor = PFactor(_Symbol);
	
//--- initialization done
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| custom deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{ 
//--- Delete objects when indicator is removed from chart
//--- Add "+ObjDel" to end of object's name
//--- ObjDel --> unique indicator identifier   
   DeleteChartObjects(ObjDel);
   
   if(handleFastMa!=INVALID_HANDLE)
      IndicatorRelease(handleFastMa);
      
   if(handleSlowMa!=INVALID_HANDLE)
      IndicatorRelease(handleSlowMa);
      
   if(handleATR!=INVALID_HANDLE)
      IndicatorRelease(handleATR);
           
//--- clear comment
   Comment("");
   
//---  
}
//+------------------------------------------------------------------+
//| 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[])
{
//--- local variables
   int limit=0;
   bool isNewBar = IsNewBar();
   
//--- array set as series   
   ArraySetAsSeries(time,true);
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(MACDLineBuffer,true);
   ArraySetAsSeries(SignalLineBuffer,true);
   ArraySetAsSeries(HistogramHighBuffer,true);
   ArraySetAsSeries(HistogramLowBuffer,true);
   ArraySetAsSeries(HistogramColorBuffer,true);
      
//--- must wait for OnCalculate() before working with MTF handles
//--- https://www.mql5.com/en/forum/168437
   if (!arrowsWereDrawnInHistory && prev_calculated>0)
   {
      int calculated=BarsCalculated(handleFastMa);
      if(calculated<=0)
      {
         Print("Not all data of handleFastMa is calculated (",calculated,"bars ). Error",GetLastError());
         return(0);
      }
      calculated=BarsCalculated(handleSlowMa);
      if(calculated<=0)
      {
         Print("Not all data of handleSlowMa is calculated (",calculated,"bars ). Error",GetLastError());
         return(0);
      }
   }      
   
//--- check for possible errors
   if (prev_calculated<0) return(-1);
//--- starting index (limit) for bars recalculation loop
   if(prev_calculated==0)// checking the first call
      limit=rates_total-4-MathMax(ATRPeriodArrows,SlowMAPeriod); // starting index first call
   else
      limit=rates_total-prev_calculated; // starting index    
      
//--- draw arrows in history
   if (!arrowsWereDrawnInHistory && prev_calculated>0)
   {
      for(int i=rates_total-4-MathMax(ATRPeriodArrows,SlowMAPeriod); i>=0; i--)
      {
         CalculateMACD(i);      
         DrawArrowsAndSendAlerts(i, time, open, close, high, low, false); 
      }
      
      // set flag
      arrowsWereDrawnInHistory = true;    
   }
         
//--- draw arrows and send alerts
   if (arrowsWereDrawnInHistory)
   {
      for(int i=limit; i>=0; i--)
      {         
         CalculateMACD(i);
               
         if (isNewBar)
            DrawArrowsAndSendAlerts(i+1, time, open, close, high, low, true);         
      }  
   }
      
//--- 
   return(rates_total);
}

//+------------------------------------------------------------------+
//| CalculateMACD()                                                  |
//+------------------------------------------------------------------+
void CalculateMACD(int i)
{   
   //--- bar shift
   int bar = iBarShift(_Symbol,TimeFrame,iTime(_Symbol,_Period,i));
   if (bar < 0) bar = 0;   

   //iMA(_Symbol,TimeFrame,FastMAPeriod,0,MODE_EMA,PRICE_CLOSE,bar)
   //iMA(_Symbol,TimeFrame,SlowMAPeriod,0,MODE_EMA,PRICE_CLOSE,bar)
   FillArrayFromBuffer(handleFastMa,0,bar,1,fastMA,true,"iMA Fast"); 
   FillArrayFromBuffer(handleSlowMa,0,bar,1,slowMA,true,"iMA Slow");
   
   //--- MACD Line
   MACDLineBuffer[i] = fastMA[0] - slowMA[0];
   
   //--- Signal Line
   SignalLineBuffer[i] = alpha*MACDLineBuffer[i] + alpha_1*SignalLineBuffer[i+1];
   
   //--- Histogram
   double hist = MACDLineBuffer[i] - SignalLineBuffer[i];
   if (hist >= 0)
   {
      HistogramHighBuffer[i] = hist;
      HistogramLowBuffer[i] = 0;
      HistogramColorBuffer[i] = 0;
   }
   if (hist < 0)
   {
      HistogramHighBuffer[i] = 0;
      HistogramLowBuffer[i] = hist;         
      HistogramColorBuffer[i] = 1;
   }
}

//+------------------------------------------------------------------+
//| DrawArrowsAndSendAlerts()                                        |
//+------------------------------------------------------------------+
void DrawArrowsAndSendAlerts(int i, 
                             const datetime &myTime[], 
                             const double &myOpen[], 
                             const double &myClose[], 
                             const double &myHigh[], 
                             const double &myLow[], 
                             bool isNewBar)
{
//--- ATR arrow spacing
    FillArrayFromBuffer(handleATR,0,i,1,ATR,true,"ATR");
    ArrowSpacing = ATR[0] * ATRMultiplierArrows;
   
//--- signal line cross
   bool isBullishSignalLineCross = false;
   bool isBearishSignalLineCross = false;
   
   //isBullishSignalLineCross = (MACDLineBuffer[i+1] <= SignalLineBuffer[i+1] && MACDLineBuffer[i] > SignalLineBuffer[i]);
   //isBearishSignalLineCross = (MACDLineBuffer[i+1] >= SignalLineBuffer[i+1] && MACDLineBuffer[i] < SignalLineBuffer[i]);

//--- reset bullish 'active' flag 
   //if (MACDLineBuffer[i+1] >= SignalLineBuffer[i+1] && MACDLineBuffer[i] < SignalLineBuffer[i])
      //isBullishSignalLineCrossActive = false;
      
//--- reset bearish 'active' flag  
   //if (MACDLineBuffer[i+1] <= SignalLineBuffer[i+1] && MACDLineBuffer[i] > SignalLineBuffer[i])
      //isBearishSignalLineCrossActive = false;

//--- bullish cross
   if (MACDLineBuffer[i] > SignalLineBuffer[i]+SignalLineGap/factor && !isBullishSignalLineCrossActive)
   {
      isBullishSignalLineCross = true;
      isBullishSignalLineCrossActive = true;
      isBearishSignalLineCrossActive = false;
   }
   
//--- bearish cross
   if (MACDLineBuffer[i] < SignalLineBuffer[i]-SignalLineGap/factor && !isBearishSignalLineCrossActive)
   {
      isBearishSignalLineCross = true;
      isBearishSignalLineCrossActive = true;
      isBullishSignalLineCrossActive = false;
   }
   
//--- bullish arrow and alert
   if (isBullishSignalLineCross)
   {          
      // send alert
      if (SendSignalLineCrossAlert && isNewBar)
      {
         string str = "Bullish Signal Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
         SendAlert(str,SendSignalLineCrossAlert,SendSignalLineCrossText);
      }
         
      // draw arrow 
      if (ShowSignalLineCrossArrows)
      {
         string str = "Bullish_Signal_Line_Cross_Arrow";
         drawArrow(i, myLow[i], myHigh[i], myTime[i], true, ArrowSpacing, BullishSignalLineCrossArrowColor, BullishSignalLineCrossArrowCode, BullishSignalLineCrossArrowWidth, str);
      }
   }
   
//--- bearish arrow and alert
   if (isBearishSignalLineCross)
   {          
      // send alert
      if (SendSignalLineCrossAlert && isNewBar)
      {
         string str = "Bearish Signal Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
         SendAlert(str,SendSignalLineCrossAlert,SendSignalLineCrossText);
      }
        
      // draw arrow 
      if (ShowSignalLineCrossArrows)
      {
         string str = "Bearish_Signal_Line_Cross_Arrow";
         drawArrow(i, myLow[i], myHigh[i], myTime[i], false, ArrowSpacing, BearishSignalLineCrossArrowColor, BearishSignalLineCrossArrowCode, BearishSignalLineCrossArrowWidth, str);
      }
   }
   
   //
   //
   //

//--- zero line cross
   bool isBullishZeroLineCross = false;
   bool isBearishZeroLineCross = false;
   
   //isBullishZeroLineCross = (MACDLineBuffer[i+1] <= 0 && MACDLineBuffer[i] > 0);
   //isBearishZeroLineCross = (MACDLineBuffer[i+1] >= 0 && MACDLineBuffer[i] < 0);

//--- bullish cross
   if (MACDLineBuffer[i] > ZeroLineGap/factor && !isBullishZeroLineCrossActive)
   {
      isBullishZeroLineCross = true;
      isBullishZeroLineCrossActive = true;
      isBearishZeroLineCrossActive = false;
   }
   
//--- bearish cross
   if (MACDLineBuffer[i] < -ZeroLineGap/factor && !isBearishZeroLineCrossActive)
   {
      isBearishZeroLineCross = true;
      isBearishZeroLineCrossActive = true;
      isBullishZeroLineCrossActive = false;
   }

//--- bullish arrow and alert
   if (isBullishZeroLineCross)
   {          
      // send alert
      if (SendZeroLineCrossAlert && isNewBar)
      {
         string str = "Bullish Zero Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
         SendAlert(str,SendZeroLineCrossAlert,SendZeroLineCrossText);
      }
         
      // draw arrow 
      if (ShowZeroLineCrossArrows)
      {
         string str = "Bullish_Zero_Line_Cross_Arrow";
         drawArrow(i, myLow[i], myHigh[i], myTime[i], true, ArrowSpacing, BullishZeroLineCrossArrowColor, BullishZeroLineCrossArrowCode, BullishZeroLineCrossArrowWidth, str);
      }
   }
   
//--- bearish arrow and alert
   if (isBearishZeroLineCross)
   {          
      // send alert
      if (SendZeroLineCrossAlert && isNewBar)
      {
         string str = "Bearish Zero Line Cross "+_Symbol+" "+TFToStr(_Period)+" | "+TimeToString(TimeCurrent(),TIME_DATE)+" "+TimeToString(TimeCurrent(),TIME_MINUTES);
         SendAlert(str,SendZeroLineCrossAlert,SendZeroLineCrossText);
      }
        
      // draw arrow 
      if (ShowZeroLineCrossArrows)
      {
         string str = "Bearish_Zero_Line_Cross_Arrow";
         drawArrow(i, myLow[i], myHigh[i], myTime[i], false, ArrowSpacing, BearishZeroLineCrossArrowColor, BearishZeroLineCrossArrowCode, BearishZeroLineCrossArrowWidth, str);
      }
   }
}

//+------------------------------------------------------------------+
//| drawArrow()                                                      |
//+------------------------------------------------------------------+
void drawArrow(int i, 
               double myLow, 
               double myHigh,
               datetime myTime, 
               bool upArrow, 
               double arrowSpacing, 
               color myColor, 
               int myArrowCode, 
               int myWidth, 
               string myName)
{    
   string name = myName+"_"+TimeToString(myTime)+ObjDel; 
   ObjectCreate(0,name,OBJ_ARROW,0,0,0,0,0);   
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,myArrowCode);
   ObjectSetInteger(0,name,OBJPROP_COLOR,myColor);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,myWidth);
   ObjectSetInteger(0,name,OBJPROP_TIME,myTime);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
   if (upArrow)
      ObjectSetDouble(0,name,OBJPROP_PRICE,myLow-arrowSpacing);
   else  
      ObjectSetDouble(0,name,OBJPROP_PRICE,myHigh+arrowSpacing);
}

//+------------------------------------------------------------------+
// IsNewBar()                                                        |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime lastTime;
    bool isNewBar = (iTime(_Symbol,_Period,0) != lastTime);
    lastTime = iTime(_Symbol,_Period,0);
    
    return(isNewBar);
}

//+------------------------------------------------------------------+
// StringUpper(string str)                                           |
//+------------------------------------------------------------------+
// Converts any lowercase characters in a string to uppercase
// Usage:    string x=StringUpper("The Quick Brown Fox")  returns x = "THE QUICK BROWN FOX"
string StringUpper(string str)
{
  string outstr = "";
  string lower  = "abcdefghijklmnopqrstuvwxyz";
  string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  for(int i=0; i<StringLen(str); i++)  {
    int t1 = StringFind(lower,StringSubstr(str,i,1),0);
    if (t1 >=0)  
      outstr = outstr + StringSubstr(upper,t1,1);
    else
      outstr = outstr + StringSubstr(str,i,1);
  }
  return(outstr);
  
} //End StringUpper(string str)

//+------------------------------------------------------------------+
//| StrToTF()                                                        |
//+------------------------------------------------------------------+
int StrToTF(string tfs)
{
   StringToUpper(tfs);
   
   for(int i=ArraySize(TFenum)-1; i>=0; i--)
      if(tfs==TFstr[i]) 
         return(TFenum[i]);
         
   return(_Period);
}

//+------------------------------------------------------------------+
//| TFToStr()                                                        |
//+------------------------------------------------------------------+
string TFToStr(int tf)
{
   for(int i=ArraySize(TFint)-1; i>=0; i--) 
      if(tf==TFint[i]) 
         return(TFstr[i]);
   
   return("Current");
}

//+------------------------------------------------------------------+
//| TFEnumToStr()                                                        |
//+------------------------------------------------------------------+
string TFEnumToStr(ENUM_TIMEFRAMES tf)
{
   string str="Current";
   
   for (int i=ArraySize(TFenum)-1; i>=0; i--) 
      if (tf==TFenum[i]) 
         str=TFstr[i];
         
   if (str=="Current")
      str=TFToStr(_Period);
   
   return(str);
}

//+------------------------------------------------------------------+
//| TFCurrentToEnum()                                                |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES TFCurrentToEnum(ENUM_TIMEFRAMES tf)
{
   if(tf == PERIOD_CURRENT)
   {
      int period=_Period;
      
      for(int i=ArraySize(TFint)-1; i>=0; i--) 
      if(period==TFint[i]) 
         return(TFenum[i]);   
   }
   
   return(tf);
}

//+------------------------------------------------------------------+
//| SendAlert()                                                      |
//+------------------------------------------------------------------+
void SendAlert(string sMsg, bool popAlert, bool textMsg)
{
   if(popAlert)
      Alert(sMsg);
   if(textMsg)
      SendNotification(sMsg);   
}

//+------------------------------------------------------------------+
//| Pip Factor                                                       |
//+------------------------------------------------------------------+
double PFactor(string symbol)
{
   //This code supplied by Lifesys. Many thanks Paul - we all owe you. 
   //Gary was trying to make me see this, but I could not understand his explanation. 
   //Paul used Janet and John words.
   
   for ( int i = ArraySize(pipFactor)-1; i >=0; i-- ) 
      if (StringFind(symbol,pipFactor[i],0) != -1) 
         return (pipFactors[i]);
   return(10000);

}//End double PFactor(string pair)


//+------------------------------------------------------------------+
//| CloseEnough()                                                    |
//+------------------------------------------------------------------+
bool CloseEnough(double num1, double num2)
{
   /*
   This function addresses the problem of the way in which mql4 compares doubles. It often messes up the 8th
   decimal point.
   For example, if A = 1.5 and B = 1.5, then these numbers are clearly equal. Unseen by the coder, mql4 may
   actually be giving B the value of 1.50000001, and so the variable are not equal, even though they are.
   This nice little quirk explains some of the problems I have endured in the past when comparing doubles. This
   is common to a lot of program languages, so watch out for it if you program elsewhere.
   Gary (garyfritz) offered this solution, so our thanks to him.
   */
   
   if (num1 == 0 && num2 == 0) return(true); //0==0
   if (MathAbs(num1 - num2) / (MathAbs(num1) + MathAbs(num2)) < 0.00000001) return(true);
   
   //Doubles are unequal
   return(false);

}//End bool CloseEnough(double num1, double num2)

//+------------------------------------------------------------------+
//| DeleteChartObjects()                                             |
//+------------------------------------------------------------------+
void DeleteChartObjects(string str)
{
   // Delete objects when indicator is removed from chart
   // Add "+ObjDel" to end of object's name
   // ObjDel --> unique indicator identifier 
   for(int i=ObjectsTotal(0)-1; i>=0; i--)
   {
      string name=ObjectName(0,i);
      if(StringFind(name, str, 0) != -1)
      {
         ObjectDelete(0,name);
      }
   }
}

//+------------------------------------------------------------------+ 
//|                                                                  | 
//+------------------------------------------------------------------+ 
bool FillArrayFromBuffer(int    ind_handle,  // handle of the indicator 
                         int    ind_buff,    // indicator buffer number
                         int    start,       // start 
                         int    count,       // number of copied values
                         double &arr[],      // array for indicator values
                         bool   as_series,   // index elements as series 
                         string ind_name)    // name of indicator 
{ 
//--- set as series
   if(as_series) ArraySetAsSeries(arr, true);
//--- reset error code 
   ResetLastError(); 
//--- fill a part of the iMABuffer array with values from the indicator buffer that has 0 index 
   if(CopyBuffer(ind_handle,ind_buff,start,count,arr)<0) 
   { 
      //--- if the copying fails, tell the error code 
      PrintFormat("Failed to copy data from the "+ind_name+" indicator, error code %d",_LastError); 
      //--- quit with zero result - it means that the indicator is considered as not calculated 
      return(false); 
   } 
//--- everything is fine 
   return(true); 
}

//+------------------------------------------------------------------+
