//+----------------------------------------------------------+
//|                                 Ehlers' fisher transform |
//|                                                   mladen |
//+----------------------------------------------------------+
#property  copyright "mladen"
#property  link      "mladenfx@gmail.com"


#property indicator_separate_window
#property indicator_buffers 8
// #property indicator_label1  "EFT Strong up"
// #property indicator_type1   DRAW_HISTOGRAM
// #property indicator_color1  clrLimeGreen
// #property indicator_width1  2

// #property indicator_label2  "EFT Weak up"
// #property indicator_type2   DRAW_HISTOGRAM
// #property indicator_color2  clrLimeGreen

// #property indicator_label3  "EFT Strong down"
// #property indicator_type3   DRAW_HISTOGRAM
// #property indicator_color3  clrPaleVioletRed
// #property indicator_width3  2

// #property indicator_label4  "EFT weak down"
// #property indicator_type4   DRAW_HISTOGRAM
// #property indicator_color4  clrPaleVioletRed

// #property indicator_label5  "Ehlers fisher transform"
// #property indicator_type5   DRAW_LINE
// #property indicator_color5  clrDarkGray
// #property indicator_width5  2

#property indicator_color6  DeepSkyBlue
#property indicator_color7  LimeGreen
#property indicator_color8  Red
#property indicator_width6  2
#property indicator_style7  STYLE_DOT
#property indicator_style8  STYLE_DOT
// #property strict

//
//
//

enum enTimeFrames
{
   tf_cu  = PERIOD_CURRENT, // Current time frame
   tf_m1  = PERIOD_M1,      // 1 minute
   tf_m5  = PERIOD_M5,      // 5 minutes
   tf_m15 = PERIOD_M15,     // 15 minutes
   tf_m30 = PERIOD_M30,     // 30 minutes
   tf_h1  = PERIOD_H1,      // 1 hour
   tf_h4  = PERIOD_H4,      // 4 hours
   tf_d1  = PERIOD_D1,      // Daily
   tf_w1  = PERIOD_W1,      // Weekly
   tf_mn1 = PERIOD_MN1,     // Monthly
   tf_n1  = -1,             // First higher time frame
   tf_n2  = -2,             // Second higher time frame
   tf_n3  = -3              // Third higher time frame
};

extern enTimeFrames   TimeFrame            = tf_cu;      // Time frame
input int             period               = 20;
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
         pr_habclose,                                // Heiken ashi (better formula) close
         pr_habopen,                                 // Heiken ashi (better formula) open
         pr_habhigh,                                 // Heiken ashi (better formula) high
         pr_hablow,                                  // Heiken ashi (better formula) low
         pr_habmedian,                               // Heiken ashi (better formula) median
         pr_habtypical,                              // Heiken ashi (better formula) typical
         pr_habweighted,                             // Heiken ashi (better formula) weighted
         pr_habaverage,                              // Heiken ashi (better formula) average
         pr_habmedianb,                              // Heiken ashi (better formula) median body
         pr_habtbiased,                              // Heiken ashi (better formula) trend biased price
         pr_habtbiased2                              // Heiken ashi (better formula) trend biased (extreme) price
      };

