Leonidas Squeeze  Momentum System
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// based on  © OskarGallard implementation 
// custom version @leonidascrypto
//@version=5

indicator(shorttitle="LSQMS", title="Leonidas Squeeze  Momentum System", overlay=false)
// Function to select the type of source
get_src(Type) =>
    if Type == "VWAP"
        ta.vwap
    else if Type == "Close"
        close
    else if Type == "Open"
        open
    else if Type == "HL2"
        hl2
    else if Type == "HLC3"
        hlc3
    else if Type == "OHLC4"
        ohlc4
    else if Type == "Volume"
        nz(volume)
    else if Type == "High"
        high
    else if Type == "Low"
        low
    else if Type == "vwap(Close)"
        ta.vwap(close)
    else if Type == "vwap(Open)"
        ta.vwap(open)
    else if Type == "vwap(High)"
        ta.vwap(high)
    else if Type == "vwap(Low)"
        ta.vwap(low)
    else if Type == "AVG(vwap(H,L))"
        math.avg(ta.vwap(high), ta.vwap(low))
    else if Type == "AVG(vwap(O,C))"
        math.avg(ta.vwap(open), ta.vwap(close))
    else if Type == "OBV" // On Balance Volume
        ta.obv
    else if Type == "AccDist" // Accumulation Distribution
        ta.accdist
    else if Type == "PVT" // Price Volume Trend
        ta.pvt
        
        
f_c_gradientAdvDecPro(_source, _center, _steps, _c_bearWeak, _c_bearStrong, _c_bullWeak, _c_bullStrong) =>
    var float _qtyAdvDec = 0.
    var float _maxSteps  = math.max(1, _steps)
    bool  _xUp     = ta.crossover(_source, _center)
    bool  _xDn     = ta.crossunder(_source, _center)
    float _chg     = ta.change(_source)
    bool  _up      = _chg > 0
    bool  _dn      = _chg < 0
    bool  _srcBull = _source > _center
    bool  _srcBear = _source < _center
    _qtyAdvDec := 
      _srcBull ? _xUp ? 1 : _up ? math.min(_maxSteps, _qtyAdvDec + 1) : _dn ? math.max(1, _qtyAdvDec - 1) : _qtyAdvDec :
      _srcBear ? _xDn ? 1 : _dn ? math.min(_maxSteps, _qtyAdvDec + 1) : _up ? math.max(1, _qtyAdvDec - 1) : _qtyAdvDec : _qtyAdvDec
    var color _return = na
    _return := 
      _srcBull ? color.from_gradient(_qtyAdvDec, 1, _maxSteps, _c_bullWeak, _c_bullStrong) : 
      _srcBear ? color.from_gradient(_qtyAdvDec, 1, _maxSteps, _c_bearWeak, _c_bearStrong) : _return

// Kaufman's Adaptive Moving Average - Fast and Slow Ends
fastK = 0.666 // KAMA Fast End
slowK = 0.645 // KAMA Slow End
kama(x, t)=>
    dist   = math.abs(x[0] - x[1])
    signal = math.abs(x - x[t])
    noise  = math.sum(dist, t)
    effr   = noise != 0 ? signal/noise : 1
    sc     = math.pow(effr*(fastK - slowK) + slowK,2)
    KAMA   = x
    KAMA  := nz(KAMA[1]) + sc*(x - nz(KAMA[1]))
    KAMA

// Jurik Moving Average of @everget
jma(src, length, power, phase) => 
    phaseRatio = phase < -100 ? 0.5 : phase > 100 ? 2.5 : phase / 100 + 1.5
    beta = 0.45 * (length - 1) / (0.45 * (length - 1) + 2)
    alpha = math.pow(beta, power)
    JMA = 0.0
    e0 = 0.0
    e0 := (1 - alpha) * src + alpha * nz(e0[1])
    e1 = 0.0
    e1 := (src - e0) * (1 - beta) + beta * nz(e1[1])
    e2 = 0.0
    e2 := (e0 + phaseRatio * e1 - nz(JMA[1])) * math.pow(1 - alpha, 2) + math.pow(alpha, 2) * nz(e2[1])
    JMA := e2 + nz(JMA[1])
    JMA

