Laguerre Moving Average

Hi, I stumbled upon this code (mind you, from tradingview: all credit goes to TheLark over there for turning it into a strategy). Results are impressive, at least with this Bitcoin 1h chart (using a 0.5 offset in settings).

Was wondering if any of you guys has a way to port this to MQ4 format or port it to an algorithm here?

Check it out:

study(title = "TheLark: Laguerre Moving Average", shorttitle="TheLark LMA", overlay=true)

//•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•//
//                                             //
//            LAGUERRE MA BY THELARK           //
//                 ~ 2-11-14 ~                 //
//                                             //
//                     •/•                     //
//                                             //
//                                             //
//•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•/•//

// The Laguerre Average was discovered by John Ehlers.
// It's a newer type of averaging that is meant to take out as much of the
// inherent lag that your typical EMA and SMA's give at the start of a major trend change.
// So what you get is an average that turns more quickly at major trend changes,
// and doesn't get tripped up on the noise (as much).

//setups
h = high
l = low
//inputs
Gamma = input(0.77)
sd = input(true, title="Show dots?")
//calc
lag(g) =>
p = (h + l)/2
L0 = (1 - g)*p+g*nz(L0[1])
L1 = -g*L0+nz(L0[1])+g*nz(L1[1])
L2 = -g*L1+nz(L1[1])+g*nz(L2[1])
L3 = -g*L2+nz(L2[1])+g*nz(L3[1])
f = (L0 + 2*L1 + 2*L2 + L3)/6
f
//plots
lma = lag(Gamma)
col =  lma > lma[1] ? #0094FF : #FF3571
up = lma > lma[1] ? 1 : 0
down = lma < lma[1] ? 1 : 0
plot(lma,linewidth=2,color=col)
plot(sd and cross(up,down) ? lma : na,style=circles, linewidth=4, color=col )

4 responses

Hi Ivan,
Is this code complete? For example where are the value for the variable "nz" assigned?? (I take it this represents some noise function..)
I take it the variable 'lma' represents the Laguerre Moving Average, but then what is all the other code doing after the line "lma = lag(Gamma)".

I am not familiar with "MQ4 format" isn’t this used in FOREX trading, something I dont believe Quantopian support's just yet?

Steve

MQ4 is code for meta trader 4, and yes, I use it for Bitcoin trading.
Was interested in backtesting with zipline using Bitcoin data from BTC-E.com (I think I saw an example here) or just porting this indicator to MT4.
I've found it to be really useful for short term trading.
Seems like the tradingview code is invoking some pre-made script so no go then.

Stumbled upon this, maybe you can work with it (this has the mql4 part covered and contains code for a lot of different MA types, no.25 is Laguerre):

//+------------------------------------------------------------------+
//|                                             AllAverages_v3.1.mq4 |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                   E-mail: [email protected] |
//+------------------------------------------------------------------+
// List of MAs:
// MA_Method= 0: SMA        - Simple Moving Average
// MA_Method= 1: EMA        - Exponential Moving Average
// MA_Method= 2: Wilder     - Wilder Exponential Moving Average
// MA_Method= 3: LWMA       - Linear Weighted Moving Average
// MA_Method= 4: SineWMA    - Sine Weighted Moving Average
// MA_Method= 5: TriMA      - Triangular Moving Average
// MA_Method= 6: LSMA       - Least Square Moving Average (or EPMA, Linear Regression Line)
// MA_Method= 7: SMMA       - Smoothed Moving Average
// MA_Method= 8: HMA        - Hull Moving Average by Alan Hull
// MA_Method= 9: ZeroLagEMA - Zero-Lag Exponential Moving Average
// MA_Method=10: DEMA       - Double Exponential Moving Average by Patrick Mulloy
// MA_Method=11: T3_basic   - T3 by T.Tillson (original version)
// MA_Method=12: ITrend     - Instantaneous Trendline by J.Ehlers
// MA_Method=13: Median     - Moving Median
// MA_Method=14: GeoMean    - Geometric Mean
// MA_Method=15: REMA       - Regularized EMA by Chris Satchwell
// MA_Method=16: ILRS       - Integral of Linear Regression Slope
// MA_Method=17: IE/2       - Combination of LSMA and ILRS
// MA_Method=18: TriMAgen   - Triangular Moving Average generalized by J.Ehlers
// MA_Method=19: VWMA       - Volume Weighted Moving Average
// MA_Method=20: JSmooth    - Smoothing by Mark Jurik
// MA_Method=21: SMA_eq     - Simplified SMA
// MA_Method=22: ALMA       - Arnaud Legoux Moving Average
// MA_Method=23: TEMA       - Triple Exponential Moving Average by Patrick Mulloy
// MA_Method=24: T3         - T3 by T.Tillson (correct version)
// MA_Method=25: Laguerre   - Laguerre filter by J.Ehlers
// MA_Method=26: MD         - McGinley Dynamic