input enPrices        Price                = pr_median;         // Price to use   
extern double         PriceSmooth          = 0.3;               // Price smoothing 
extern double         IndexSmooth          = 0.3;               // Index smoothing
//+-----------------------------------------------------------------------------------------------------------+
input int             SvePeriod            = 18;                // Sve Period
input double          BBDeviations         = 1.6;               // BB Deviations
input int             DeviationsPeriod     = 63;                // Deviations Period
//+-----------------------------------------------------------------------------------------------------------+
input ENUM_LINE_STYLE LevelsStyle          = STYLE_DOT;         // Levels Style
input color           LevelsColor          = clrDimGray;        // Levels Color
//+-----------------------------------------------------------------------------------------------------------+
input bool            alertsOn             = false;             // Alerts?
input bool            alertsOnCurrent      = false;             // Alerts open bar?
input bool            alertsMessage        = true;              // Alerts message?
input bool            alertsSound          = true;              // Alerts sound?
input bool            alertsNotify         = false;             // Alerts notification?
input bool            alertsEmail          = false;             // Alerts email?
input bool            arrowsVisible        = false;             // Arrows visible true/false?
input bool            arrowsOnNewest       = false;             // Arrows drawn on newest bar of higher time frame bar true/false?
input string          arrowsIdentifier     = "eft Arrows2";     // Unique ID for arrows
input double          arrowsUpperGap       = 0.5;               // Upper arrow gap
input double          arrowsLowerGap       = 0.5;               // Lower arrow gap
input color           arrowsUpColor        = clrBlue;           // Up arrow color
input color           arrowsDnColor        = clrCrimson;        // Down arrow color
input int             arrowsUpCode         = 116;               // Up arrow code
input int             arrowsDnCode         = 116;               // Down arrow code
input int             arrowsUpSize         = 2;                 // Up arrow size
input int             arrowsDnSize         = 2;                 // Down arrow size
input bool            vLinesVisible        = false;             // Show vertical lines
input bool            linesOnNewest        = false;             // Vertical lines drawn on newest bar of higher time frame bar?
input string          vLinesID             = "eft Lines2";      // Lines ID
input color           vLinesUpColor        = clrBlue;           // Lines up color 
input color           vLinesDnColor        = clrRed;            // Lines down color
input ENUM_LINE_STYLE vLinesStyle          = STYLE_DOT;         // Lines style
input int             vLinesWidth          = 0;                 // Vertical lines width  
input bool            ShowZones_MC         = true;              // Display the background zones on the main chart
input bool            ShowZones_SW1        = false;             // Display the background zones in the first separated window
input bool            ShowZones_SW2        = false;             // Display the background zones in the second separated window
input bool            ShowZones_SW3        = false;             // Display the background zones in the third separated window
input color           ZoneColorUp          = clrIndigo;         // Uptrend Zone color
input color           ZoneColorDn          = clrBlack;          // Downtrend Zone color
input string          UniqueZoneID         = "eftzones2";       // Unique ID for the zones
input bool            Interpolate          = true;              // Interpolate in multi time frame mode on/off?  

double huu[],hud[],hdd[],hdu[],val[],valc[],prc[],trend[],count[];
double bbValue[];
double bbUpper[];
double bbLower[];
double svePerB[];

int WhatSW1 = 1,WhatSW2 = 2,WhatSW3 = 3;
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,period,Price,PriceSmooth,IndexSmooth,SvePeriod,BBDeviations,DeviationsPeriod,LevelsStyle,LevelsColor,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,arrowsVisible,arrowsOnNewest,arrowsIdentifier,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,arrowsUpSize,arrowsDnSize,vLinesVisible,linesOnNewest,vLinesID,vLinesUpColor,vLinesDnColor,vLinesStyle,vLinesWidth,ShowZones_MC,ShowZones_SW1,ShowZones_SW2,ShowZones_SW3,ZoneColorUp,ZoneColorDn,UniqueZoneID,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int OnInit()
{
   if (PriceSmooth>=1.0)
   {
      PriceSmooth=0.9999;
      Alert("EFT: PriceSmothing factor has to be < 1!");
   }
   if (PriceSmooth<0)
   {
      PriceSmooth=0;
      Alert("EFT: PriceSmothing factor mustn''t be negative!");
   }
   if (IndexSmooth>=1.0)
   {
      IndexSmooth=0.9999;
      Alert("EFT: PriceSmothing factor has to be smaller 1!");
   }
   if (IndexSmooth<0)
   {
      IndexSmooth=0;
      Alert("EFT: PriceSmothing factor mustn''t be negative!");
   }
   IndicatorBuffers(13);
   SetIndexBuffer(0, huu,INDICATOR_DATA); SetIndexLabel(0,"EFT Strong up");
   SetIndexBuffer(1, hud,INDICATOR_DATA); SetIndexLabel(1,"EFT Weak up");
   SetIndexBuffer(2, hdd,INDICATOR_DATA); SetIndexLabel(2,"EFT Strong down");
   SetIndexBuffer(3, hdu,INDICATOR_DATA); SetIndexLabel(3,"EFT weak down");
   SetIndexBuffer(4, val,INDICATOR_DATA); SetIndexLabel(4,"EFT");

   SetIndexBuffer(5, bbValue); SetIndexLabel(5,"bbValue");
   SetIndexBuffer(6, bbUpper); SetIndexLabel(6,"bbUpper");
   SetIndexBuffer(7, bbLower); SetIndexLabel(7,"bbLower");
   SetIndexBuffer(8, svePerB); SetIndexLabel(8,"svePerB");

   SetIndexBuffer(9, prc);
   SetIndexBuffer(10, valc);
   SetIndexBuffer(11, trend);
   SetIndexBuffer(12, count);

   //--- set levels
   IndicatorSetInteger(INDICATOR_LEVELS,3);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,LevelsColor);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE,LevelsStyle);

   IndicatorSetDouble(INDICATOR_LEVELVALUE,0,0);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,1,50);
   IndicatorSetDouble(INDICATOR_LEVELVALUE,2,100);

   indicatorFileName = WindowExpertName();
   TimeFrame         = (enTimeFrames)timeFrameValue(TimeFrame);
              
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" Ehlers\' Fisher transform SVE_BB ("+(string)period+","+DoubleToStr(BBDeviations,1)+")");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) 
{ 
   ObjectsDeleteAll(0,vLinesID+":");
   ObjectsDeleteAll(0,arrowsIdentifier+":");
   string lookFor       = UniqueZoneID+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
      if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
   GlobalVariableDel(ChartID()+":"+UniqueZoneID); 
}

