//+------------------------------------------------------------------+
//|                       TriangularMA centered asymmetric bands.mq4 |
//|       Mladen                                                     |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------------------------------+
//|                                                  AIS TMA+EMA.mq4                         |
//| https://forexsystemsru.com/threads/matematicheskie-osnovy-indikatorov.89867/post-1789861 |
//|                                                        AIS Forex                         |
//|       AlexeNP          https://www.mql5.com/ru/users/aleksej1966                         |
//+------------------------------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                    TMA(AlexeNP)_centered_asymmetric_bands_gm.mq4 |
//|       Genry(gm)                                                  |
//+------------------------------------------------------------------+
// 10jan2023 Genry mod: не рисующая TMA calculation without redrawing
// RUS: Индикатор TMA(AlexeNP)_centered_asymmetric_bands_gm объединяет коды индикаторов от AlexeNP и Mladena. 
// Eng: Indicator TMA(AlexeNP)_centered_asymmetric_bands_gm combines indicator codes from AlexeNP and Mladen. 
// RUS: Расчетная часть алгоритма ТМА Младена заменена на расчет без переррисовки от Алексея.
// Eng: The calculation part of Mladen's TMA algorithm was replaced by Alexey's calculation without redrawing.
// RUS: Добавлена возможность выбора символа. Added the ability to select a symbol.
// RUS: Индикатор разработан в теме (The indicator is developed in the theme): 
//        https://forexsystemsru.com/threads/sovetnik-twokio-abha.87593/post-1818243
//--------
// 
// С уважением, Генри. (Sincerely, Genry)
//---------------------------------------------------------------------------------------------------------------------------------------
 

#property copyright "mladen; AlexeNP; Genry(gm)"
#property link      "NoLink"
#property version   "1.00"
#property strict

#property description "10jan2023 Genry mod:Indicator TMA(AlexeNP)_centered_asymmetric_bands_gm combines indicator codes from AlexeNP and Mladen."

#property indicator_chart_window
#property indicator_buffers 5

#property indicator_color1  clrDodgerBlue
#property indicator_color2  clrOrangeRed
#property indicator_color3  clrLimeGreen
#property indicator_color4  clrYellow
#property indicator_color5  clrYellow

#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT
//---
//---
extern string              TimeFrame       = "0";
extern string              For_Symbol      = "";
extern int                 Period_TMA      = 20;
input ushort               Period_EMA      = 10;
input double               Coefficient     = 0.5;//Coefficient EMA
extern ENUM_APPLIED_PRICE  Price           = PRICE_WEIGHTED;
extern double              BandsDeviations = 2.382;
extern double              koeff           = 0.0001;
extern bool                Interpolate     = true;
//---
//input bool db=true;
//---
double tmBuffer[];
double upBuffer[];
double dnBuffer[];
double wuBuffer[];
double wdBuffer[];
double upArrow[];
double dnArrow[];
//---
int period=0;
double weight[];
//---
string IndicatorFileName;
bool   calculatingTma = false;
bool   returningBars  = false;
int    timeFrame;
string ForSymbol = For_Symbol;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   if (ForSymbol == "") ForSymbol = Symbol();   
  
   period=MathMax(Period_TMA,Period_EMA);
   ArrayResize(weight,period);
   ArrayInitialize(weight,0);
   //---
   if(Period_TMA>0)
     {
      int size=Period_TMA,c=MathMod(size,2)==0?Period_TMA/2:(Period_TMA+1)/2;
      double array[],denom=0;
      ArrayResize(array,size);
      for(int i=0; i<c; i++)
        {
         array[i]=i+1;
         array[size-i-1]=i+1;
        }
      for(int i=0; i<size; i++)
         denom=denom+array[i];
      for(int i=0; i<size; i++)
         weight[i]=array[i]/denom;
     }

   if(Period_EMA>0)
     {
      int size=Period_EMA;
      double array[],c=1-MathMin(MathAbs(Coefficient),1),denom=1;
      size=c==0?1:Period_EMA;
      ArrayResize(array,size);
      array[0]=1;
      for(int i=1; i<size; i++)
        {
         array[i]=array[i-1]*c;
         denom=denom+array[i];
        }
      for(int i=0; i<size; i++)
         weight[i]=weight[i]+array[i]/denom;
     }

   double denom=0;
   for(int i=0; i<period; i++)
      denom=denom+weight[i];
   for(int i=0; i<period; i++)
      weight[i]=weight[i]/denom;   
   
   //---  
   timeFrame  = stringToTimeFrame(TimeFrame);
   Period_TMA = MathMax(Period_TMA,1);
   IndicatorBuffers(7);
   SetIndexBuffer(0,tmBuffer);  SetIndexDrawBegin(0,Period_TMA); SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,upBuffer);  SetIndexDrawBegin(1,Period_TMA); SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,dnBuffer);  SetIndexDrawBegin(2,Period_TMA); SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(3,dnArrow);   SetIndexStyle(3,DRAW_ARROW); SetIndexArrow(3,233);
   SetIndexBuffer(4,upArrow);   SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,234);
   SetIndexBuffer(5,wuBuffer);
   SetIndexBuffer(6,wdBuffer);

   if(TimeFrame=="calculateTma")  { calculatingTma=true; return(0); }
   if(TimeFrame=="returnBars")    { returningBars=true;  return(0); }

