Worm *Public*
// This Source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// ©aidenhawkins2004

//@version=5
indicator("Worm (Clean)" , overlay = true)

//__ Inputs

    //Titles

SettingTitle1       = "Indicator Settings"                       , SettingTitle2       = "Backtest Settings"                        , SettingTitle3     = "Color Settings"
IntegerTitle1       = "Alpha"                                    , IntegerTitle2       = "Gap between indicator and current price"  , IntegerTitle3     = "Gap between price and Indicator"
Color1              = "Buy Color"                                , Color2              = "Sell Color"                               , Color3            = "Wait Color"
Color1Tooltip       = "Default Green"                            , Color2Tooltip       = "Default Red"                              , Color3Tooltip     = "Default Yellow"
AlertTitle1         = "Red Worm"                                 , AlertTitle2         = "Green Worm"                               , AlertTitle3       = "Yellow Zig Zag"

Location1           = "Momentum Indicator display above price?"  , LocationTooltip1    = "On higher timeframes, this will revert to tracking the price."
Location2           = "Momentum Indicator displays below price?" , LocationTooltip2    = "On higher timeframes, this will revert to tracking the price. Is the default option."  
Location3           = "Momentum Indicator displays at price?"    , LocationTooltip3    = "Other options revert to this by default on higher timeframes."

IndicatorTitle1     = "Trailing Momentum"                        , IndicatorTitle2     = "Wiggly Worm"


    //Toggleable Inputs

Above_price         = input.bool   (defval = false               ,  title = Location1     , group = SettingTitle1       , tooltip = LocationTooltip1           , confirm = true)
Below_price         = input.bool   (defval = true                ,  title = Location2     , group = SettingTitle1       , tooltip = LocationTooltip2           , confirm = true)
At_price            = input.bool   (defval = false               ,  title = Location3     , group = SettingTitle1       , tooltip = LocationTooltip3           , confirm = true)

Buy_Color           = input.color  (defval = color.green       ,  title = Color1        , group = SettingTitle3       , display    = display.all             , confirm = true)
Sell_Color          = input.color  (defval = color.red         ,  title = Color2        , group = SettingTitle3       , display    = display.all             , confirm = true)
Wait_Color          = input.color  (defval = color.yellow      ,  title = Color3        , group = SettingTitle3       , display    = display.all             , confirm = true)

AlphaLine           = input.float  (defval = 0.10                ,  title = IntegerTitle1 , minval = 0  , maxval  = 100 , step = 0.1 ,   group = SettingTitle1 , confirm = true)
Gap                 = input.float  (defval = 1.05                ,  title = IntegerTitle3 , minval = 1  , maxval  = 100 , step = 0.1 ,   group = SettingTitle1 , confirm = true)



    //Bool Inputs & Source

HighlightCrossovers = true , ApplyNorm  = true      , ColorChange = true
Tru                 = true , Src        = close     , SourceLine  = hl2


    //Indicator Values

Length              = 20   , LengthKC   = 20        , MulIntegerTitle1    = 2.0   , MultKC      = 1.5 

L0Line              = 0.0  , L0         = 0.0       , L1Line              = 0.0   , L1          = 0.0

L2Line              = 0.0  , L2         = 0.0       , L3Line              = 0.0   , L3          = 0.0

CU                  = 0.0  , CD         = 0.0       , Half_Price          = 0.0 

//*************************\\


//__ Momentum Calculations

HC                  =  math.max(high , nz(close[1]))                , OC                 =  (open + nz(close[1])) / 2
LC                  =  math.min(low  , nz(close[1]))                , Gamma              =  1 - AlphaLine             

L0                  := (1 - Gamma) * SourceLine + Gamma * nz(L0[1]) , L1                 := -Gamma * L0 + nz(L0[1])  + Gamma * nz(L1[1])
L2                  := -Gamma * L1 + nz(L1[1])  + Gamma * nz(L2[1]) , L3                 := -Gamma * L2 + nz(L2[1])  + Gamma * nz(L3[1])

lrsi                =  (L0 + 2 * L1 + 2 * L2 + L3) / 6

CU                  := (L0 >= L1 ? L0 - L1 : 0 ) + (L1 >= L2 ? L1 - L2 : 0 ) + (L2 >= L3 ? L2 - L3 : 0 )
CD                  := (L0 >= L1 ? 0  : L1 - L0) + (L1 >= L2 ? 0  : L2 - L1) + (L2 >= L3 ? 0  : L3 - L2)