// List of Prices:
// Price    = 0 - Close
// Price    = 1 - Open
// Price    = 2 - High
// Price    = 3 - Low
// Price    = 4 - Median Price   = (High+Low)/2
// Price    = 5 - Typical Price  = (High+Low+Close)/3
// Price    = 6 - Weighted Close = (High+Low+Close*2)/4
// Price    = 7 - Heiken Ashi Close
// Price    = 8 - Heiken Ashi Open
// Price    = 9 - Heiken Ashi High
// Price    =10 - Heiken Ashi Low

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1  Silver
#property indicator_width1  2
#property indicator_color2  DeepSkyBlue
#property indicator_width2  2
#property indicator_color3  Tomato
#property indicator_width3  2

//----
extern int     TimeFrame    =  0;
extern int     Price        =  0;
extern int     MA_Period    = 14;
extern int     MA_Shift     =  0;
extern int     MA_Method    =  0;
extern int     Color_Mode   =  0;
extern int     Sound_Mode   =  0; //0-off,1-on(works only with Color_Mode=1)
extern int     Sound_Shift  =  0; //0-open bar(multiple),1-closed bar(once)

extern string  PriceMode    = "";
extern string  _0           = "Close";
extern string  _1           = "Open";
extern string  _2           = "High";
extern string  _3           = "Low";
extern string  _4           = "Median";
extern string  _5           = "Typical";
extern string  _6           = "Weighted Close";
extern string  _7           = "Heiken Ashi Close";
extern string  _8           = "Heiken Ashi Open";
extern string  _9           = "Heiken Ashi High";
extern string  _10          = "Heiken Ashi Low";
extern string  MAMode       = "";
extern string  __0          = "SMA";
extern string  __1          = "EMA";
extern string  __2          = "Wilder";
extern string  __3          = "LWMA";
extern string  __4          = "SineWMA";
extern string  __5          = "TriMA";
extern string  __6          = "LSMA";
extern string  __7          = "SMMA";
extern string  __8          = "HMA";
extern string  __9          = "ZeroLagEMA";
extern string  __10         = "DEMA";
extern string  __11         = "T3 basic";
extern string  __12         = "ITrend";
extern string  __13         = "Median";
extern string  __14         = "GeoMean";
extern string  __15         = "REMA";
extern string  __16         = "ILRS";
extern string  __17         = "IE/2";
extern string  __18         = "TriMAgen";
extern string  __19         = "VWMA";
extern string  __20         = "JSmooth";
extern string  __21         = "SMA_eq";
extern string  __22         = "ALMA";
extern string  __23         = "TEMA";
extern string  __24         = "T3";
extern string  __25         = "Laguerre";
extern string  __26         = "MD";

double MA[];
double Up[];
double Dn[];
double aPrice[];
//----
double tmp[][2];
double haClose[2], haOpen[2], haHigh[2], haLow[2];
int    draw_begin, arraysize;
string IndicatorName, TF, short_name;
int    sUp = 0, sDn =0;
datetime prevtime, prevhatime;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
//----
IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));

