Pips-Stepped, OMA-Filtered, Ocean NMA [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("Pips-Stepped, OMA-Filtered, Ocean NMA [Loxx]",
     shorttitle='STDSOMAFONMA [Loxx]', 
     overlay = true, 
     timeframe="", 
     timeframe_gaps = true)
     
import loxx/loxxexpandedsourcetypes/3

greencolor = #2DD204
redcolor = #D2042D 

_declen()=>
    mtckstr = str.tostring(syminfo.mintick)
    da = str.split(mtckstr, ".")
    temp = array.size(da) 
    dlen = 0.
    if syminfo.mintick < 1
        dstr = array.get(da, 1) 
        dlen := str.length(dstr)
    dlen

_filt(src, len, filter)=>
    price = src
    filtdev = filter * ta.stdev(src, len)
    price := math.abs(price - price[1]) < filtdev ? price[1] : price
    price

_oma(src, len, const, adapt) =>
    e1 = nz(src[1]), e2 = nz(src[1]), e3 = nz(src[1])
    e4 = nz(src[1]), e5 = nz(src[1]), e6 = nz(src[1])
    
    averagePeriod = len
    noise = 0.00000000001
    minPeriod = averagePeriod/2.0
    maxPeriod = minPeriod*5.0
    endPeriod = math.ceil(maxPeriod)
    signal = math.abs(src - nz(src[endPeriod]))
    
    if adapt
        for k = 1 to endPeriod
            noise += math.abs(src - nz(src[k]))
        averagePeriod := math.ceil(((signal / noise) * (maxPeriod - minPeriod)) + minPeriod)
    
    //calc jurik momentum
    alpha = (2.0 + const) / (1.0 + const + averagePeriod)
    
    e1 := nz(e1[1] + alpha * (src - e1[1]), src)
    e2 := nz(e2[1] + alpha * (e1 - e2[1]), e1)
    v1 = 1.5 * e1 - 0.5 * e2
    
    e3 := nz(e3[1] + alpha * (v1 - e3[1]), v1)
    e4 := nz(e4[1] + alpha * (e3 - e4[1]), e3)
    v2 = 1.5 * e3 - 0.5 * e4
    
    e5 := nz(e5[1] + alpha * (v2 - e5[1]), v2) 
    e6 := nz(e6[1] + alpha * (e5 - e6[1]), e5) 
    v3 = 1.5 * e5 - 0.5 * e6
    v3
    
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)"])
     
namper = input.int(40, "NMA Period", minval=1, group = "Basic Settings")

len = input.int(10, "Average Period", minval = 1, group = "Basic Settings")
const = input.float(-0.5, "Speed", step = .01, group = "Basic Settings")
adapt = input.bool(true, "Make it adaptive?", group = "Basic Settings")
steps = input.float(25.0, "Steps in Pips", group = "Pips Filter Settings")

colorbars = input.bool(true, "Color bars?", group= "UI Options")
showSigs = input.bool(true, "Show signals?", group= "UI Options")
flat = input.bool(true, "Flat-level colroing?", 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)

src = 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
	
maout = _oma(src, len, const, adapt)
mom = maout - nz(maout[1])

momRatio = 0., sumMomen = 0., ratio    = 0.
for k = 0 to namper - 1
    sumMomen += math.abs(nz(mom[k]))
    momRatio += nz(mom[k]) * (math.sqrt(k + 1) - math.sqrt(k))

ratio := sumMomen != 0 ? math.abs(momRatio)/sumMomen : ratio

nma = 0.
nma := nz(nma[1]) + ratio * (src - nz(nma[1]))

val = 0.
_stepSize = (steps > 0 ? steps : 0) * syminfo.mintick * math.pow(10, _declen() % 2)

if (_stepSize > 0) 
    _diff = nma - nz(val[1])
    val := nz(val[1]) + ((_diff < _stepSize and _diff > -_stepSize) ? 0 : int(_diff / _stepSize) * _stepSize)
else 
    val := (_stepSize > 0) ? math.round(nma / _stepSize) * _stepSize : nma

colorout = val > val[1] ? greencolor : val < val[1] ? redcolor : color.gray

goLong_pre = ta.crossover(val, val[1])
goShort_pre = ta.crossunder(val, val[1])

contSwitch = 0
contSwitch := nz(contSwitch[1])
contSwitch := goLong_pre ? 1 : goShort_pre ? -1 : contSwitch

goLong = goLong_pre and ta.change(contSwitch)
goShort = goShort_pre and ta.change(contSwitch)

plot(val,"Pips-Stepped, OMA-Filtered, Ocean NMA", color = flat ? colorout : (contSwitch == 1  ? greencolor : redcolor), linewidth = 3)

barcolor(colorbars ? contSwitch == 1 ? greencolor : redcolor : na)

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

alertcondition(goLong, title="Long", message="Pips-Stepped, OMA-Filtered, Ocean NMA [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Pips-Stepped, OMA-Filtered, Ocean NMA [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")



