Dear all,

Meant to come back to this thread, but only getting round to it now. I've had a look at a version of TMA + CG (there are a few around), it appears very accurate on MT4, but of course it repaints. None the less I like the idea of a TMA with bands above and below.

Code:
extern string TimeFrame       = "current time frame";
extern int    HalfLength      = 56;
extern int    Price           = PRICE_WEIGHTED;
extern double BandsDeviations = 2.5;
extern bool   showPrice       = true;
//
//
//
//
//

double tmBuffer[];
double upBuffer[];
double dnBuffer[];
double wuBuffer[];
double wdBuffer[];
double upLevel[];
double dnLevel[];

//
//
//
//
//

string IndicatorFileName;
bool   calculatingTma = false;
bool   returningBars  = false;
int    timeFrame;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

int init()
  {
   timeFrame  = stringToTimeFrame(TimeFrame);
   HalfLength = MathMax(HalfLength,1);
   IndicatorBuffers(7);
   SetIndexBuffer(0,tmBuffer);  SetIndexDrawBegin(0,HalfLength);
   SetIndexBuffer(1,upBuffer);  SetIndexDrawBegin(1,HalfLength);
   SetIndexBuffer(2,dnBuffer);  SetIndexDrawBegin(2,HalfLength);
   SetIndexBuffer(3,dnLevel);   SetIndexStyle(3,DRAW_LINE);
   SetIndexBuffer(4,upLevel);   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE,STYLE_DOT,1);
   SetIndexStyle(4,DRAW_LINE,STYLE_DOT,1);
   SetIndexBuffer(5,wuBuffer);
   SetIndexBuffer(6,wdBuffer);

   if(TimeFrame=="calculateTma")  { calculatingTma=true; return(0); }
   if(TimeFrame=="returnBars")    { returningBars=true;  return(0); }


   IndicatorFileName=WindowExpertName();
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int deinit()
  {
   for(int i=ObjectsTotal()-1; i>=0; i--)
     {
      if(StringSubstr(ObjectName(i),0,4)=="band")
         ObjectDelete(ObjectName(i));

     }

   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
  {
   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+HalfLength);

   if(returningBars)  { tmBuffer[0] = limit; return(0); }
   if(calculatingTma) { calculateTma(limit); return(0); }
   if(timeFrame>Period()) limit=MathMax(limit,MathMin(Bars-1,iCustom(NULL,timeFrame,IndicatorFileName,"returnBars",0,0)*timeFrame/Period()));

//
//
//
//
//

   for(i=limit; i>=0; i--)
     {
      int      shift1 = iBarShift(NULL,timeFrame,Time[i]);
      datetime time1  = iTime    (NULL,timeFrame,shift1);
      double level;

      tmBuffer[i] = iCustom(NULL,timeFrame,IndicatorFileName,"calculateTma",HalfLength,Price,BandsDeviations,0,shift1);
      upBuffer[i] = iCustom(NULL,timeFrame,IndicatorFileName,"calculateTma",HalfLength,Price,BandsDeviations,1,shift1);
      dnBuffer[i] = iCustom(NULL,timeFrame,IndicatorFileName,"calculateTma",HalfLength,Price,BandsDeviations,2,shift1);

      level=(upBuffer[i]-dnBuffer[i])*20/100; // other lines take away 20% OF DIFFERENCE IN RANGE
      
      upLevel[i] = (upBuffer[i] - level);
      dnLevel[i] = (dnBuffer[i] + level);
if(showPrice)
{
      SetPrice("bandHigh",Time[0],upBuffer[0],Red);
      SetPrice("bandMid",Time[0],tmBuffer[0],DimGray);
      SetPrice("bandLow",Time[0],dnBuffer[0],LimeGreen);
      
      SetPrice("bandInnerHigh",Time[0],upLevel[0],Red);
      SetPrice("bandInnerLow",Time[0],dnLevel[0],LimeGreen);
      }

     }

   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void calculateTma(int limit)
  {
   int i,j,k;
   double FullLength=2.0*HalfLength+1.0;

   for(i=limit; i>=0; i--)
     {
      double sum  = (HalfLength+1)*iMA(NULL,0,1,0,MODE_SMA,Price,i);
      double sumw = (HalfLength+1);
      for(j=1,k=HalfLength; j<=HalfLength; j++,k--)
        {
         sum  += k*iMA(NULL,0,1,0,MODE_SMA,Price,i+j);
         sumw += k;

         if(j<=i)
           {
            sum  += k*iMA(NULL,0,1,0,MODE_SMA,Price,i-j);
            sumw += k;
           }
        }
      tmBuffer[i]=sum/sumw;

      //
      //
      //
      //
      //

      double diff=iMA(NULL,0,1,0,MODE_SMA,Price,i)-tmBuffer[i];
      if(i>(Bars-HalfLength-1)) continue;
      if(i==(Bars-HalfLength-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]);


     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//
//
//
//
//
//

int stringToTimeFrame(string tfs)
  {
   for(int l=StringLen(tfs)-1; l>=0; l--)
     {
      int thechar=StringGetChar(tfs,l);
      if((thechar>96 && thechar<123) || (thechar>223 && thechar<256))
         tfs=StringSetChar(tfs,1,thechar-32);
      else
      if(thechar>-33 && thechar<0)
         tfs=StringSetChar(tfs,1,thechar+224);
     }
   int tf=0;
   if(tfs=="M1" || tfs=="1")     tf=PERIOD_M1;
   if(tfs=="M5" || tfs=="5")     tf=PERIOD_M5;
   if(tfs=="M15"|| tfs=="15")    tf=PERIOD_M15;
   if(tfs=="M30"|| tfs=="30")    tf=PERIOD_M30;
   if(tfs=="H1" || tfs=="60")    tf=PERIOD_H1;
   if(tfs=="H4" || tfs=="240")   tf=PERIOD_H4;
   if(tfs=="D1" || tfs=="1440")  tf=PERIOD_D1;
   if(tfs=="W1" || tfs=="10080") tf=PERIOD_W1;
   if(tfs=="MN" || tfs=="43200") tf=PERIOD_MN1;
   if(tf==0 || tf<Period()) tf=Period();
   return(tf);
  }
//+------------------------------------------------------------------+

void SetPrice(string name, datetime Tm, double Prc, color clr) {
	if(ObjectFind(name) == -1) {
		ObjectCreate(name, OBJ_ARROW, 0, Tm, Prc);
		ObjectSet(name, OBJPROP_COLOR, clr);
		ObjectSet(name, OBJPROP_WIDTH, 1);
		ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_RIGHTPRICE);
	} else {
		ObjectSet(name, OBJPROP_TIME1, Tm);
		ObjectSet(name, OBJPROP_PRICE1, Prc);
		ObjectSet(name, OBJPROP_COLOR, clr);
		ObjectSet(name, OBJPROP_WIDTH, 1);
		ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_RIGHTPRICE);
	}
}
//+------------------------------------------------------------------+



My understanding of the above, I'm a trader not a programmer, is that it calculates a triangular moving average, tmbuffer[], then calculates the bands based on a weighted average of the differences between the price and the tmbuffer.

1) I don't really understand that bit, but I think it may be where the center of gravity comes in. Jcl, I would really appreciate a mathematicians explanation of it appropriate to my mental age of 7.

