Natural Market Mirror (NMM) and NMAs w/ Dynamic Zones [Loxx]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © loxx

//@version=5
indicator("Natural Market Mirror (NMM) and NMAs w/ Dynamic Zones [Loxx]", 
     shorttitle='NMMNMADZ [Loxx]', 
     overlay = false, 
     timeframe="", 
     timeframe_gaps = true)
    
import loxx/loxxdynamiczone/3
import loxx/loxxexpandedsourcetypes/4

greencolor = #2DD204
redcolor = #D2042D

SM02 = 'Slope'
SM03 = 'Middle Crossover'
SM04 = 'Levels Crossover'

twopoless(float src, int len)=>
    a1 = 0., b1 = 0.
    coef1 = 0., coef2 = 0., coef3 = 0.
    filt = 0., trig = 0.
    a1 := math.exp(-1.414 * math.pi / len)
    b1 := 2 * a1 * math.cos(1.414 * math.pi / len)
    coef2 := b1
    coef3 := -a1 * a1
    coef1 := 1 - coef2 - coef3
    filt := coef1 * src + coef2 * nz(filt[1]) + coef3 * nz(filt[2])
    filt := bar_index < 3 ? src : filt
    trig := nz(filt[1])
    filt
    
_nnmfunc(float src, int per)=>
    float sum = 0.0
    for i = 1 to per 
        sum += (src - nz(src[i])) / math.sqrt(i)
    out = ((sum / per) * 1000.0)
    out

_nmfper(float src, int per, int minPeriod, int smthper)=>
    int maxlb = 0
    float maxmomen = 0.0
    float currPrice = twopoless(src, smthper)
    for i = 1 to per 
        tmom = math.abs((src - nz(src[i])) / math.sqrt(i))
        if (tmom > maxmomen)
            maxmomen := tmom
            maxlb := i
    out = (math.max(maxlb, minPeriod))
    out

_nmaratio(float src, int per, float iMom)=>
    float momRatio = 0.0
    float sumMomen = 0.0
    float ratio = 0.0
    for k = 1 to per 
        sumMomen += math.abs(nz(iMom[k]))
        momRatio += nz(iMom[k]) * (math.sqrt(k + 1) - math.sqrt(k))
    ratio := sumMomen != 0 ? math.abs(momRatio) / sumMomen : ratio
    ratio
    
smthtype = input.string("Kaufman", "Heikin-Ashi Better Caculation Type", options = ["AMA", "T3", "Kaufman"], group = "Basic Settings")

srcin = input.string("Close", "Source", group= "Basic Settings", 
     options = 
     ["Close", "Open", "High", "Low", "Median", "Typical", "Weighted", "Average", "Average Median Body", "Trend Biased", "Trend Biased (Extreme)", 
     "HA Close", "HA Open", "HA High", "HA Low", "HA Median", "HA Typical", "HA Weighted", "HA Average", "HA Average Median Body", "HA Trend Biased", "HA Trend Biased (Extreme)",
     "HAB Close", "HAB Open", "HAB High", "HAB Low", "HAB Median", "HAB Typical", "HAB Weighted", "HAB Average", "HAB Average Median Body", "HAB Trend Biased", "HAB Trend Biased (Extreme)"])

nmmper = input.int(40, "NMM Period", group = "Basic Settings")
nnmsmthper = input.int(1, "NMM Pre-smoothing, 2-Pole Super Smother Period", group = "Basic Settings")
ssmthper = input.int(10, "NMF 2-Pole Super Smother Period", group = "Basic Settings")
zone = input.string("NMM", "Core Output Source", options = ["NMF", "NMM", "NMA"], group = "Basic Settings")

dzper = input.int(70, "Dynamic Zone Period", group = "Levels Settings")
buyprob  = input.float(0.1, "Dynamic Zone Buy Probability Level", group = "Levels Settings")
sellprob = input.float(0.1, "Dynamic Zone Sell Probability Level", group = "Levels Settings")

sigtype = input.string(SM03, "Signal type", options = [SM02, SM03, SM04], group = "Signal Settings")

colorbars = input.bool(false, "Color bars?", group = "UI Options")
showsignals = input.bool(false, "Show signals?", group = "UI Options")

kfl=input.float(0.666, title="* Kaufman's Adaptive MA (KAMA) Only - Fast End", group = "Moving Average Inputs")
ksl=input.float(0.0645, title="* Kaufman's Adaptive MA (KAMA) Only - Slow End", group = "Moving Average Inputs")
amafl = input.int(2, title="* Adaptive Moving Average (AMA) Only - Fast", group = "Moving Average Inputs")
amasl = input.int(30, title="* Adaptive Moving Average (AMA) Only - Slow", group = "Moving Average Inputs")

haclose = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, close)
haopen = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, open)
hahigh = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, high)
halow = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, low)
hamedian = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hl2)
hatypical = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hlc3)
haweighted = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, hlcc4)
haaverage = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, ohlc4)