//+----------------------------------------------------------+
//|                                                          |
//+----------------------------------------------------------+

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[])
{
   int r,limit=fmin(rates_total-prev_calculated+1,rates_total-1); count[0] = limit;
   datetime tDummy = GlobalVariableGet(ChartID()+":"+UniqueZoneID); if (tDummy==0) tDummy = time[0];
      if (TimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(12,0)*TimeFrame/_Period));
         for (int i=limit;i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               huu[i] = _mtfCall(0,y);
               hud[i] = _mtfCall(1,y);
               hdd[i] = _mtfCall(2,y);
               hdu[i] = _mtfCall(3,y);
               val[i] = _mtfCall(4,y);

               bbValue[i] = _mtfCall(5,y);
               bbUpper[i] = _mtfCall(6,y);
               bbLower[i] = _mtfCall(7,y);
               svePerB[i] = _mtfCall(8,y);
               
               //
               //
               //
                     
               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 btime = iTime(NULL,TimeFrame,y);
                     for(n = 1; (i+n)<rates_total && time[i+n] >= btime; n++) continue;	
                     for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) 
                     {
                        _interpolate(val);  
                        if (huu[i]!= EMPTY_VALUE) huu[i+k] = val[i+k];
  	                     if (hud[i]!= EMPTY_VALUE) hud[i+k] = val[i+k];
  	                     if (hdd[i]!= EMPTY_VALUE) hdd[i+k] = val[i+k];
  	                     if (hdu[i]!= EMPTY_VALUE) hdu[i+k] = val[i+k];
                     }            
        } 
        GlobalVariableSet(ChartID()+":"+UniqueZoneID,time[0]+_Period*60-1);       
   return(rates_total);
   }

   //
   //
   //
   
   struct sWork
   {
         double tem;
   };
   static sWork wrk[];
   static int   wrkSize=-1;
            if (wrkSize<rates_total) wrkSize = ArrayResize(wrk,rates_total+500);
            
   //
   //
   //
   
   for(i=limit,r=rates_total-i-1;i>=0;i--,r++)
   {
      prc[i] = getPrice(Price,open,close,high,low,i,rates_total);
        
      double max = prc[ArrayMaximum(prc,period,i)];
      double min = prc[ArrayMinimum(prc,period,i)];
         wrk[r].tem = (r>0) ? (max!=min) ? PriceSmooth*((prc[i]-min)/(max-min)-0.5)+PriceSmooth*wrk[r-1].tem : 0.00 : 0.00; 
         wrk[r].tem = (wrk[r].tem>0.999) ? 0.999 : (wrk[r].tem<-0.999) ? -0.999 : wrk[r].tem;
         val[i]  = (r>0) ? IndexSmooth*log((1.0+wrk[r].tem)/(1.0-wrk[r].tem))+IndexSmooth*val[i+1] : 0;      
         valc[i] = (r>0) ? (val[i]>0) ? (val[i]>val[i+1]) ? 0 : 1 : (val[i]<val[i+1]) ? 2 : 3 : 0;
         huu[i] = (valc[i] == 0) ? val[i] : EMPTY_VALUE;
         hud[i] = (valc[i] == 1) ? val[i] : EMPTY_VALUE;
         hdd[i] = (valc[i] == 2) ? val[i] : EMPTY_VALUE;
         hdu[i] = (valc[i] == 3) ? val[i] : EMPTY_VALUE;

         // trend[i] = (r>0) ? (val[i]>0) ? 1 :(val[i]<0) ? -1 : trend[i+1] : 0;

         // SVE Bollinger Bands of EFT
         double sdev = iDeviation(val,SvePeriod,i);
         if (sdev != 0)
                  svePerB[i] = 25.0*(val[i]+2.0*sdev-iMAOnArray(val,0,SvePeriod,0,MODE_LWMA,i))/sdev;
         else svePerB[i] = 0;
         sdev = iDeviation(svePerB,DeviationsPeriod,i);

         bbValue[i] = svePerB[i];
         bbUpper[i] = 50.0 + sdev*BBDeviations;
         bbLower[i] = 50.0 - sdev*BBDeviations;

         trend[i] = trend[i+1];
         if(bbValue[i] > 50) trend[i]= 1;
         if(bbValue[i] < 50) trend[i]=-1;
         //---
        
         //
         //
         //
      
         if (arrowsVisible)
         {
            string lookFor = arrowsIdentifier+":"+(string)time[i]; if (ObjectFind(0,lookFor)==0) ObjectDelete(0,lookFor);                       
            if (i<(rates_total-1) && trend[i] != trend[i+1])
            {
               if (trend[i] == 1) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
               if (trend[i] ==-1) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);
            }
          }     
         
         //
         //
         //
         
         if (vLinesVisible)
         {
           string tlookFor = vLinesID+":"+(string)time[i]; if (ObjectFind(0,tlookFor)==0) ObjectDelete(0,tlookFor);            
           if (i<rates_total-1 && trend[i]!=trend[i+1])
           {
             if (trend[i] == 1) drawLine(i,vLinesUpColor);
             if (trend[i] ==-1) drawLine(i,vLinesDnColor);
           }
         }
         
         //
         //
         //
         
         int index=0;
         for (index=i; index<rates_total; index++) if (trend[index]!= trend[index+1]) break;
         if (ShowZones_MC)
         {
            string   name     = UniqueZoneID+":MainChart"+time[index+1]; ObjectDelete(name); ObjectDelete(UniqueZoneID+":"+time[1]);
            datetime lastTime = time[i-1]; if (i==0) { lastTime = tDummy; if (time[index]==lastTime) lastTime = time[0]+Period()*60;}
            ObjectCreate(name,OBJ_RECTANGLE,0,Time[index],0,lastTime,WindowPriceMax()*3.0);
            ObjectSet(name,OBJPROP_BACK,true);
            if (trend[i]==-1)
                  ObjectSet(name,OBJPROP_COLOR,ZoneColorDn);
            else  ObjectSet(name,OBJPROP_COLOR,ZoneColorUp);
          }
          if (ShowZones_SW1)
          {
            string name2 = UniqueZoneID+":aboveZero1"+time[index+1]; ObjectDelete(name2); ObjectDelete(UniqueZoneID+":"+time[1]);             
            datetime lastTime2 = time[i-1]; if (i==0) { lastTime2 = tDummy; if (time[index]==lastTime2) lastTime2 = time[0]+Period()*60;}
            ObjectCreate(name2,OBJ_RECTANGLE,WhatSW1,time[index],0,lastTime2,1000);
               ObjectSet(name2,OBJPROP_BACK,true);
            if (trend[i]==-1)
                  ObjectSet(name2,OBJPROP_COLOR,ZoneColorDn);
            else  ObjectSet(name2,OBJPROP_COLOR,ZoneColorUp);

            string name3 = UniqueZoneID+":belowZero1"+time[index+1]; ObjectDelete(name3); ObjectDelete(UniqueZoneID+":"+time[1]);             
            datetime lastTime3 = time[i-1]; if (i==0) { lastTime3 = tDummy; if (time[index]==lastTime3) lastTime3 = time[0]+Period()*60;}
            ObjectCreate(name3,OBJ_RECTANGLE,WhatSW1,time[index],0,lastTime3,-1000);
               ObjectSet(name3,OBJPROP_BACK,true);
            if (trend[i]==-1)
                  ObjectSet(name3,OBJPROP_COLOR,ZoneColorDn);
            else  ObjectSet(name3,OBJPROP_COLOR,ZoneColorUp);
           }
           if (ShowZones_SW2)
           {
              string name4 = UniqueZoneID+":aboveZero2"+time[index+1]; ObjectDelete(name4); ObjectDelete(UniqueZoneID+":"+time[1]);             
              datetime lastTime4 = time[i-1]; if (i==0) { lastTime4 = tDummy; if (time[index]==lastTime4) lastTime4 = time[0]+Period()*60;}
              ObjectCreate(name4,OBJ_RECTANGLE,WhatSW2,time[index],0,lastTime4,1000);
                 ObjectSet(name4,OBJPROP_BACK,true);
              if (trend[i]==-1)
                    ObjectSet(name4,OBJPROP_COLOR,ZoneColorDn);
              else  ObjectSet(name4,OBJPROP_COLOR,ZoneColorUp);

              string name5 = UniqueZoneID+":belowZero2"+time[index+1]; ObjectDelete(name5); ObjectDelete(UniqueZoneID+":"+time[1]);             
              datetime lastTime5 = time[i-1]; if (i==0) { lastTime5 = tDummy; if (time[index]==lastTime5) lastTime5 = time[0]+Period()*60;}
              ObjectCreate(name5,OBJ_RECTANGLE,WhatSW2,time[index],0,lastTime5,-1000);
                 ObjectSet(name5,OBJPROP_BACK,true);
              if (trend[i]==-1)
                    ObjectSet(name5,OBJPROP_COLOR,ZoneColorDn);
              else  ObjectSet(name5,OBJPROP_COLOR,ZoneColorUp);
             }
             if (ShowZones_SW3)
             {
               string name6 = UniqueZoneID+":aboveZero3"+time[index+1]; ObjectDelete(name6); ObjectDelete(UniqueZoneID+":"+time[1]);             
               datetime lastTime6 = time[i-1]; if (i==0) { lastTime6 = tDummy; if (time[index]==lastTime6) lastTime6 = time[0]+Period()*60;}
               ObjectCreate(name6,OBJ_RECTANGLE,WhatSW3,time[index],0,lastTime6,1000);
                  ObjectSet(name6,OBJPROP_BACK,true);
               if (trend[i]==-1)
                     ObjectSet(name6,OBJPROP_COLOR,ZoneColorDn);
               else  ObjectSet(name6,OBJPROP_COLOR,ZoneColorUp);

               string name7 = UniqueZoneID+":belowZero3"+time[index+1]; ObjectDelete(name7); ObjectDelete(UniqueZoneID+":"+time[1]);             
               datetime lastTime7 = time[i-1]; if (i==0) { lastTime7 = tDummy; if (time[index]==lastTime7) lastTime7 = time[0]+Period()*60;}
               ObjectCreate(name7,OBJ_RECTANGLE,WhatSW3,time[index],0,lastTime7,-1000);
                  ObjectSet(name7,OBJPROP_BACK,true);
               if (trend[i]==-1)
                     ObjectSet(name7,OBJPROP_COLOR,ZoneColorDn);
               else  ObjectSet(name7,OBJPROP_COLOR,ZoneColorUp);
            }  
   }

   if (alertsOn)
   {
      int whichBar =(alertsOnCurrent) ? 0 : 1; 
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] == 1) doAlert(" crossing zero up");
         if (trend[whichBar] ==-1) doAlert(" crossing zero down");       
       }         
   }     