cti(sm, src, cd) =>
    di = (sm - 1.0) / 2.0 + 1.0
    c1 = 2 / (di + 1.0)
    c2 = 1 - c1
    c3 = 3.0 * (cd * cd + cd * cd * cd)
    c4 = -3.0 * (2.0 * cd * cd + cd + cd * cd * cd)
    c5 = 3.0 * cd + 1.0 + cd * cd * cd + 3.0 * cd * cd
    i1 = 0.0
    i2 = 0.0
    i3 = 0.0
    i4 = 0.0
    i5 = 0.0
    i6 = 0.0
    i1 := c1*src + c2*nz(i1[1])
    i2 := c1*i1 + c2*nz(i2[1])
    i3 := c1*i2 + c2*nz(i3[1])
    i4 := c1*i3 + c2*nz(i4[1])
    i5 := c1*i4 + c2*nz(i5[1])
    i6 := c1*i5 + c2*nz(i6[1])
        
    bfr = -cd*cd*cd*i6 + c3*(i5) + c4*(i4) + c5*(i3)
    bfr
    
a = 0.618
T3ma(src,Len) =>
    e1 = ta.ema(src, Len)
    e2 = ta.ema(e1, Len)
    e3 = ta.ema(e2, Len)
    e4 = ta.ema(e3, Len)
    e5 = ta.ema(e4, Len)
    e6 = ta.ema(e5, Len)
    C1 = -a*a*a
    C2 = 3*a*a+3*a*a*a
    C3 = -6*a*a-3*a-3*a*a*a
    C4 = 1+3*a+a*a*a+3*a*a
    C1*e6+C2*e5+C3*e4+C4*e3

VIDYA(src,Len) =>
    mom     = ta.change(src)
    upSum   = math.sum(math.max(mom, 0), Len)
    downSum = math.sum(-math.min(mom, 0), Len)
    out     = (upSum - downSum) / (upSum + downSum)
    cmo     = math.abs(out)
    alpha   = 2 / (Len + 1)
    vidya   = 0.0
    vidya   := src * alpha * cmo + nz(vidya[1]) * (1 - alpha * cmo)
    vidya

// ZLEMA: Zero Lag
zema(_src, _len) =>
    _alpha = (_len - 1) / 2
    _zlema0 = (_src + (_src - _src[_alpha]))
    _zlemaF = ta.ema(_zlema0, _len)

ma(MAType, MASource, MAPeriod) =>
    if MAPeriod > 0
        if MAType == "SMA"
            ta.sma(MASource, MAPeriod)
        else if MAType == "EMA"
            ta.ema(MASource, MAPeriod)
        else if MAType == "WMA"
            ta.wma(MASource, MAPeriod)
        else if MAType == "RMA"
            ta.rma(MASource, MAPeriod)
        else if MAType == "HMA"
            ta.hma(MASource, MAPeriod)
        else if MAType == "DEMA"
            e = ta.ema(MASource, MAPeriod)
            2 * e - ta.ema(e, MAPeriod)
        else if MAType == "TEMA"
            e = ta.ema(MASource, MAPeriod)
            3 * (e - ta.ema(e, MAPeriod)) + ta.ema(ta.ema(e, MAPeriod), MAPeriod)
        else if MAType == "VWMA"
            ta.vwma(MASource, MAPeriod)
        else if MAType == "ALMA"
            ta.alma(MASource, MAPeriod, .85, 6)
        else if MAType == "CTI"
            cti(MAPeriod, MASource, 0)
        else if MAType == "KAMA"
            kama(MASource, MAPeriod)
        else if MAType == "SWMA" 
            ta.swma(MASource)
        else if MAType == "JMA"
            jma(MASource, MAPeriod, 2, 50)
        else if MAType == "LSMA"
            ta.linreg(MASource, MAPeriod, 0) // Least Squares
        else if MAType == "Wild"
            wild = MASource
            wild := nz(wild[1]) + (MASource - nz(wild[1])) / MAPeriod
        else if MAType == "Tillson T3"
            T3ma(MASource, MAPeriod)
        else if MAType == "VIDYA"
            VIDYA(MASource, MAPeriod)
        else if MAType == "DWMA" // Double Weighted Moving Average
            ta.wma(ta.wma(MASource, MAPeriod), MAPeriod)
        else if MAType == "DVWMA" // Double Volume-Weighted Moving Average
            ta.vwma(ta.vwma(MASource, MAPeriod), MAPeriod)
        else if MAType == "Zero Lag"
            zema(MASource, MAPeriod)

