
//+------------------------------------------------------------------+
//|                                                  StepMa - 3D.mq4 |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   3
#property indicator_label1  "Fast StepMa"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrDarkGray,clrGreen,clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
#property indicator_label2  "Slow StepMa"
#property indicator_type2   DRAW_COLOR_LINE
#property indicator_color2  clrDarkGray,clrGreen,clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2
#property indicator_label3  "Mid StepMa"
#property indicator_type3   DRAW_COLOR_LINE
#property indicator_color3  clrDarkGray,clrGreen,clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

//
//
//

input ENUM_APPLIED_PRICE    inpPrice   = PRICE_CLOSE;                // Price to use
input int                   ATR_Length = 10;                         // Length
enum  enAtrMode
      {
         atr_Rng,                                                    // Calculate using range
         atr_Atr                                                     // Calculate using ATR
      };
input enAtrMode             AtrMode    = atr_Rng;                    // Range calculating mode
input double                Kv         = 3;                          // Sensitivity
input int                   Window     = 256;                        // ATR minimum maximum window size

double fst[],slw[],mid[],valf[],valm[],vals[];
struct sGlobalStruct
{
   int    lim; 
   double atr,prc,trmax,trmin,ssMin,ssMax,ssMid;
   double tMin,tMid,tMax,lmin,lmid,lmax;
};
sGlobalStruct glo;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int OnInit()
{
   SetIndexBuffer(0,fst, INDICATOR_DATA); 
   SetIndexBuffer(1,valf,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,mid, INDICATOR_DATA);
   SetIndexBuffer(3,valm,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(4,slw, INDICATOR_DATA); 
   SetIndexBuffer(5,vals,INDICATOR_COLOR_INDEX);
   
   IndicatorSetString(INDICATOR_SHORTNAME,"StepMA 3D");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

double work[][13];
#define SminMin   0
#define SmaxMin   1
#define SminMid   2
#define SmaxMid   3
#define SminMax   4
#define SmaxMax   5
#define TrendMin  6
#define TrendMid  7
#define TrendMax  8
#define linemin   9 
#define linemid  10
#define linemax  11
#define k_atr    12
#define bigValue 99999999

//
//
//

int OnCalculate(const int32_t rates_total,
                const int32_t 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 int32_t &spread[])
{
   glo.lim = (prev_calculated ? prev_calculated-1 : 0);
   if (ArrayRange(work,0) != rates_total) ArrayResize(work,rates_total);

   //
   //
   //

   for (int i=glo.lim; i<rates_total && !_StopFlag; i++)
   {
      glo.prc = iGetPrice(inpPrice,open[i],high[i],low[i],close[i]);
      glo.atr = 0; for (int k=0; k<ATR_Length && (i-k-1)>=0; k++) 
                      if (AtrMode==atr_Atr)
                            glo.atr += fmax(high[i-k],close[i-k-1])-fmin(low[i-k],close[i-k-1]);
                      else  glo.atr += high[i-k]-low[i-k];
                      work[i][k_atr] = glo.atr/ATR_Length;  
       
         
               
      if (i<Window)
      {
         work[i][TrendMin] = 0;
         work[i][TrendMid] = 0;
         work[i][TrendMax] = 0;
         work[i][linemin]  = 0;
         work[i][linemid]  = 0;
         work[i][linemax]  = 0;
         work[i][SminMin]  = bigValue;
         work[i][SmaxMin]  = bigValue;
         work[i][SminMax]  = 0;
         work[i][SmaxMax]  = 0;
         work[i][SminMid]  = 0;
         work[i][SmaxMid]  = 0;
         fst[i]            = EMPTY_VALUE;
         slw[i]            = EMPTY_VALUE;
         mid[i]            = EMPTY_VALUE;   
         continue;
      }

      //
      //
      //
      
      glo.trmax = work[i][k_atr];
      glo.trmin = work[i][k_atr];
      for (int k=1; k<Window && (i-k)>=0; k++)
      {
          glo.trmax = fmax(glo.trmax,work[i-k][k_atr]); 
          glo.trmin = fmin(glo.trmin,work[i-k][k_atr]); 
      }         
      if (work[i][k_atr]>glo.trmax) glo.trmax=work[i][k_atr];
	   if (work[i][k_atr]<glo.trmin) glo.trmin=work[i][k_atr];
	
      glo.ssMin = (Kv*glo.trmin);
	   glo.ssMax = (Kv*glo.trmax);
	   glo.ssMid = (Kv*0.5*(glo.trmax+glo.trmin));
	   //glo.ssMin = round(Kv*glo.trmin/_Point)*_Point;
	   //glo.ssMax = round(Kv*glo.trmax/_Point)*_Point;
	   //glo.ssMid = round(Kv*0.5*(glo.trmax+glo.trmin)/_Point)*_Point;
	    
      work[i][SmaxMin] = glo.prc + 2.0 * glo.ssMin;
      work[i][SminMin] = glo.prc - 2.0 * glo.ssMin;
      work[i][SmaxMax] = glo.prc + 2.0 * glo.ssMax;
      work[i][SminMax] = glo.prc - 2.0 * glo.ssMax;
      work[i][SmaxMid] = glo.prc + 2.0 * glo.ssMid;
      work[i][SminMid] = glo.prc - 2.0 * glo.ssMid;

      //
      //
      //
         
      glo.tMin = work[i-1][TrendMin];
      glo.tMid = work[i-1][TrendMid];
      glo.tMax = work[i-1][TrendMax];
      glo.lmin = work[i-1][linemin];
      glo.lmid = work[i-1][linemid];
      glo.lmax = work[i-1][linemax];
            
      if (glo.prc > work[i-1][SmaxMin]) glo.tMin =  1;
      if (glo.prc < work[i-1][SminMin]) glo.tMin = -1;
      if (glo.prc > work[i-1][SmaxMax]) glo.tMax =  1;
      if (glo.prc < work[i-1][SminMax]) glo.tMax = -1;
      if (glo.prc > work[i-1][SmaxMid]) glo.tMid =  1;
      if (glo.prc < work[i-1][SminMid]) glo.tMid = -1;

      if (glo.tMin>0) if(work[i][SminMin]<work[i-1][SminMin]) work[i][SminMin]=work[i-1][SminMin]; 
      if (glo.tMin<0) if(work[i][SmaxMin]>work[i-1][SmaxMin]) work[i][SmaxMin]=work[i-1][SmaxMin]; 
	   if (glo.tMax>0) if(work[i][SminMax]<work[i-1][SminMax]) work[i][SminMax]=work[i-1][SminMax]; 
      if (glo.tMax<0) if(work[i][SmaxMax]>work[i-1][SmaxMax]) work[i][SmaxMax]=work[i-1][SmaxMax]; 
	   if (glo.tMid>0) if(work[i][SminMid]<work[i-1][SminMid]) work[i][SminMid]=work[i-1][SminMid];
      if (glo.tMid<0) if(work[i][SmaxMid]>work[i-1][SmaxMid]) work[i][SmaxMid]=work[i-1][SmaxMid]; 
      if (glo.tMin>0) glo.lmin = work[i][SminMin] + glo.ssMin;
      if (glo.tMin<0) glo.lmin = work[i][SmaxMin] - glo.ssMin;
      if (glo.tMax>0) glo.lmax = work[i][SminMax] + glo.ssMax;
      if (glo.tMax<0) glo.lmax = work[i][SmaxMax] - glo.ssMax;
      if (glo.tMid>0) glo.lmid = work[i][SminMid] + glo.ssMid;
      if (glo.tMid<0) glo.lmid = work[i][SmaxMid] - glo.ssMid;
        work[i][TrendMin] = glo.tMin;
        work[i][TrendMid] = glo.tMid;
        work[i][TrendMax] = glo.tMax;
        work[i][linemin]  = glo.lmin;
        work[i][linemid]  = glo.lmid;
        work[i][linemax]  = glo.lmax;
        fst[i]  = glo.lmin;
        mid[i]  = glo.lmid;
        slw[i]  = glo.lmax;
        valf[i] = (i>0) ? (fst[i]>fst[i-1]) ? 1 : (fst[i]<fst[i-1]) ? 2 : valf[i-1] : 0;
        valm[i] = (i>0) ? (mid[i]>mid[i-1]) ? 1 : (mid[i]<mid[i-1]) ? 2 : valm[i-1] : 0;
        vals[i] = (i>0) ? (slw[i]>slw[i-1]) ? 1 : (slw[i]<slw[i-1]) ? 2 : vals[i-1] : 0; 
   }
return(rates_total);
}

//--------------------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------------------

double iGetPrice(int tprice, double open, double high, const double low, const double close)
{
   switch (tprice)
      {
         case PRICE_CLOSE:     return(close);
         case PRICE_OPEN:      return(open);
         case PRICE_HIGH:      return(high);
         case PRICE_LOW:       return(low);
         case PRICE_MEDIAN:    return((high+low)/2.0);
         case PRICE_TYPICAL:   return((high+low+close)/3.0);
         case PRICE_WEIGHTED:  return((high+low+close+close)/4.0);
      }
   return(0);
}