return(rates_total);
}      
 
//------------------------------------------------------------------
//
//------------------------------------------------------------------

#define _prHABF(_prtype) (_prtype>=pr_habclose && _prtype<=pr_habtbiased2)
#define _priceInstances     1
#define _priceInstancesSize 4
double workHa[][_priceInstances*_priceInstancesSize];
double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int bars, int instanceNo=0)
{
  if (tprice>=pr_haclose)
   {
      if (ArrayRange(workHa,0)!= bars) ArrayResize(workHa,bars); instanceNo*=_priceInstancesSize; int r = bars-i-1;
         
         //
         //
         //
         //
         //
         
         double haOpen  = (r>0) ? (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0 : (open[i]+close[i])/2;;
         double haClose = (open[i]+high[i]+low[i]+close[i]) / 4.0;
         if (_prHABF(tprice))
               if (high[i]!=low[i])
                     haClose = (open[i]+close[i])/2.0+(((close[i]-open[i])/(high[i]-low[i]))*fabs((close[i]-open[i])/2.0));
               else  haClose = (open[i]+close[i])/2.0; 
         double haHigh  = fmax(high[i], fmax(haOpen,haClose));
         double haLow   = fmin(low[i] , fmin(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:
            case pr_habclose:    return(haClose);
            case pr_haopen:   
            case pr_habopen:     return(haOpen);
            case pr_hahigh: 
            case pr_habhigh:     return(haHigh);
            case pr_halow:    
            case pr_hablow:      return(haLow);
            case pr_hamedian:
            case pr_habmedian:   return((haHigh+haLow)/2.0);
            case pr_hamedianb:
            case pr_habmedianb:  return((haOpen+haClose)/2.0);
            case pr_hatypical:
            case pr_habtypical:  return((haHigh+haLow+haClose)/3.0);
            case pr_haweighted:
            case pr_habweighted: return((haHigh+haLow+haClose+haClose)/4.0);
            case pr_haaverage:  
            case pr_habaverage:  return((haHigh+haLow+haClose+haOpen)/4.0);
            case pr_hatbiased:
            case pr_habtbiased:
               if (haClose>haOpen)
                     return((haHigh+haClose)/2.0);
               else  return((haLow+haClose)/2.0);        
            case pr_hatbiased2:
            case pr_habtbiased2:
               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("");
}
int timeFrameValue(int _tf)
{
   int add  = (_tf>=0) ? 0 : fabs(_tf);
   if (add != 0) _tf = _Period;
   int size = ArraySize(iTfTable); 
      int i =0; for (;i<size; i++) if (iTfTable[i]==_tf) break;
                                   if (i==size) return(_Period);
                                                return(iTfTable[(int)fmin(i+add,size-1)]);
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
         
           message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" ehlers fisher transform "+doWhat;
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(_Symbol+" ehlers fisher transform ",message);
             if (alertsSound)   PlaySound("alert2.wav");
      }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

void drawArrow(int i,color theColor,int theCode, int theSize, bool up)
{
   string name = arrowsIdentifier+":"+(string)Time[i];
   double gap  = iATR(NULL,0,20,i);   
   
      //
      //
      //
      //
      //

      datetime atime = Time[i]; if (arrowsOnNewest) atime += PeriodSeconds(_Period)-1;     
      ObjectCreate(name,OBJ_ARROW,0,atime,0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_WIDTH,theSize);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i] + arrowsUpperGap * gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i]  - arrowsLowerGap * gap);
}

//
//
//

void drawLine(int i,color theColor)
{
      string name = vLinesID+":"+(string)Time[i];
   
      //
      //
      //
      //
      //
         
      datetime time = Time[i]; if (linesOnNewest) time += _Period*60-1;    
      ObjectCreate(name,OBJ_VLINE,0,time,0);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_STYLE,vLinesStyle);
         ObjectSet(name,OBJPROP_WIDTH,vLinesWidth);
         ObjectSet(name,OBJPROP_BACK,true);
}

//
//
//

double iDeviation(double& array[], int period2, int pos)
{
   double dMA  = iSma(array,period2,pos);
   double dSum = 0;
      for(int i=0; i<period2; i++,pos++) dSum += (array[pos]-dMA)*(array[pos]-dMA);
   return(MathSqrt(dSum/period2));
}
double iSma(double& array[], int period3, int pos)
{
   double sum = 0.0;
      for(int i=0; i<period3; i++,pos++) sum += array[pos];
   return(sum/period3);     
}
//+------------------------------------------------------------------+

//+--------------------------- END ----------------------------------+
