PA_adaptive_MACD

Download script
Author: � mladen, 2016, MetaQuotes Software Corp.
PA_adaptive_MACD

This script is a sophisticated technical analysis tool designed to identify market trends and potential reversal points by combining several advanced mathematical concepts into a single visual indicator. Instead of relying on a simple moving average, it uses complex calculations to filter out "noise" and focus on the underlying momentum of the price action.

Core Logic and Mechanics

1. Advanced Price Processing The script does not just look at the current price. It offers a wide variety of ways to interpret market data, including standard prices (Close, Open, High, Low), weighted averages, and "Trend Biased" prices. Most notably, it includes support for Heiken Ashi calculations—a method of price smoothing that helps traders see the trend more clearly by averaging price movements over time.

2. Hilbert Transform & Phase Analysis A key unique feature of this script is its use of the Hilbert Transform. In non-technical terms, this allows the script to analyze the "cycles" of the market. It attempts to determine if the market is currently in a trending phase or a ranging (sideways) phase. By calculating the "phase" of the price movement, it can adapt to different market environments more dynamically than standard indicators.

3. The "PA MACD" Calculation The script constructs a custom version of the MACD (Moving Average Convergence Divergence). It uses two different cycle lengths (Fast and Slow) derived from the Hilbert Transform.

  • The Fast Cycle captures immediate momentum.
  • The Slow Cycle captures the broader market trend. By subtracting these two values, the script generates a signal that shows how quickly the current price is moving relative to its long-term cycle.

4. Dynamic Level Detection To help users decide when a move is "extreme," the script calculates three distinct horizontal levels based on the past performance of the indicator:

  • Upper Level: Identifies overbought or peak momentum areas.
  • Lower Level: Identifies oversold or bottoming areas.
  • Middle Level: Acts as a neutral equilibrium point. These levels can be set to be "Floating" (based on the highest/lowest range of recent history) or "Quantile" (based on statistical distribution).

5. Trend Identification & Visual Signals The script automatically determines the trend based on which level the price crosses. It then handles the visual representation in three ways:

  • Color Changes: The indicator changes color depending on whether the momentum is breaking out of the upper/lower levels or crossing the middle line.
  • Arrows: It can automatically plot "Breakout" arrows (when the trend shifts significantly) and "Retrace" arrows (when the price pulls back but stays within a trend).
  • Alerts: The script features a complete notification system, capable of sending pop-up alerts, playing sounds, sending emails, or pushing mobile notifications the moment a trend change is detected.

6. Multi-Timeframe (MTF) Capability The logic includes an interpolation engine. This means if you are looking at a 15-minute chart but want to see the data from a 4-hour chart, the script can "stretch" and smooth that higher-timeframe data so it aligns perfectly with your current view, ensuring you don't miss the "big picture" while trading smaller movements.

Indicators Used
Indicator of the average true range
Miscellaneous
It issuies visual alerts to the screenIt sends emailsIt plays sound alerts
10 Views
0 Downloads
0 Favorites
PA_adaptive_MACD
//------------------------------------------------------------------
#property copyright "© mladen, 2016, MetaQuotes Software Corp."
#property link      "www.forex-tsd.com, www.mql5.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 8
#property indicator_color1  clrDeepSkyBlue
#property indicator_color2  clrPaleVioletRed
#property indicator_color3  clrDimGray
#property indicator_color4  clrSilver
#property indicator_color5  clrDeepSkyBlue
#property indicator_color6  clrDeepSkyBlue
#property indicator_color7  clrPaleVioletRed
#property indicator_color8  clrPaleVioletRed
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_width7  2
#property indicator_width8  2
#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT
#property strict

//
//
//
//
//

