Utility
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © derekren321

//@version=5
library("Utility", true)
import TradingView/ta/5

// Smoothed moving average
export smma(series float src, simple int length) =>
    smma = 0.0
    sma = ta.sma(src, length)
    smma := na(smma[1]) ? sma : (smma[1] * (length - 1) + src) / length
    smma

export ema(series float src, simple int length) =>
    ta.ema(src, length)

export dema(series float src, simple int length) =>
    e1 = ta.ema(src, length)
    e2 = ta.ema(e1, length)
    dema = 2 * e1 - e2

export tema(series float src, simple int length) =>
    e1 = ta.ema(src, length)
    e2 = ta.ema(e1, length)
    e3 = ta.ema(e2, length)
    tema = 3 * (e1 - e2) + e3

export t3(series float src = close, simple int length = 10) =>
    axe1 = ta.ema(src, length)
    axe2 = ta.ema(axe1, length)
    axe3 = ta.ema(axe2, length)
    axe4 = ta.ema(axe3, length)
    axe5 = ta.ema(axe4, length)
    axe6 = ta.ema(axe5, length)
    ab = 0.7
    ac1 = -ab*ab*ab
    ac2 = 3*ab*ab+3*ab*ab*ab
    ac3 = -6*ab*ab-3*ab-3*ab*ab*ab
    ac4 = 1+3*ab+ab*ab*ab+3*ab*ab
    maPrice = ac1 * axe6 + ac2 * axe5 + ac3 * axe4 + ac4 * axe3

export hma(series float src, simple int length) =>
    ta.wma(2 * ta.wma(src, length / 2) - ta.wma(src, length), math.round(math.sqrt(length)))

// https://en.wikipedia.org/wiki/Zero_lag_exponential_moving_average
export zlema(series float src, simple int length) =>
    lag = math.ceil((length - 1) / 2)
    emaData = src + (src - src[lag])
    zl = ta.ema(emaData, length)

// zlema definition from impulseMACD from Lazybear
export zlema2(series float src, simple int length) =>
	e1 = ta.ema(src, length)
	e2 = ta.ema(e1, length)
	diff = e1 - e2
	e1 + diff

//Kijun-sen
export KijunSen(series float src, simple int length) =>
    kijun = math.avg(ta.lowest(src, length), ta.highest(src, length))
    kijun
    
export McGinley(series float src, simple int length) =>
    mg = 0.0
    ema = ta.ema(src, length)
    mg := na(mg[1]) ? ema : mg[1] + (src - mg[1]) / (length * math.pow(src/mg[1], 4))
    mg

export stochRSI(series float src, simple int lengthRSI = 10, simple int lengthStoch = 10, simple int smoothK = 3, simple int smoothD = 3) =>
    rsi1 = ta.rsi(src, lengthRSI)
    k = ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
    d = ta.sma(k, smoothD)
    [k, d]

export slope(series float src, simple int length) =>
    (src - src[length]) / length

// Monte Carlo Simulation Drift
// https://www.investopedia.com/terms/m/montecarlosimulation.asp
export drift(series float src, simple int length) =>
    pc = math.log(src / src[1])
    variance = ta.variance(pc, length)
    drift = ta.sma(pc, length) - variance / 2
    drift

// Impulse MACD
export impulseMACD(series float src = hlc3, simple int lengthSlowMA = 34, simple int lengthFastMA = 34, simple int lengthDEM = 9, simple float addThreshold = 0.0) =>
    upper = (1 + addThreshold) * smma(high, lengthSlowMA)
    lower = (1 - addThreshold) * smma(low, lengthSlowMA)
    mid = zlema2(src, lengthFastMA)
    diff = (mid > upper) ? (mid - upper) : (mid < lower) ? (mid - lower) : 0
    dem = ta.sma(diff, lengthDEM)
    macd = 2 * (diff - dem)
    [diff, dem, macd]

// SuperTrend with custom input
// -1 for uptrend, +1 for downtrend
export superTrend(series float src = hl2, simple int atrPeriod = 10, simple float atrMultiplier = 3.0) =>
    atr = ta.atr(atrPeriod)
    upperBand = src + atrMultiplier * atr
    lowerBand = src - atrMultiplier * atr
    prevLowerBand = nz(lowerBand[1])
    prevUpperBand = nz(upperBand[1])

    lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
    upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
    int direction = na
    float superTrend = na
    prevSuperTrend = superTrend[1]
    if na(atr[1])
        direction := 1
    else if prevSuperTrend == prevUpperBand
        direction := close > upperBand ? -1 : 1
    else
        direction := close < lowerBand ? 1 : -1
    superTrend := direction == -1 ? lowerBand : upperBand
    [superTrend, direction]

// Sigmoid activation function
export sigmoid(series float x) => 
    1 / (1 + math.exp(-x))

// Zero centered sigmoid, range from [-1, 1]
export zcsigmoid(series float x) =>
    2 * (sigmoid(x) - 0.5)

// Tanh, range from [-1, 1]
export tanh(series float x) =>
    (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))

// Normalizes series with unknown min/max using historical min/max.
// src: series to rescale.
// min, max: min/max values of rescaled series.
// length: length of previous data points to find normalize the data from.
export normalize(series float src, simple float min = -1, simple float max = 1, simple int length = na) =>
    var historicMin = 10e10
    var historicMax = -10e10
    // length not specified, find all time min/max
    if na(length)
        historicMin := math.min(nz(src, historicMin), historicMin)
        historicMax := math.max(nz(src, historicMax), historicMax)
    else
        historicMin := ta.lowest(src, length)
        historicMax := ta.highest(src, length)
    min + (max - min) * (src - historicMin) / math.max(historicMax - historicMin, 10e-10)

// Calculate the normal distribution curve using mean and std.
export normalDistribution(series float src, simple float mean, simple float std) =>
    a1 = 1 / (std * math.sqrt(2 * math.pi))
    a2 = math.exp(-0.5 * math.pow((src - mean) / std, 2))
    a1 * a2

plot(smma(KijunSen(close, 10),10), color = color.yellow)
plot(McGinley(close, 10))