if(TimeFrame == 0 || TimeFrame < Period()) TimeFrame = Period();

//----
IndicatorBuffers(4);

SetIndexBuffer(0,    MA); SetIndexStyle(0,DRAW_LINE); SetIndexShift(0,MA_Shift*TimeFrame/Period());
SetIndexBuffer(1,    Up); SetIndexStyle(1,DRAW_LINE); SetIndexShift(1,MA_Shift*TimeFrame/Period());
SetIndexBuffer(2,    Dn); SetIndexStyle(2,DRAW_LINE); SetIndexShift(2,MA_Shift*TimeFrame/Period());
SetIndexBuffer(3,aPrice);

draw_begin=2*MathCeil(0.5*(MA_Period+1))*TimeFrame/Period();
SetIndexDrawBegin(0,draw_begin);
SetIndexDrawBegin(1,draw_begin);
SetIndexDrawBegin(2,draw_begin);

//----

switch(MA_Method)
{
case 1 : short_name="EMA(";  break;
case 2 : short_name="Wilder("; break;
case 3 : short_name="LWMA("; break;
case 4 : short_name="SineWMA("; break;
case 5 : short_name="TriMA("; break;
case 6 : short_name="LSMA("; break;
case 7 : short_name="SMMA("; break;
case 8 : short_name="HMA("; break;
case 9 : short_name="ZeroLagEMA("; break;
case 10: short_name="DEMA("; arraysize = 2; break;
case 11: short_name="T3 basic("; arraysize = 6; break;
case 12: short_name="InstTrend(";  break;
case 13: short_name="Median(";  break;
case 14: short_name="GeometricMean("; break;
case 15: short_name="REMA(";  break;
case 16: short_name="ILRS(";  break;
case 17: short_name="IE/2(";  break;
case 18: short_name="TriMA_gen("; break;
case 19: short_name="VWMA("; break;
case 20: short_name="JSmooth("; arraysize = 5; break;
case 21: short_name="SMA_eq("; break;
case 22: short_name="ALMA("; break;
case 23: short_name="TEMA("; arraysize = 4; break;
case 24: short_name="T3("; arraysize = 6; break;
case 25: short_name="Laguerre("; arraysize = 4; break;
case 26: short_name="McGinleyDynamic(";  break;
default: MA_Method=0; short_name="SMA(";
}

switch(TimeFrame)
{
case 1     : TF = "M1" ; break;
case 5     : TF = "M5" ; break;
case 15    : TF = "M15"; break;
case 30    : TF = "M30"; break;
case 60    : TF = "H1" ; break;
case 240   : TF = "H4" ; break;
case 1440  : TF = "D1" ; break;
case 10080 : TF = "W1" ; break;
case 43200 : TF = "MN1"; break;
default    : TF = "Current";
}

IndicatorName = WindowExpertName();

IndicatorShortName(short_name+MA_Period+")"+" "+TF);

SetIndexLabel(1,short_name+MA_Period+")"+" "+TF+" UpTrend");
SetIndexLabel(2,short_name+MA_Period+")"+" "+TF+" DnTrend");
SetIndexLabel(0,short_name+MA_Period+")"+" "+TF);

//----
ArrayResize(tmp,arraysize);