enum enPrices
{
   pr_close,      // Close
   pr_open,       // Open
   pr_high,       // High
   pr_low,        // Low
   pr_median,     // Median
   pr_typical,    // Typical
   pr_weighted,   // Weighted
   pr_average,    // Average (high+low+open+close)/4
   pr_medianb,    // Average median body (open+close)/2
   pr_tbiased,    // Trend biased price
   pr_tbiased2,   // Trend biased (extreme) price
   pr_haclose,    // Heiken ashi close
   pr_haopen ,    // Heiken ashi open
   pr_hahigh,     // Heiken ashi high
   pr_halow,      // Heiken ashi low
   pr_hamedian,   // Heiken ashi median
   pr_hatypical,  // Heiken ashi typical
   pr_haweighted, // Heiken ashi weighted
   pr_haaverage,  // Heiken ashi average
   pr_hamedianb,  // Heiken ashi median body
   pr_hatbiased,  // Heiken ashi trend biased price
   pr_hatbiased2  // Heiken ashi trend biased (extreme) price
};
enum enColorOn
{
   cc_onSlope,   // Change color on slope change
   cc_onMiddle,  // Change color on middle line cross
   cc_onLevels   // Change color on outer levels cross
};
enum enLevelType
{
   lev_float, // Floating levels
   lev_quan   // Quantile levels
};

extern ENUM_TIMEFRAMES TimeFrame              = PERIOD_CURRENT; // Time frame to use
extern string          ForSymbol              = "";             // Symbol to use (empty for current symbol)
extern double          FastCycles             = 1.5;            // Fast phase accumulation cycles
extern int             FastFilter             = 1.0;            // Fast phase accumulation filter
extern double          SlowCycles             = 3.0;            // Slow phase accumulation cycles
extern int             SlowFilter             = 1.0;            // Slow phase accumulation filter
extern enPrices        AppliedPrice           = pr_close;       // Price to use
extern int             FlPeriod               = 35;             // Levels period
extern double          FlUp                   = 90;             // Upper level %
extern double          FlDown                 = 10;             // Lower level %
extern enLevelType     FlType                 = lev_quan;       // Levels type
extern enColorOn       ColorOn                = cc_onSlope;     // Color on
extern bool            arrowsVisible          = false;          // Display arrows?
extern bool            arrowsOnFirst          = false;          // Arrows on first bar (mtf mode)?
extern bool            arrowsShowBreakOut     = true;           // Show breakout arrow?s
extern bool            arrowsShowRetrace      = true;           // Show retrace arrows?
extern string          arrowsIdentifier       = "pa macd arrows"; // Arros unique ID
extern double          arrowsUpperGap         = 0.5;            // Upper gap for arrows
extern double          arrowsLowerGap         = 0.5;            // Lower gap for arrows
extern color           arrowsUpColor          = clrLimeGreen;   // Up arrow color
extern color           arrowsDnColor          = clrRed;         // Down arrow color
extern int             arrowsUpCode           = 241;            // Up arrow code
extern int             arrowsDnCode           = 242;            // Down arrow code
extern bool            alertsOn               = false;          // Turn alert on?
extern bool            alertsOnCurrent        = false;          // Alerts on still opened bar?
extern bool            alertsMessage          = true;           // Alerts should display a message?
extern bool            alertsSound            = false;          // Alerts should play a sound? 
extern bool            alertsNotify           = false;          // Alerts should send a notification?
extern bool            alertsEmail            = false;          // Alerts should send an email?
extern string          soundFile              = "alert2.wav";   // Alerts sound file
extern bool            Interpolate            = true;           // Interpolate in multi time frame mode

//
//
//
//
//

