CMO with ATR and LagF Filtering - RevNR - 12-27-22
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © hockeydude84

//@version=5
indicator("Chande Momentum Oscillator (CMO) ATR - Laguerre Filtered - RevNR - 12-27-22", shorttitle= "CMO with LagF Rev NR -12-27-22", format=format.price)

//Rev NR of the CMO ATR, with LagF Filtering - Released 12-27-22
//This code takes Chande Momentum Oscillator (CMO), adds a coded ATR option and then filters the result through a Laguerre Filter (LagF) to reduce eronious signals. 
//This code also has an option for self adjusting alpha on the Lag, via a lookback table and monitoring the price rate of change (ROC) in the lookback length.
//Faster ROC will allow the LagF to move faster, slower price action will slow down LagF reaction.
//Pausing of signals is also present pased on Rate of Change of the LagF Curve
//Agressive signals and Base signaling is allowed - agressive bases signals on increase/decrease of previous LagF curve value point, Base is greather or less than 0
//Original Code credits; Lost some of this due to time and multiple script manipulations, I beleive the CMO orgin code is from @TradingView, and the LagF from @KıvançÖzbilgiç

//CMO Code 
var CMO ="Chande Momentum Oscillator (CMO) Inputs"
intval1CMO = input.string('Chart', 'CMO ATR', options=['Chart', '30S', 'M01', 'M02', 'M03', 'M04', 'M05', 'M10', 'M15', 'M30', 'M45', 'H01', 'H02', 'H03', 'H04', 'H06', 'H08', 'H12', 'Day', 'Week', 'Month', 'Year'], group=CMO )
srcType = input(close, "CMO Source", group=CMO)

//Obtain the correct Time Period for the CMO Code
getRezCMO(intvalCMO) =>
    iff_1CMO = intvalCMO == 'Year' ? '12M' : '60'
    iff_2CMO = intvalCMO == 'Month' ? 'M' : iff_1CMO
    iff_3CMO = intvalCMO == 'Week' ? 'W' : iff_2CMO
    iff_4CMO = intvalCMO == 'Day' ? 'D' : iff_3CMO
    iff_5CMO = intvalCMO == 'H12' ? '720' : iff_4CMO
    iff_6CMO = intvalCMO == 'H08' ? '480' : iff_5CMO
    iff_7CMO = intvalCMO == 'H06' ? '360' : iff_6CMO
    iff_8CMO = intvalCMO == 'H04' ? '240' : iff_7CMO
    iff_9CMO = intvalCMO == 'H03' ? '180' : iff_8CMO
    iff_10CMO = intvalCMO == 'H02' ? '120' : iff_9CMO
    iff_11CMO = intvalCMO == 'H01' ? '60' : iff_10CMO
    iff_12CMO = intvalCMO == 'M45' ? '45' : iff_11CMO
    iff_13CMO = intvalCMO == 'M30' ? '30' : iff_12CMO
    iff_14CMO = intvalCMO == 'M15' ? '15' : iff_13CMO
    iff_15CMO = intvalCMO == 'M10' ? '10' : iff_14CMO 
    iff_16CMO = intvalCMO == 'M05' ? '5' : iff_15CMO
    iff_17CMO = intvalCMO == 'M04' ? '4' : iff_16CMO 
    iff_18CMO = intvalCMO == 'M03' ? '3' : iff_17CMO
    iff_19CMO = intvalCMO == 'M02' ? '2' : iff_18CMO
    iff_20CMO = intvalCMO == 'M01' ? '1' : iff_19CMO
    iff_21CMO = intvalCMO == '30S' ? '30S' : iff_20CMO
    int_1CMO = intvalCMO == 'Chart' ? timeframe.period : iff_21CMO
    int_1CMO
 
resCMO = getRezCMO(intval1CMO) //final timeperiod obtained

//use security to get the timperiod data - non repaintcoded security
srcCMOx = request.security(syminfo.ticker, resCMO, srcType[1], gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_on)   
srcCMO = ta.tsi(srcCMOx,7,21) //DO NOT MODIFY - this TSI filters the values from ATR's to prvoide usable data for the LAGF (if you change this HTF's will look wonky)
lengthCMO = input.int(14,"CMO Length (Default = 14)",  minval=1, group=CMO) 

momm = ta.change(srcCMO)
f1(m) => m >= 0.0 ? m : 0.0
f2(m) => m >= 0.0 ? 0.0 : -m
m1 = f1(momm)
m2 = f2(momm)
sm1 = math.sum(m1, lengthCMO)
sm2 = math.sum(m2, lengthCMO)
percent(nom, div) => 100 * nom / div
chandeMO = percent(sm1-sm2, sm1+sm2)
//plot(chandeMO, "Chande MO", color=color.aqua)  //uncomment if you want the CMO plot

///////////////////////////////
///////////////////////////////