2) As an aside, I also cannot understand why the author uses iMA (MT4's moving average function) with a period of 1, is that not simply the price?

3) With my limitations, I did have a crack at coding it for zorro, but am unsure if this is correct.

Code:
function run()
{
	StartDate	= 20140101;
	EndDate		= 20140130;
	BarPeriod	= 15;
	
	int		HalfLength      = 56;	
	var		BandsDeviations = 2.5;
	
	vars	Price          = series(price());
	vars	tmBuffer			= series(0);
	vars	upBuffer			= series(0);
	vars	dnBuffer			= series(0);
	vars	wuBuffer			= series(0);
	vars	wdBuffer			= series(0);



   int i,j,k;
   
   var FullLength = 2.0*HalfLength+1;
   
   for (i=HalfLength; i>=0; i--)
		{
      	var sum  = (HalfLength+1)*SMA(Price+i,1);
      	var sumw = (HalfLength+1);
			
      	for(j=1, k=HalfLength; j<=HalfLength; j++, k--)
      		{
         		sum  += k*SMA(Price+(i+j),1);
         		sumw += k;
					
         		if (j<=i)
         			{
            			sum  += k*SMA(Price+(i-j),1);
            			sumw += k;
         			}
      		}
      	tmBuffer[0] = sum/sumw;
			
			var diff = SMA(Price+i,1)-tmBuffer[i];
         if (i> (Bar-HalfLength-1)) continue;
         if (i==(Bar-HalfLength-1))
         	{
            	upBuffer[i] = tmBuffer[i];
            	dnBuffer[i] = tmBuffer[i];
            
            	if (diff>=0)
               	{
                  	wuBuffer[i] = pow(diff,2);
                  	wdBuffer[i] = 0;
               	}
            	else
               	{               
                  	wdBuffer[i] = pow(diff,2);
                  	wuBuffer[i] = 0;
               	}                  
            	continue;
         	}
      		
			if(diff>=0)
            {
               wuBuffer[i] = (wuBuffer[i+1]*(FullLength-1)+pow(diff,2))/FullLength;
               wdBuffer[i] = (wdBuffer[i+1]*(FullLength-1))/FullLength;
            }
         else
            {
               wdBuffer[i] = (wdBuffer[i+1]*(FullLength-1)+pow(diff,2))/FullLength;
               wuBuffer[i] =  wuBuffer[i+1]*(FullLength-1)/FullLength;
            }
            
         upBuffer[0] = tmBuffer[0] + BandsDeviations*sqrt(wuBuffer[0]);
         dnBuffer[0] = tmBuffer[0] - BandsDeviations*sqrt(wdBuffer[0]);
		}
   
   
   plot("tmbuffer",tmBuffer[0],0,BLUE);
   plot("upbuffer",upBuffer[0],0,RED);
   plot("dnbuffer",dnBuffer[0],0,GREEN);
   

}



I'm not happy with the above, possibly because the plots don't repaint, but visually it does not look so impressive as the MT4 one.

I'm pretty sure this can be improved on in zorro using the built in TRIMA and possibly the centre of gravity indicators, but I'd like to know if I'm on the right track and understand the band calculation a bit more first.