double buffer1[],buffer2[],buffer3[],buffer4[],buffer5[],buffer6[],buffer7[],bbMacd[],trendSlope[];
string indicatorFileName;
bool   returnBars;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
int init()
{
   IndicatorBuffers(9);
   SetIndexBuffer(0, buffer1);
   SetIndexBuffer(1, buffer2);
   SetIndexBuffer(2, buffer3);
   SetIndexBuffer(3, bbMacd);
   SetIndexBuffer(4, buffer4);
   SetIndexBuffer(5, buffer5);
   SetIndexBuffer(6, buffer6);
   SetIndexBuffer(7, buffer7);
   SetIndexBuffer(8, trendSlope);

            indicatorFileName = WindowExpertName();
            returnBars        = TimeFrame==-99;
            TimeFrame         = MathMax(TimeFrame,_Period);
            if (ForSymbol=="") ForSymbol = Symbol();
   IndicatorShortName(ForSymbol+" "+timeFrameToString(TimeFrame)+" PA Macd ("+(string)FastCycles+","+(string)SlowCycles+","+(string)FlPeriod+")");
   return(0);
}
int deinit() { ObjectsDeleteAll(0,arrowsIdentifier+":");  return(0); }

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start()
{
   int counted_bars = IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = MathMin(Bars - counted_bars,Bars-1);
         if (returnBars) { buffer1[0] = limit+1; return(0); }
         if (ForSymbol != _Symbol || TimeFrame != _Period) 
         {
            #define _mtfCall(_buff) iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",FastCycles,FastFilter,SlowCycles,SlowFilter,AppliedPrice,FlPeriod,FlUp,FlDown,FlType,ColorOn,arrowsVisible,arrowsOnFirst,arrowsShowBreakOut,arrowsShowRetrace,arrowsIdentifier,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,_buff,y)
            limit = (int)MathMax(limit,MathMin(Bars-1,iCustom(ForSymbol,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
            if (trendSlope[limit]== 1) CleanPoint(limit,buffer4,buffer5);
            if (trendSlope[limit]==-1) CleanPoint(limit,buffer6,buffer7);
            for(int i=limit; i>=0; i--)
            {
               int y = iBarShift(ForSymbol,TimeFrame,Time[i]);
                  buffer1[i]    = _mtfCall(0);
                  buffer2[i]    = _mtfCall(1);
                  buffer3[i]    = _mtfCall(2);
                  bbMacd[i]     = _mtfCall(3);
                  trendSlope[i] = _mtfCall(8);
                  buffer4[i]    = EMPTY_VALUE;
                  buffer5[i]    = EMPTY_VALUE;
                  buffer6[i]    = EMPTY_VALUE;
                  buffer7[i]    = EMPTY_VALUE;
            
                  //
                  //
                  //
                  //
                  //
      
                  if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                     #define _interpolate(_buff) _buff[i+k] = _buff[i]+(_buff[i+n]-_buff[i])*k/n
                     int n,k; datetime time = iTime(NULL,TimeFrame,y);
                        for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                        for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) 
                        {
                           _interpolate(bbMacd);
                           _interpolate(buffer1);
                           _interpolate(buffer2);
                           _interpolate(buffer3);
                     }                           
            }
            for (int i=limit;i>=0;i--)
            {
               if (trendSlope[i]== 1) PlotPoint(i,buffer4,buffer5,bbMacd);
               if (trendSlope[i]==-1) PlotPoint(i,buffer6,buffer7,bbMacd);
            }               
            return(0);
         }

   //
   //
   //
   //
   //

   if (trendSlope[limit]== 1) CleanPoint(limit,buffer4,buffer5);
   if (trendSlope[limit]==-1) CleanPoint(limit,buffer6,buffer7);
   for(int i = limit; i >= 0 ; i--)
   {
      double price = getPrice(AppliedPrice,Open,Close,High,Low,i);
         bbMacd[i] = iEma(price,iHilbertPhase(price,FastFilter,FastCycles,i,0),i,0)-iEma(price,iHilbertPhase(price,SlowFilter,SlowCycles,i,1),i,1);
            if (FlType==lev_float)
            {
               double min   = bbMacd[ArrayMinimum(bbMacd,FlPeriod,i)];
               double max   = bbMacd[ArrayMaximum(bbMacd,FlPeriod,i)];
               double range = max-min;
                  buffer1[i] = min+FlUp  *range/100.0;
                  buffer2[i] = min+FlDown*range/100.0;
                  buffer3[i] = min+0.5*range;
            }
            else
            {
                  buffer1[i] = iQuantile(bbMacd[i],FlPeriod, FlUp            ,i,Bars);
                  buffer2[i] = iQuantile(bbMacd[i],FlPeriod, FlDown          ,i,Bars);
                  buffer3[i] = iQuantile(bbMacd[i],FlPeriod,(FlUp+FlDown)/2.0,i,Bars);
            }
            switch(ColorOn)
            {
               case cc_onLevels:         trendSlope[i] = (bbMacd[i]>buffer1[i])  ? 1 : (bbMacd[i]<buffer2[i])  ? -1 : 0; break;
               case cc_onMiddle:         trendSlope[i] = (bbMacd[i]>buffer3[i])  ? 1 : (bbMacd[i]<buffer3[i])  ? -1 : 0; break;
               default :  if (i<Bars-1)  trendSlope[i] = (bbMacd[i]>bbMacd[i+1]) ? 1 : (bbMacd[i]<bbMacd[i+1]) ? -1 : trendSlope[i+1];
            }                  
            buffer4[i] = EMPTY_VALUE;
            buffer5[i] = EMPTY_VALUE;
            buffer6[i] = EMPTY_VALUE;
            buffer7[i] = EMPTY_VALUE;
            if (trendSlope[i]== 1) PlotPoint(i,buffer4,buffer5,bbMacd);
            if (trendSlope[i]==-1) PlotPoint(i,buffer6,buffer7,bbMacd);
            
            //
            //
            //
            //
            //
            
            if (arrowsVisible && ForSymbol==Symbol())
            {
               ObjectDelete(arrowsIdentifier+":"+(string)Time[i]);
               if ((i<Bars-1) && trendSlope[i]!=trendSlope[i+1])
               {
                  if (arrowsShowBreakOut && trendSlope[i] == 1)                        drawArrow(i,arrowsUpColor,arrowsUpCode,false);
                  if (arrowsShowBreakOut && trendSlope[i] ==-1)                        drawArrow(i,arrowsDnColor,arrowsDnCode,true);
                  if (arrowsShowRetrace  && trendSlope[i] == 0 && trendSlope[i+1]== 1) drawArrow(i,arrowsDnColor,arrowsDnCode,true);
                  if (arrowsShowRetrace  && trendSlope[i] == 0 && trendSlope[i+1]==-1) drawArrow(i,arrowsUpColor,arrowsUpCode,false);
               }
            }
   }
   if (alertsOn)
   {
     int whichBar = 1; if (alertsOnCurrent) whichBar = 0; 
     if (trendSlope[whichBar] != trendSlope[whichBar+1])
     {
           if (trendSlope[whichBar] == 1)                               doAlert(whichBar,"up");
           if (trendSlope[whichBar] ==-1)                               doAlert(whichBar,"down");
           if (trendSlope[whichBar] == 0 && trendSlope[whichBar+1]== 1) doAlert(whichBar,"back from up into zone");
           if (trendSlope[whichBar] ==-0 && trendSlope[whichBar+1]==-1) doAlert(whichBar,"back from down into zone");
     }         
   }
   return(0);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

#define _quantileInstances 1
double _sortQuant[];
double _workQuant[][_quantileInstances];

double iQuantile(double value, int period, double qp, int i, int bars, int instanceNo=0)
{
   if (period<1) return(value);
   if (ArrayRange(_workQuant,0)!=bars) ArrayResize(_workQuant,bars); 
   if (ArraySize(_sortQuant)!=period)  ArrayResize(_sortQuant,period); 
            i=bars-i-1; _workQuant[i][instanceNo]=value;
            int k=0; for (; k<period && (i-k)>=0; k++) _sortQuant[k] = _workQuant[i-k][instanceNo];
                     for (; k<period            ; k++) _sortQuant[k] = 0;
                     ArraySort(_sortQuant);

   //
   //
   //
   //
   //
   
   double index = (period-1.0)*qp/100.00;
   int    ind   = (int)index;
   double delta = index - ind;
   if (ind == NormalizeDouble(index,5))
         return(            _sortQuant[ind]);
   else  return((1.0-delta)*_sortQuant[ind]+delta*_sortQuant[ind+1]);
}   

//
//
//
//
//

double workEma[][3];
double iEma(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workEma,0)!= Bars) ArrayResize(workEma,Bars); r = Bars-r-1;

   workEma[r][instanceNo] = price;
   if (r>0 && period>1)
          workEma[r][instanceNo] = workEma[r-1][instanceNo]+(2.0 / (1.0+period))*(price-workEma[r-1][instanceNo]);
   return(workEma[r][instanceNo]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

#define _hilInstances    2
#define _hilInstanceSize 9
double  workHil[][_hilInstances*_hilInstanceSize];
#define _price      0
#define _smooth     1
#define _detrender  2
#define _period     3
#define _instPeriod 4
#define _phase      5
#define _deltaPhase 6
#define _Q1         7
#define _I1         8

double iHilbertPhase(double price, double filter, double cyclesToReach, int i, int s=0)
{
   if (ArrayRange(workHil,0)!=Bars) ArrayResize(workHil,Bars);
   int r = Bars-i-1; s = s*_hilInstanceSize;
      
   //
   //
   //
   //
   //

   #define _calcComp(_ind) ((0.0962*workHil[r][s+_ind] + 0.5769*workHil[r-2][s+_ind] - 0.5769*workHil[r-4][s+_ind] - 0.0962*workHil[r-6][s+_ind]) * (0.075*workHil[r-1][s+_period] + 0.54))

      workHil[r][s+_price]      = price; 
      if (r<6) { workHil[r][s+_smooth]=price; return(0); }
      workHil[r][s+_smooth]     = (4.0*workHil[r][s+_price]+3.0*workHil[r-1][s+_price]+2.0*workHil[r-2][s+_price]+workHil[r-3][s+_price])/10.0;
      workHil[r][s+_detrender]  = _calcComp(_smooth);
      workHil[r][s+_Q1]         = 0.15*_calcComp(_detrender)     +0.85*workHil[r-1][s+_Q1];
      workHil[r][s+_I1]         = 0.15*workHil[r-3][s+_detrender]+0.85*workHil[r-1][s+_I1];
      workHil[r][s+_phase]      = workHil[r-1][s+_phase];
      workHil[r][s+_instPeriod] = workHil[r-1][s+_instPeriod];

      //
      //
      //
      //
      //
           
         if (MathAbs(workHil[r][s+_I1])>0)
                     workHil[r][s+_phase] = 180.0/M_PI*MathArctan(MathAbs(workHil[r][s+_Q1]/workHil[r][s+_I1]));
           
         if (workHil[r][s+_I1]<0 && workHil[r][s+_Q1]>0) workHil[r][s+_phase] = 180.0-workHil[r][s+_phase];
         if (workHil[r][s+_I1]<0 && workHil[r][s+_Q1]<0) workHil[r][s+_phase] = 180.0+workHil[r][s+_phase];
         if (workHil[r][s+_I1]>0 && workHil[r][s+_Q1]<0) workHil[r][s+_phase] = 360.0-workHil[r][s+_phase];

      //
      //
      //
      //
      //
                        
      workHil[r][s+_deltaPhase] = workHil[r-1][s+_phase]-workHil[r][s+_phase];

         if (workHil[r-1][s+_phase]<90.0 && workHil[r][s+_phase]>270.0)
             workHil[r][s+_deltaPhase] = 360.0+workHil[r-1][s+_phase]-workHil[r][s+_phase];
             workHil[r][s+_deltaPhase] = MathMax(MathMin(workHil[r][s+_deltaPhase],60),7);
      
            //
            //
            //
            //
            //
                  
            double phaseSum = 0; int k=0; for (; phaseSum<cyclesToReach*360.0 && (r-k)>0; k++) phaseSum += workHil[r-k][s+_deltaPhase];
            if (k>0) workHil[r][s+_instPeriod]= k;
                     workHil[r][s+_period] = iEma(workHil[r][s+_instPeriod],filter,i,2);
   return (workHil[r][s+_period]);
}

//
//
//
//
//

#define priceInstances 1
double workHa[][priceInstances*4];
double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int instanceNo=0)
{
  if (tprice>=pr_haclose)
   {
      if (ArrayRange(workHa,0)!= Bars) ArrayResize(workHa,Bars); instanceNo*=4;
         int r = Bars-i-1;
         
         //
         //
         //
         //
         //
         
         double haOpen;
         if (r>0)
                haOpen  = (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0;
         else   haOpen  = (open[i]+close[i])/2;
         double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0;
         double haHigh  = MathMax(high[i], MathMax(haOpen,haClose));
         double haLow   = MathMin(low[i] , MathMin(haOpen,haClose));

         if(haOpen  <haClose) { workHa[r][instanceNo+0] = haLow;  workHa[r][instanceNo+1] = haHigh; } 
         else                 { workHa[r][instanceNo+0] = haHigh; workHa[r][instanceNo+1] = haLow;  } 
                                workHa[r][instanceNo+2] = haOpen;
                                workHa[r][instanceNo+3] = haClose;
         //
         //
         //
         //
         //
         
         switch (tprice)
         {
            case pr_haclose:     return(haClose);
            case pr_haopen:      return(haOpen);
            case pr_hahigh:      return(haHigh);
            case pr_halow:       return(haLow);
            case pr_hamedian:    return((haHigh+haLow)/2.0);
            case pr_hamedianb:   return((haOpen+haClose)/2.0);
            case pr_hatypical:   return((haHigh+haLow+haClose)/3.0);
            case pr_haweighted:  return((haHigh+haLow+haClose+haClose)/4.0);
            case pr_haaverage:   return((haHigh+haLow+haClose+haOpen)/4.0);
            case pr_hatbiased:
               if (haClose>haOpen)
                     return((haHigh+haClose)/2.0);
               else  return((haLow+haClose)/2.0);        
            case pr_hatbiased2:
               if (haClose>haOpen)  return(haHigh);
               if (haClose<haOpen)  return(haLow);
                                    return(haClose);        
         }
   }
   
   //
   //
   //
   //
   //
   
   switch (tprice)
   {
      case pr_close:     return(close[i]);
      case pr_open:      return(open[i]);
      case pr_high:      return(high[i]);
      case pr_low:       return(low[i]);
      case pr_median:    return((high[i]+low[i])/2.0);
      case pr_medianb:   return((open[i]+close[i])/2.0);
      case pr_typical:   return((high[i]+low[i]+close[i])/3.0);
      case pr_weighted:  return((high[i]+low[i]+close[i]+close[i])/4.0);
      case pr_average:   return((high[i]+low[i]+close[i]+open[i])/4.0);
      case pr_tbiased:   
               if (close[i]>open[i])
                     return((high[i]+close[i])/2.0);
               else  return((low[i]+close[i])/2.0);        
      case pr_tbiased2:   
               if (close[i]>open[i]) return(high[i]);
               if (close[i]<open[i]) return(low[i]);
                                     return(close[i]);        
   }
   return(0);
}   

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

void drawArrow(int i,color theColor,int theCode,bool up)
{
   string name = arrowsIdentifier+":"+(string)Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/4.0;   
   int    add  = 0; if (!arrowsOnFirst) add = _Period*60-1;
   
      //
      //
      //
      //
      //
      
      ObjectCreate(name,OBJ_ARROW,0,Time[i]+add,0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i]+ arrowsUpperGap * gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i] - arrowsLowerGap * gap);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[forBar]) {
          previousAlert  = doWhat;
          previousTime   = Time[forBar];

          //
          //
          //
          //
          //

          message =  StringConcatenate(Symbol()," ",timeFrameToString(_Period)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," pa Macd ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," pa Macd "),message);
             if (alertsNotify)  SendNotification(message);
             if (alertsSound)   PlaySound(soundFile);
      }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (i>=Bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
      if (first[i+2] == EMPTY_VALUE) 
            { first[i]  = from[i];  first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
      else  { second[i] =  from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
   else     { first[i]  = from[i];                           second[i] = EMPTY_VALUE; }
}

Comments