//LagF Filter Code (By @KıvançÖzbilgiç with some minor modifications by @Hockeydude84)
var lf = "Laguerre Filter (LagF) Inputs"
srcCMOL = chandeMO //Chande Momentum  is the input for the for LagF to filter for use (vs close as would be typical)
UseAG_LagF = input(true, title='Use Agressive LagF Signaling (Default = Yes) ', group=lf)
UseAC_Alpha = input(true, title='Use Auto Correcting Alpha (Default = Yes) ', group=lf)
alpha_1 = input.float(title='Alpha (For Non-Auto Correcting)', minval=0, maxval=1, step=0.1, defval=0.2, group=lf)
size_1 = 1
max_1  = 3 

var fib_1 = array.from(1,1)
var dist_1 = 0.,var avg_1 = 0.,var fib_n_1 = 1

n_1 = bar_index

if barstate.isfirst
    for i_1 = 1 to max_1
        array.push(fib_1,array.get(fib_1,i_1-1) + array.get(fib_1,i_1))

dist_1 := ta.atr(14)*size_1*array.get(fib_1,fib_n_1)

fib_n_1 := math.abs(srcCMOL-avg_1) > dist_1 ? fib_n_1+1 : fib_n_1
avg_1 := nz(fib_n_1 > max_1+1 ? srcCMOL : avg_1[1],srcCMOL)
fib_n_1 := fib_n_1 > max_1+1 ? 1 : fib_n_1


//Rate of Change (ROC)
rcF = input(14, 'For AutoCorrecting Alpha - ROC Filter Fast Length (Default=14)', group=lf)
rcS = input(100, 'For AutoCorrecting Alpha - ROC Filter Slow Length (Default=100)', group=lf)

//AutoCorrecting Gamma Code (@Hockedude84)
rise_ROC= ta.highest(close,rcF)- ta.lowest(close, rcF)
slope_ROC = (rise_ROC/rcF)
pre_normalized_ROC= math.abs(slope_ROC/(ta.highest(slope_ROC,rcS) - ta.lowest(slope_ROC,rcS))) //normalizing to "1"
noramlized_ROC = pre_normalized_ROC>1 ? 1 : pre_normalized_ROC //Due to moving target, any values above 1 get equated to 1

//Final Gamma determination
gamma_AC = noramlized_ROC //Autocorrecting Gamma (0-1 with 1 being fastes ROC)
gamma_Locked = 1 - alpha_1 //Locked Gamma (typical for LagF Code) - 1 is fastest responding, 0 would be slowest
gamma_1 = UseAC_Alpha ? gamma_AC : gamma_Locked //choose which gamma to use

//LAGF Curve Code
L0_1 = 0.0
L0_1 := (1 - gamma_1) * srcCMOL + gamma_1 * nz(L0_1[1])
L1_1 = 0.0
L1_1 := -gamma_1 * L0_1 + nz(L0_1[1]) + gamma_1 * nz(L1_1[1])

L2_1 = 0.0
L2_1:= -gamma_1 * L1_1 + nz(L1_1[1]) + gamma_1 * nz(L2_1[1])

L3_1 = 0.0
L3_1 := -gamma_1 * L2_1 + nz(L2_1[1]) + gamma_1 * nz(L3_1[1])

LagF_1 = (L0_1 + 2 * L1_1 + 2 * L2_1 + L3_1) / 6 //Final LagF Output


//Pause Code - if LagF curve isn't moving "quickly" (such as an inactive/stagnant market) - it will pause signals
UsePause = input(true, title='Enable Pause in Signals if LagF ROC is Slow (Defualt = Yes) ', group=lf)
threshold_Pause = input.float(0.3, 'Pause Value (0-1) - Default = 0.3', minval = 0, maxval=1, step = 0.1)
rise_Pause= ta.highest(LagF_1,rcF)- ta.lowest(LagF_1, rcF)
slope_Pause = (rise_Pause/rcF)
pre_normalize_Pause = math.abs(slope_Pause/(ta.highest(slope_Pause,rcS) - ta.lowest(slope_Pause,rcS))) //normalize Pause value to 1
normalized_Pause= pre_normalize_Pause>1 ? 1 : pre_normalize_Pause

//Final Pause determinations
pause = normalized_Pause > threshold_Pause ? 1: 0 // 1 enables trade, 0 inhibits
pause_Final = UsePause==true ? pause : 1

//Colarize Signals and Final Plot
Color_AG = pause_Final ==0 ? color.orange : LagF_1 > LagF_1[1] ? color.lime  : color.fuchsia //embrace the darkside with fuchsia
Color_Base = pause_Final ==0 ? color.orange : LagF_1 >0  ? color.lime  : color.fuchsia  //embrace the darkside with fuchsia
Color_Final = UseAG_LagF == true ? Color_AG : Color_Base
plot(LagF_1, title='LagF', linewidth=3, color=Color_Final) //final chart output