//---

   IndicatorFileName=WindowExpertName();
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  
int deinit() { 
   return(0); 
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
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 counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   limit=MathMin(Bars-1,Bars-counted_bars-2);  

   if(returningBars)  { tmBuffer[0] = limit; return(0); }
   if(calculatingTma) { calculateTma(limit); return(0); }
   if(timeFrame>Period()) limit=MathMax(limit,MathMin(Bars-1,(int)iCustom(ForSymbol,timeFrame,IndicatorFileName,"returnBars",0,0)*timeFrame/Period())-1);
   //---
   for(i=limit; i>=0; i--)
     {
      int      shift1 = iBarShift(ForSymbol,timeFrame,Time[i]);
      datetime time1  = iTime    (ForSymbol,timeFrame,shift1);
      //---
      tmBuffer[i] = iCustom(ForSymbol,timeFrame,IndicatorFileName,"calculateTma","",Period_TMA,Period_EMA,Coefficient,Price,BandsDeviations,0,shift1);
      upBuffer[i] = iCustom(ForSymbol,timeFrame,IndicatorFileName,"calculateTma","",Period_TMA,Period_EMA,Coefficient,Price,BandsDeviations,1,shift1);
      dnBuffer[i] = iCustom(ForSymbol,timeFrame,IndicatorFileName,"calculateTma","",Period_TMA,Period_EMA,Coefficient,Price,BandsDeviations,2,shift1);
      upArrow[i] = EMPTY_VALUE;
      dnArrow[i] = EMPTY_VALUE;
      if(iHigh(ForSymbol,timeFrame,i+1)>upBuffer[i+1] && iClose(ForSymbol,timeFrame,i+1)>iOpen(ForSymbol,timeFrame,i+1) && iClose(ForSymbol,timeFrame,i)<iOpen(ForSymbol,timeFrame,i)) upArrow[i] = iHigh(ForSymbol,timeFrame,i)+iATR(ForSymbol,timeFrame,20,i)+koeff;
      if( iLow(ForSymbol,timeFrame,i+1)<dnBuffer[i+1] && iClose(ForSymbol,timeFrame,i+1)<iOpen(ForSymbol,timeFrame,i+1) && iClose(ForSymbol,timeFrame,i)>iOpen(ForSymbol,timeFrame,i)) dnArrow[i] = iLow(ForSymbol,timeFrame,i)-iATR(ForSymbol,timeFrame,20,i)-koeff;

      if(timeFrame<=Period() || shift1==iBarShift(ForSymbol,timeFrame,Time[i>0?i-1:0])) continue;
      if(!Interpolate) continue;
      //---
      int n;
      for(n=1; i+n<Bars-1 && Time[i+n]>=time1; n++) continue;
      double factor=1.0/n;
      for(int k=1; k<n; k++)
        {
         tmBuffer[i+k] = k*factor*tmBuffer[i+n] + (1.0-k*factor)*tmBuffer[i];
         upBuffer[i+k] = k*factor*upBuffer[i+n] + (1.0-k*factor)*upBuffer[i];
         dnBuffer[i+k] = k*factor*dnBuffer[i+n] + (1.0-k*factor)*dnBuffer[i];
        }
     } // for i=limit; i>=0; i--

   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
void calculateTma(int limit)
  {
   int i;//,j,k;
   double FullLength=2.0*Period_TMA+1.0;
   for(i=limit; i>=0; i--)
     {
      double sum=0;
      for(int j=0; j<period; j++)
        {
         int p=i+j;
         sum=sum+weight[j]*iMA(ForSymbol,0,1,0,MODE_SMA,Price,p);
        }       
      tmBuffer[i]=sum; //sum/sumw;
      double diff=iMA(ForSymbol,0,1,0,MODE_SMA,Price,i)-tmBuffer[i];
      //
      if(i>(Bars-Period_TMA-1)) continue;
      if(i==(Bars-Period_TMA-1))
        {
         upBuffer[i] = tmBuffer[i];
         dnBuffer[i] = tmBuffer[i];
         if(diff>=0)
           {
            wuBuffer[i] = MathPow(diff,2);
            wdBuffer[i] = 0;
           }
         else
           {
            wdBuffer[i] = MathPow(diff,2);
            wuBuffer[i] = 0;
           }
         continue;
        }
      //---        
      if(diff>=0)
        {
         wuBuffer[i] = (wuBuffer[i+1]*(FullLength-1)+MathPow(diff,2))/FullLength;
         wdBuffer[i] =  wdBuffer[i+1]*(FullLength-1)/FullLength;
        }
      else
        {
         wdBuffer[i] = (wdBuffer[i+1]*(FullLength-1)+MathPow(diff,2))/FullLength;
         wuBuffer[i] =  wuBuffer[i+1]*(FullLength-1)/FullLength;
        }
      upBuffer[i] = tmBuffer[i] + BandsDeviations*MathSqrt(wuBuffer[i]);
      dnBuffer[i] = tmBuffer[i] - BandsDeviations*MathSqrt(wdBuffer[i]);
     }
  }
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int stringToTimeFrame(string tfs) 
  {
   StringToUpper(tfs);
   for(int i=ArraySize(iTfTable)-1; i>=0; i--)
      if(tfs==sTfTable[i] || tfs==""+(string)iTfTable[i]) return(MathMax(iTfTable[i],Period()));
   return(Period());
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string timeFrameToString(int tf) 
  {
   for(int i=ArraySize(iTfTable)-1; i>=0; i--)
      if(tf==iTfTable[i]) return(sTfTable[i]);
   return("");
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