// Input - Squeeze Momentum Indicator
show_Momen = input.bool(true,    "▷ Show Momentum ", inline="mom", group="Squeeze Momentum Indicator")
bgoff      = input.bool(true,    "Background Off", inline="mom", group="Squeeze Momentum Indicator")
lengthM    = input.int(20,       "MOM Length", minval=1, step=1, inline="M", group="Squeeze Momentum Indicator")
srcM       = input.source(close, "Source", inline="M", group="Squeeze Momentum Indicator")
typeMom    = input.string('ALMA', "Type", inline = "M", group="Squeeze Momentum Indicator", options=["SMA", "EMA", "WMA", "DWMA", "VWMA", "DVWMA", "HMA", "ALMA", "Wild", "JMA", "KAMA", "Zero Lag", "Tillson T3", "VIDYA", "CTI", "RMA", "DEMA", "TEMA", "SWMA"])
length     = input.int(20,       "SQZ Length",  minval=1, step=1, inline="S", group="Squeeze Momentum Indicator")
src        = input.source(ohlc4, "SQZ Source", inline="S", group="Squeeze Momentum Indicator")
bbmatype   = input.string('ALMA', "BB Calculation Type", inline = "bb", group="Squeeze Momentum Indicator", options=["SMA", "EMA", "WMA", "DWMA", "VWMA", "DVWMA", "HMA", "ALMA", "LSMA", "Wild", "JMA", "Zero Lag", "Tillson T3", "VIDYA", "KAMA", "CTI", "RMA", "DEMA", "TEMA", "SWMA"])
multBB     = input.float(2.0 ,   "BB MultFactor", step=0.25, inline = "bb", group="Squeeze Momentum Indicator") //Bollinger Bands Multiplier
kcmatype   = input.string('ALMA', "Keltner Channel Calculation Type", inline = "kc", group="Squeeze Momentum Indicator", options=["SMA", "EMA", "WMA", "DWMA", "VWMA", "DVWMA", "HMA", "ALMA", "LSMA", "Wild", "JMA", "Zero Lag", "Tillson T3", "VIDYA", "KAMA", "CTI", "RMA", "DEMA", "TEMA", "SWMA"])
useTR      = input.bool(true,    "Use TrueRange (KC)", inline = "kc", group="Squeeze Momentum Indicator")
drdiv      = input.bool(false,   "Draw Divergence", inline="l1", group="Squeeze Momentum Indicator")
zeroSQZ    = input.bool(false,   "SQZ Zero Line", inline="l1", group="Squeeze Momentum Indicator")
darkm      = input.bool(false,   "Gray Background for Dark Mode", inline="l1", group="Squeeze Momentum Indicator")

fasttrend  = input.bool(false,   "Show Fast SQ", inline="l1", group="Squeeze Momentum Indicator")
fastlen    = input.int(6,   "Fast SQ", inline="l1", group="Squeeze Momentum Indicator")