srcout = switch srcin
	"Close" => loxxexpandedsourcetypes.rclose()
	"Open" => loxxexpandedsourcetypes.ropen()
	"High" => loxxexpandedsourcetypes.rhigh()
	"Low" => loxxexpandedsourcetypes.rlow()
	"Median" => loxxexpandedsourcetypes.rmedian()
	"Typical" => loxxexpandedsourcetypes.rtypical()
	"Weighted" => loxxexpandedsourcetypes.rweighted()
	"Average" => loxxexpandedsourcetypes.raverage()
    "Average Median Body" => loxxexpandedsourcetypes.ravemedbody()
	"Trend Biased" => loxxexpandedsourcetypes.rtrendb()
	"Trend Biased (Extreme)" => loxxexpandedsourcetypes.rtrendbext()
	"HA Close" => loxxexpandedsourcetypes.haclose(haclose)
	"HA Open" => loxxexpandedsourcetypes.haopen(haopen)
	"HA High" => loxxexpandedsourcetypes.hahigh(hahigh)
	"HA Low" => loxxexpandedsourcetypes.halow(halow)
	"HA Median" => loxxexpandedsourcetypes.hamedian(hamedian)
	"HA Typical" => loxxexpandedsourcetypes.hatypical(hatypical)
	"HA Weighted" => loxxexpandedsourcetypes.haweighted(haweighted)
	"HA Average" => loxxexpandedsourcetypes.haaverage(haaverage)
    "HA Average Median Body" => loxxexpandedsourcetypes.haavemedbody(haclose, haopen)
	"HA Trend Biased" => loxxexpandedsourcetypes.hatrendb(haclose, haopen, hahigh, halow)
	"HA Trend Biased (Extreme)" => loxxexpandedsourcetypes.hatrendbext(haclose, haopen, hahigh, halow)
	"HAB Close" => loxxexpandedsourcetypes.habclose(smthtype, amafl, amasl, kfl, ksl)
	"HAB Open" => loxxexpandedsourcetypes.habopen(smthtype, amafl, amasl, kfl, ksl)
	"HAB High" => loxxexpandedsourcetypes.habhigh(smthtype, amafl, amasl, kfl, ksl)
	"HAB Low" => loxxexpandedsourcetypes.hablow(smthtype, amafl, amasl, kfl, ksl)
	"HAB Median" => loxxexpandedsourcetypes.habmedian(smthtype, amafl, amasl, kfl, ksl)
	"HAB Typical" => loxxexpandedsourcetypes.habtypical(smthtype, amafl, amasl, kfl, ksl)
	"HAB Weighted" => loxxexpandedsourcetypes.habweighted(smthtype, amafl, amasl, kfl, ksl)
	"HAB Average" => loxxexpandedsourcetypes.habaverage(smthtype, amafl, amasl, kfl, ksl)
    "HAB Average Median Body" => loxxexpandedsourcetypes.habavemedbody(smthtype, amafl, amasl, kfl, ksl)
	"HAB Trend Biased" => loxxexpandedsourcetypes.habtrendb(smthtype, amafl, amasl, kfl, ksl)
	"HAB Trend Biased (Extreme)" => loxxexpandedsourcetypes.habtrendbext(smthtype, amafl, amasl, kfl, ksl)
	=> haclose
	
src = math.log(srcout)
nmm = _nnmfunc(twopoless(src, nnmsmthper), nmmper)

oneFifth = math.max(math.round(nmmper/5) ,1)
iMom = nmm - nz(nmm[1])

nma = 0., nmf = 0.

nma := nz(nma[1]) + _nmaratio(src, nmmper, iMom) * (nmm - nz(nma[1]))
nmf := nz(nmf[1]) + _nmaratio(src, _nmfper(src, 1, oneFifth, ssmthper), iMom) * (nmm - nz(nmf[1]))

out = zone == "NMM" ? nmm : zone == "NMF" ? nmf : nma

bli = loxxdynamiczone.dZone("buy", out, buyprob,  dzper)
sli = loxxdynamiczone.dZone("sell", out, sellprob,  dzper)
zli = loxxdynamiczone.dZone("sell", out, 0.5,  dzper)
sig = out[1]

state = 0.
if sigtype == SM02
    if (out < sig) 
        state :=-1
    if (out > sig) 
        state := 1
else if sigtype == SM03
    if (out < zli) 
        state :=-1
    if (out > zli)
        state := 1
else if sigtype == SM04
    if (out < bli) 
        state :=-1
    if (out > sli)
        state := 1
     
lwnmm = zone == "NMM" ? 4 : 1  
lwnmf = zone == "NMF" ? 4 : 1  
lwnma = zone == "NMA" ? 4 : 1  

colorout = state == -1 ? redcolor : state == 1 ? greencolor : color.gray

plot(nmm, "Natural Market Mirror", color = zone == "NMM" ? colorout : color.white, linewidth = lwnmm)
plot(nmf, "Natrual Moving Average Fast", color = bar_index % 2 ? zone == "NMF" ? colorout : color.white : na, linewidth = lwnmf)
plot(nma, "Natural Moving Averge Regular", color = bar_index % 4 ? zone == "NMA" ? colorout : color.yellow : na, linewidth = lwnma)

plot(bli, color = greencolor)
plot(sli, color = redcolor)
plot(zli, color = color.white)

barcolor(colorbars ? colorout : na)

goLong = sigtype == SM02 ? ta.crossover(out, sig) : sigtype == SM03 ? ta.crossover(out, zli) : ta.crossover(out, sli)
goShort = sigtype == SM02 ? ta.crossunder(out, sig) : sigtype == SM03 ? ta.crossunder(out, zli) :  ta.crossunder(out, bli)

plotshape(goLong and showsignals, title = "Long", color = color.yellow, textcolor = color.yellow, text = "L", style = shape.triangleup, location = location.bottom, size = size.tiny)
plotshape(goShort and showsignals, title = "Short", color = color.fuchsia, textcolor = color.fuchsia, text = "S", style = shape.triangledown, location = location.top, size = size.tiny)

alertcondition(goLong, title="Long", message="Natural Market Mirror {NMM) and NMAs w/ Dynamic Zones [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Natural Market Mirror {NMM) and NMAs w/ Dynamic Zones [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")