lrsi                := CU + CD != 0 ? ApplyNorm  ? 100 * CU / (CU + CD) : CU / (CU + CD) : 0
mult                =  ApplyNorm                 ? 100 : 1

ob                  =  0.75 * mult
middle              =  0.5  * mult
os                  =  0.25 * mult


//*************************\\


//__ Calculate BB

Source              = close           , Basis    = ta.sma (Source, Length) , Dev  = MultKC * ta.stdev(Source, Length)
UpperBB             = Basis  + Dev    , LowerBB  = Basis  - Dev


//*************************\\


//__ Calculate KC

Range_1             = Tru     ? ta.tr   : high - low , Ma       = ta.sma  (Source , LengthKC) , Rangema = ta.sma  (Range_1  , LengthKC)

UpperKC             = Ma      + Rangema * MultKC     , LowerKC  = Ma - Rangema * MultKC

SqzOn               = LowerBB > LowerKC and UpperBB < UpperKC
SqzOff              = LowerBB < LowerKC and UpperBB > UpperKC

NoSqz               = SqzOn   == false  and SqzOff == false


Val                 = ta.linreg  (Source - math.avg(math.avg(ta.highest(high, LengthKC), ta.lowest(low, LengthKC)), ta.sma(close, LengthKC)), LengthKC, 0)
Buy                 = Val        > 0  and ta.barssince(ta.crossover(lrsi, os)) < ta.barssince(ta.crossunder(lrsi, ob)) 

Iff_1               = Val        > nz(Val[1])   ? Buy_Color  : Wait_Color
Iff_2               = Val        < nz(Val[1])   ? Sell_Color : Wait_Color

Bcolor              = Val        > 0            ? Iff_1      : Iff_2
Scolor              = NoSqz      ? color.blue : Buy        ? Buy_Color : Sell_Color

L0Line              := (1-Gamma) * SourceLine   + Gamma                 * nz(L0Line[1])
L1Line              := -Gamma    * L0Line       + nz(L0Line[1]) + Gamma * nz(L1Line[1])
L2Line              := -Gamma    * L1Line       + nz(L1Line[1]) + Gamma * nz(L2Line[1])
L3Line              := -Gamma    * L2Line       + nz(L2Line[1]) + Gamma * nz(L3Line[1])

LagF                =  (L0Line   + 2            * L1Line        + 2     * L2Line + L3Line) / 6


//*************************\\


//__ Control colour

Color               = ColorChange ? (LagF > LagF[1] ? Buy_Color : Sell_Color) : Wait_Color
Ycol                = 10

if close > close[1] 
    Ycol := Ycol + 1

if close < close[1]
    Ycol := Ycol - 1


//*************************\\


//__ Red -->> Green

var line  LowestRedLine           = na , var line  HighestGreenLine        = na
var float LowestRedPrice          = na , var float HighestGreenPrice       = na

if Color                          == Sell_Color
    LowestRedPrice                := math.min(LowestRedPrice      , low)
    line.set_xy1                             (LowestRedLine       , bar_index[1]   , LowestRedPrice   )
    line.set_xy2                             (LowestRedLine       , bar_index      , LowestRedPrice   )

if Color                          == Buy_Color
    HighestGreenPrice             := math.max(HighestGreenPrice   , high)
    line.set_xy1                             (HighestGreenLine    , bar_index[1]   , HighestGreenPrice)
    line.set_xy2                             (HighestGreenLine    , bar_index      , HighestGreenPrice)


//_Location for Wave Line (above / below price)

if  Above_price == true
    Half_Price  := close * Gap

if  Below_price == true
    Half_Price  := close / Gap

if  At_price    == true
    Half_Price  := 0.0

//__ Plot Wave Line


plot(Val + Half_Price, title=IndicatorTitle1, color=Bcolor, style=plot.style_stepline, linewidth=4, display = display.all)

//__ Plot Worm

plot(LagF, title=IndicatorTitle2, linewidth=1, color=color.from_gradient(close, low, high, color.new(Color, Ycol), color.new(Color, Ycol)), style=plot.style_stepline, display = display.all)

alertcondition  (Color  == Sell_Color , title = AlertTitle1, message = AlertTitle1)
alertcondition  (Color  == Buy_Color  , title = AlertTitle2, message = AlertTitle2)
alertcondition  (Bcolor == Wait_Color , title = AlertTitle3, message = AlertTitle3)


//*************************\\..........// EXPERIMENT SECTION \\..........//*************************\\



//*************************\\