//SQ Colors
strongbullcolor = input(#00ffe7, title = "Strong Bull Color",group="Squeeze Momentum Indicator")
weakbullcolor   = input(#4000ff, title = "Weak Bull Color",group="Squeeze Momentum Indicator")
strongbearcolor = input(#ff0032, title = "Strong Bear Color",group="Squeeze Momentum Indicator")
weakbearcolor   = input(#ffff00, title = "Weak Bear Color",group="Squeeze Momentum Indicator")
fastsqcolor     = input(color.yellow, title = "Fast SQ Color",group="Squeeze Momentum Indicator")
stepn           = input(5, title = "Max Gradient Steps",group="Squeeze Momentum Indicator")

// Input - ADX and DMI
scale     = input.float(55.0,        "Scala for ADX", inline="dmi0", group="Directional Movement Index")
pos       = input.color(color.white, "Positive slope", inline="dmi0", group="Directional Movement Index") 
neg       = input.color(color.gray,  "Negative slope", inline="dmi0", group="Directional Movement Index") 
show_ADX  = input.bool(true,         "Show ADX", inline="showDMI", group="Directional Movement Index")
hideLabel = input.bool(false,        "▷ Hide DMI Label ◁", inline= "showDMI", group="Directional Movement Index")
adxlen    = input.int(14,            "ADX Smoothing", minval=1, maxval=50, group="Directional Movement Index")
dilen     = input.int(14,            "DI Length", minval=1, group="Directional Movement Index") 
keyLevel  = input.int(23,            "Key level for ADX", group="Directional Movement Index")
weakTrend = input.int(17,            "Weak Trend Theshold", group="Directional Movement Index")
histLabel = input.int(0    ,         "Historical Label Readings", minval=0, group="Directional Movement Index")
keyColor  = input.bool(false,        "KeyLevel with color DMI", inline="k_level", group="Directional Movement Index")
distance  = input.int(-5,            "Distance between KeyLevel and 0", inline="k_level", group="Directional Movement Index") 

//_________________________________________________________________________________
// Based on "Squeeze Momentum Indicator" - Author:@LazyBear and @J-Streak          
// https://www.tradingview.com/script/nqQ1DT5a-Squeeze-Momentum-Indicator-LazyBear/
// https://www.tradingview.com/script/557GijRq-JS-Squeeze-Pro-2/                   
//_________________________________________________________________________________
// Bollinger Bands Basis Line
basis = ma(bbmatype, src, length) 

// Keltner Channel Basis Line
basiskc = ma(kcmatype, src, length)
// Keltner Channel Range
range_src = useTR ? ta.tr : (high - low)
range_kc  = ma(kcmatype, range_src, length)
// Keltner Channel Low Multiplier
multlowKC = 2.0
// Keltner Channel Mid Multiplier
multmidKC = 1.5
// Keltner Channel High Multiplier
multhighKC = 1.0

// Bollinger Bands 
dev         = multBB * ta.stdev(src, length)
upperBB     = basis + dev
lowerBB     = basis - dev
//Keltner Channel Bands Low 
upperKCl    = basiskc + range_kc * multlowKC
lowerKCl    = basiskc - range_kc * multlowKC
//Keltner Channel Bands Mid
upperKCm    = basiskc + range_kc * multmidKC
lowerKCm    = basiskc - range_kc * multmidKC
//Keltner Channel Bands High
upperKCh    = basiskc + range_kc * multhighKC
lowerKCh    = basiskc - range_kc * multhighKC

//------------------------{ Squeeze Momentum Basics }------------------------------------
//Momentum
ma_momentum = ma(typeMom, srcM, lengthM)
sz = ta.linreg(srcM - math.avg(math.avg(ta.highest(high, lengthM), ta.lowest(low, lengthM)), ma_momentum), lengthM, 0)

//Momentum Conditions
sc1 = sz >= 0
sc2 = sz < 0
sc3 = sz >= sz[1]
sc4 = sz < sz[1]

//Squeeze On
lowsqz      = lowerBB > lowerKCl and upperBB < upperKCl
lsf         = lowsqz == false
midsqz      = lowerBB > lowerKCm and upperBB < upperKCm
msf         = midsqz == false
highsqz     = lowerBB > lowerKCh and upperBB < upperKCh
hsf         = highsqz == false


//-----------------{ Indicator Components and Plots }---------------------------
//Squeeze Dot Colors
orange_red     = #FF4000 // Original Squeeze 
golden_yellow  = #FFE500 // High Squeeze
sqzproc  = highsqz ? golden_yellow : midsqz ? orange_red : lowsqz ? color.gray : na

fastsq= ta.ema(sz,fastlen)

//Plot Zero Line
color_zero = color.gray
plot(zeroSQZ ? 0 : na, title="Squeeze Zero Line", color=color_zero, linewidth=2, style=plot.style_circles)


//Squeeze Plot
col = f_c_gradientAdvDecPro(sz, 0, stepn , weakbearcolor, strongbearcolor, weakbullcolor,strongbullcolor ) 

plot(show_Momen ? sz : na, title="Squeeze Momentum", color=col, style=plot.style_area)

plot(fasttrend?fastsq: na,title="Fast SQ",color=fastsqcolor,style=plot.style_circles)

//Background Conditions
bg1_dark = color.new(color.gray, 95)
bg2_dark = color.new(#673AB7, 95)
bg3_dark = color.new(color.gray, 95)
bg4_dark = color.new(#FFD600, 95)
bg5_dark = color.new(#CE93D8, 95)


clr1_bg        = sc1 and sc3 ? color.new(#00EEFF, 80) : 
   sc1 and sc4 ? color.new(#000EFF, 80) : sc2 and sc4 ? color.new(#FF0000, 80) : sc2 and sc3 ? color.new(#FFE500, 80) : color.new(color.gray, 80)
clr2_bg        = sc1 and sc3 ? color.new(#00bcd4, 80) : 
   sc1 and sc4 ? color.new(#0D47A1, 80) : sc2 and sc4 ? color.new(#BA68C8, 80) : sc2 and sc3 ? color.new(#9C27B0, 80) : color.new(#673AB7, 80)
clr3_bg        = sc1 and sc3 ? color.new(#15FF00, 80) : sc1 and sc4 ? color.new(#388E3C, 80) : 
   sc2 and sc4 ? color.new(#F44336, 80) : sc2 and sc3 ? color.new(#B71C1C, 80) : color.new(color.gray, 80)
clr4_bg        = sc1 and sc3 ? color.new(#fff59d, 80) : 
   sc1 and sc4 ? color.new(#FFD600, 80) : sc2 and sc4 ? color.new(#FFCC80, 80) : sc2 and sc3 ? color.new(#FF9800, 80) : color.new(#702700, 80)
clr5_bg        = sc1 and sc3 ? color.new(#2196F3, 80) : 
   sc1 and sc4 ? color.new(#0D47A1, 80) : sc2 and sc4 ? color.new(#EF9A9A, 80) : sc2 and sc3 ? color.new(#D32F2F, 80) : color.new(#CE93D8, 80)



//Divergence Formula {Compliments of Ricardo Santos}
ftf(_src) =>
    _src[4] < _src[2] and _src[3] < _src[2] and _src[2] > _src[1] and 
       _src[2] > _src[0]
fbf(_src) =>
    _src[4] > _src[2] and _src[3] > _src[2] and _src[2] < _src[1] and 
       _src[2] < _src[0]
ffract(_src) =>
    fbf__1 = fbf(_src)
    ftf(_src) ? 1 : fbf__1 ? -1 : 0
fractaltop  = ffract(sz) > 0 ? sz[2] : na
fractalbot  = ffract(sz) < 0 ? sz[2] : na
high_prev   = ta.valuewhen(fractaltop, sz[2], 1)
high_price  = ta.valuewhen(fractaltop, high[2], 1)
low_prev    = ta.valuewhen(fractalbot, sz[2], 1)
low_price   = ta.valuewhen(fractalbot, low[2], 1)
regbeardiv  = fractaltop and high[2] > high_price and sz[2] < high_prev
hidbeardiv  = fractaltop and high[2] < high_price and sz[2] > high_prev
regbulldiv  = fractalbot and low[2] < low_price and sz[2] > low_prev
hidbulldiv  = fractalbot and low[2] > low_price and sz[2] < low_prev



//Divergence Plot
plot(drdiv ? fractaltop ? sz[2] : na : na, 'Bearish Fractal', color=regbeardiv ? color.new(color.orange,1) : na, linewidth=2, offset=-2, editable=false)
plot(drdiv ? fractalbot ? sz[2] : na : na, 'Bullish Fractal', color=regbulldiv ? color.new(color.blue,1) : na, linewidth=2, offset=-2, editable=false)
plot(drdiv ? fractaltop ? sz[2] : na : na, 'Bearish Divergence', style=plot.style_circles, color=regbeardiv ? color.new(color.orange,1) : na, linewidth=3, offset=-2, editable=false)
plot(drdiv ? fractalbot ? sz[2] : na : na, 'Bullish Divergence', style=plot.style_circles, color=regbulldiv ? color.new(color.blue,1) : na, linewidth=3, offset=-2, editable=false)

//______________________________________________________________________________
// Based on "Directional Movement Index and ADX"
// https://www.tradingview.com/script/VroqhJmg/
//______________________________________________________________________________
[diplus, diminus, adxValue] = ta.dmi(dilen, adxlen)

biggest(series) =>
    max = 0.0
    max := nz(max[1], series)
    if series > max
        max := series
    max

// Calculate ADX Scale
ni = biggest(sz)
adx_scale = (adxValue - keyLevel + distance) * ni/scale

dmiBull = diplus   >= diminus     and adxValue >= keyLevel
dmiBear = diplus   <  diminus     and adxValue >= keyLevel
dmiWeak = adxValue <  keyLevel and adxValue >  weakTrend

dmiColor = dmiBull ? (adxValue > adxValue[1] ? #006400     : color.green) : 
           dmiBear ? (adxValue > adxValue[1] ? #910000     : color.red  ) : 
           dmiWeak ? (adxValue > adxValue[1] ? color.black : color.gray ) : 
           (adxValue > adxValue[1] ? #DAA80A : #FFC40C)  
 
color_ADX  = adxValue > adxValue[1] ? pos : neg
plot(show_ADX ? adx_scale : na, color = color_ADX, title = "ADX", linewidth = 2)
plot(zeroSQZ ? na : (show_ADX ? distance* ni/scale : na), color = keyColor ? dmiColor : color_ADX, title = "Key Level", linewidth = 1, style = plot.style_line)








 