return(0);
}
//+------------------------------------------------------------------+
//| AllAverages_v3.1                                                 |
//+------------------------------------------------------------------+
int start()
{
int limit, y, i, shift, cnt_bars = IndicatorCounted();

if(cnt_bars > 0)  limit = Bars - cnt_bars - 1;
if(cnt_bars < 0)  return(0);
if(cnt_bars < 1)
{
limit = Bars - 1;

for(i=Bars-1;i>0;i--)
{
MA[i] = EMPTY_VALUE;
Up[i] = EMPTY_VALUE;
Dn[i] = EMPTY_VALUE;
}
}

//----
if(TimeFrame != Period())
{
limit = MathMax(limit,TimeFrame/Period()+1);

for(shift = 0;shift < limit;shift++)
{
y = iBarShift(NULL,TimeFrame,Time[shift]);

if(Color_Mode > 0)
{
}
}

return(0);
}
else
{
for(shift=limit;shift>=0;shift--)
{
if(arraysize > 1 && prevtime != Time[shift])
{
for(i=0;i0) double lwma = Sum/Weight;
else lwma = 0;
return(lwma);
}
// MA_Method=4: SineWMA - Sine Weighted Moving Average
double SineWMA(double array[],int per,int bar)
{
double pi = 3.1415926535;
double Sum = 0;
double Weight = 0;

for(int i = 0;i < per;i++)
{
Weight+= MathSin(pi*(i+1)/(per+1));
Sum += array[bar+i]*MathSin(pi*(i+1)/(per+1));
}
if(Weight>0) double swma = Sum/Weight;
else swma = 0;
return(swma);
}
// MA_Method=5: TriMA - Triangular Moving Average
double TriMA(double array[],int per,int bar)
{
double sma;
int len = MathCeil((per+1)*0.5);

double sum=0;
for(int i = 0;i < len;i++)
{
sma = SMA(array,len,bar+i);
sum += sma;
}
double trima = sum/len;

return(trima);
}
// MA_Method=6: LSMA - Least Square Moving Average (or EPMA, Linear Regression Line)
double LSMA(double array[],int per,int bar)
{
double Sum=0;
for(int i=per; i>=1; i--) Sum += (i-(per+1)/3.0)*array[bar+per-i];
double lsma = Sum*6/(per*(per+1));
return(lsma);
}
// MA_Method=7: SMMA - Smoothed Moving Average
double SMMA(double array[],double prev,int per,int bar)
{
if(bar == Bars - per) double smma = SMA(array,per,bar);
else
if(bar < Bars - per)
{
double Sum = 0;
for(int i = 0;i < per;i++) Sum += array[bar+i+1];
smma = (Sum - prev + array[bar])/per;
}

return(smma);
}
// MA_Method=8: HMA - Hull Moving Average by Alan Hull
double HMA(double array[],int per,int bar)
{
double tmp[];
int len = MathSqrt(per);

ArrayResize(tmp,len);

if(bar == Bars - per) double hma = array[bar];
else
if(bar < Bars - per)
{
for(int i=0;i0) double vwma = Sum/Weight;
else vwma = 0;
return(vwma);
}

// MA_Method=20: JSmooth - Smoothing by Mark Jurik
double JSmooth(int num,double price,int per,double pow,int bar)
{
double beta = 0.45*(per-1)/(0.45*(per-1)+2);
double alpha = MathPow(beta,pow);
if(bar == Bars - 2) {tmp[num+4][0] = price; tmp[num+0][0] = price; tmp[num+2][0] = price;}
else
if(bar <  Bars - 2)
{
tmp[num+0][0] = (1-alpha)*price + alpha*tmp[num+0][1];
tmp[num+1][0] = (price - tmp[num+0][0])*(1-beta) + beta*tmp[num+1][1];
tmp[num+2][0] = tmp[num+0][0] + tmp[num+1][0];
tmp[num+3][0] = (tmp[num+2][0] - tmp[num+4][1])*MathPow((1-alpha),2) + MathPow(alpha,2)*tmp[num+3][1];
tmp[num+4][0] = tmp[num+4][1] + tmp[num+3][0];
}
return(tmp[num+4][0]);
}

// MA_Method=21: SMA_eq     - Simplified SMA
double SMA_eq(double price[],double array[],int per,int bar)
{
if(bar == Bars - per) double sma = SMA(price,per,bar);
else
if(bar <  Bars - per) sma = (price[bar] - price[bar+per])/per + array[bar+1];

return(sma);
}

// MA_Method=22: ALMA by Arnaud Legoux / Dimitris Kouzis-Loukas / Anthony Cascino
double ALMA(double price[],int per,double offset,double sigma,int bar)
{
double m = MathFloor(offset * (per - 1));
double s = per/sigma;

double w, sum =0, wsum = 0;
for (int i=0;i < per;i++)
{
w = MathExp(-((i - m)*(i - m))/(2*s*s));
wsum += w;
sum += price[bar+(per-1-i)] * w;
}

if(wsum != 0) double alma = sum/wsum;

return(alma);
}

// MA_Method=23: TEMA - Triple Exponential Moving Average by Patrick Mulloy
double TEMA(double price,int per,double v,int bar)
{
double alpha = 2.0/(per+1);

if(bar == Bars - 2) {tmp[0][0] = price; tmp[1][0] = price; tmp[2][0] = price;}
else
if(bar <  Bars - 2)
{
tmp[0][0] = tmp[0][1] + alpha *(price     - tmp[0][1]);
tmp[1][0] = tmp[1][1] + alpha *(tmp[0][0] - tmp[1][1]);
tmp[2][0] = tmp[2][1] + alpha *(tmp[1][0] - tmp[2][1]);
tmp[3][0] = tmp[0][0] + v*(tmp[0][0] + v*(tmp[0][0]-tmp[1][0]) - tmp[1][0] - v*(tmp[1][0] - tmp[2][0]));
}

return(tmp[3][0]);
}

// MA_Method=24: T3 by T.Tillson (correct version)
double T3(int num,double price,int per,double v,int bar)
{
double len = MathMax((per + 5.0)/3.0-1,1), dema1, dema2;

if(bar == Bars - 2)
{
double T3 = price;
for(int k=0;k


A little late to this thread :) Here is my attempt at the Laguerre RSI. I think this is right although I'm not sure how to set the bar count variable

18
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
 Returns 1 Month 3 Month 6 Month 12 Month
 Alpha 1 Month 3 Month 6 Month 12 Month
 Beta 1 Month 3 Month 6 Month 12 Month
 Sharpe 1 Month 3 Month 6 Month 12 Month
 Sortino 1 Month 3 Month 6 Month 12 Month
 Volatility 1 Month 3 Month 6 Month 12 Month
 Max Drawdown 1 Month 3 Month 6 Month 12 Month
import talib
from datetime import datetime
import numpy as np

def initialize(context):
context.max_notional = 100000
#context.stock = sid(8084)
#set_benchmark(sid(8084))
context.stock = symbol('SPY')
set_benchmark(symbol('SPY'))
context.lookback = 500
context.charttype = '1d'
context.L0 = 0
context.L1 = 0
context.L2 = 0
context.L3 = 0
context.L0_s = 0
context.L1_s = 0
context.L2_s = 0
context.L3_s = 0
context.lagrsi = 0
context.lagrsi_s = 0
context.gamma = .6

context.gamma_s = .8
schedule_function(
func=getlag,
date_rule=date_rules.every_day(),
time_rule=time_rules.market_close(minutes=1),
half_days=True)

def lag_rsi(context,prices_close):
L0_n = (1 - context.gamma)*prices_close + context.gamma*context.L0
L1_n = -context.gamma*L0_n+context.L0+context.gamma*context.L1
L2_n = -context.gamma*L1_n+context.L1+context.gamma*context.L2
L3_n = -context.gamma*L2_n+context.L2+context.gamma*context.L3

context.L0 = L0_n
context.L1 = L1_n
context.L2 = L2_n
context.L3 = L3_n

cu = 0
cd = 0

if L0_n >= L1_n:
cu = L0_n - L1_n
else:
cd = L1_n - L0_n

if L1_n >= L2_n:
cu = cu + L1_n - L2_n
else:
cd = cd + L2_n - L1_n

if L2_n >= L3_n:
cu = cu + L2_n - L3_n
else:
cd = cd + L3_n - L2_n
if cu+cd != 0:
lrsi = cu/(cu+cd)
return lrsi

def lag_rsi_s(context,prices_close):
L0_n = (1 - context.gamma_s)*prices_close + context.gamma_s*context.L0_s
L1_n = -context.gamma_s*L0_n+context.L0_s+context.gamma_s*context.L1_s
L2_n = -context.gamma_s*L1_n+context.L1_s+context.gamma_s*context.L2_s
L3_n = -context.gamma_s*L2_n+context.L2_s+context.gamma_s*context.L3_s

context.L0_s = L0_n
context.L1_s = L1_n
context.L2_s = L2_n
context.L3_s = L3_n

cu = 0
cd = 0

if L0_n >= L1_n:
cu = L0_n - L1_n
else:
cd = L1_n - L0_n

if L1_n >= L2_n:
cu = cu + L1_n - L2_n
else:
cd = cd + L2_n - L1_n

if L2_n >= L3_n:
cu = cu + L2_n - L3_n
else:
cd = cd + L3_n - L2_n
if cu+cd != 0:
lrsi = cu/(cu+cd)
return lrsi

def getlag(context,data):

closeprice = data.history(context.stock, 'close', 2, '1d')[-2]

context.lagrsi = lag_rsi(context,closeprice)
context.lagrsi_s = lag_rsi_s(context,closeprice)
record(lrsi_fast = context.lagrsi)
record(lrsi_slow = context.lagrsi_s)
#print '--------------------'
#print 'RSI'+str(context.rsi)
#print '--------------------'


There was a runtime error.

Laguerre filter..

31
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
 Returns 1 Month 3 Month 6 Month 12 Month
 Alpha 1 Month 3 Month 6 Month 12 Month
 Beta 1 Month 3 Month 6 Month 12 Month
 Sharpe 1 Month 3 Month 6 Month 12 Month
 Sortino 1 Month 3 Month 6 Month 12 Month
 Volatility 1 Month 3 Month 6 Month 12 Month
 Max Drawdown 1 Month 3 Month 6 Month 12 Month
import talib
from datetime import datetime
import numpy as np

def initialize(context):
context.max_notional = 100000
#context.stock = sid(8084)
#set_benchmark(sid(8084))
context.stock = symbol('qqq')
set_benchmark(symbol('qqq'))
context.lookback = 500
context.L0 = [0]
context.L1 = [0]
context.L2 = [0]
context.L3 = [0]
context.gamma = .2
context.lfilter = 0
schedule_function(
func=getlag,
date_rule=date_rules.every_day(),
time_rule=time_rules.market_close(minutes=1),
half_days=True)

def get_lag(context,highprice,lowprice):
price_var = (highprice+lowprice)/2
filt = 0

L0 = context.gamma*price_var+(1-context.gamma)*context.L0[-1]
L1 = -(1 - context.gamma)*L0+context.L0[-1]+(1-context.gamma)*context.L1[-1]
L2 = -(1 - context.gamma)*L1+context.L1[-1]+(1-context.gamma)*context.L2[-1]
L3 = -(1 - context.gamma)*L2+context.L2[-1]+(1-context.gamma)*context.L3[-1]

filt = (L0+2*L1+2*L2+L3)/6
context.L0.append(L0)
context.L1.append(L1)
context.L2.append(L2)
context.L3.append(L3)
return filt

# Will be called on every trade event for the securities you specify.
def getlag(context, data):

lowprice =  data.history(context.stock, 'low', 2, '1d')[-2]
highprice =  data.history(context.stock, 'high', 2, '1d')[-2]
closeprice = data.history(context.stock, 'close', 2, '1d')[-2]

lfilter = get_lag(context,highprice,lowprice)

record(lag_filter = lfilter)
record(price_val = closeprice)


There was a runtime error.