J_TPO Velocity Variation
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ThiagoSchmitz

//@version=5
indicator("J_TPO Velocity Variation", "J_TPO", precision=5)
int length          = input.int(40, "Length", inline="core")
int emaLength       = input.int(200, "EMA Length", inline="core")
float src           = input.source(close, "Source", inline="core")
bool colorbars      = input.bool(true, "Color Bars", inline="display", group="Display")
bool showFirstCross = input.bool(true, "Kicking Middle Cross", inline="display", group="Display")
bool showCross      = input.bool(true, "Middle Crosses", inline="display", group="Display")
bool useTrendFilter = input.bool(true, "Trend Filter", inline="display", group="Display")
color colorUp1      = input.color(#43A047, "Higher", inline="colors", group="Colors")
color colorUp2      = input.color(#A5D6A7, "High", inline="colors", group="Colors")
color colorDown1    = input.color(#E53935, "Lower", inline="colors", group="Colors")
color colorDown2    = input.color(#EF9A9A, "Low", inline="colors", group="Colors")

var bool crossedUp      = false
var float normalization = 12 / (length * (length - 1) * (length + 1))
var float Lenp1half     = (length + 1) * 0.5

getRange() =>
    float H = ta.highest(length)
    float L = ta.lowest(length)
    H - L

getValue() =>
    float[] arr1 = array.new_float(length + 2, 0)
    float[] arr2 = array.new_float(length + 2, 0)
    float[] arr3 = array.new_float(length + 2, 0)
    float accum     = 0.0
    int m = 1
    for int i = 1 to length
        array.set(arr2, i, i)
        array.set(arr3, i, i)
        array.set(arr1, i, src[length - i])
    
    for int i = 1 to length - 1
        float maxval = array.get(arr1, i)
        int maxloc = i
        for j = i + 1 to length
            if array.get(arr1, j) < maxval
                maxval := array.get(arr1, j)
                maxloc := j
        
        float tmp1 = array.get(arr1, i)
        array.set(arr1, i, array.get(arr1, maxloc))
        array.set(arr1, maxloc, tmp1)
        float tmp2 = array.get(arr2, i)
        array.set(arr2, i, array.get(arr2, maxloc))
        array.set(arr2, maxloc, tmp2)
    while m < length - 1
        int j = m + 1
        bool flag = true
        accum := array.get(arr3, m)
        
        while flag
            if array.get(arr1, m) != array.get(arr1, j)
                if j - m > 1
                    accum := accum / (j - m)
                    for int n = m to j - 1
                        array.set(arr3, n, accum)
                flag := false
            else
                accum := accum + array.get(arr3, j)
                j := j + 1
                if j >= array.size(arr1) - 1
                    flag := false
        m := j
        
    accum := 0.0
    for int i = 1 to length
        accum := accum + (array.get(arr3, m) - Lenp1half) * (array.get(arr2, m) - Lenp1half)
    accum

float j_tpo             = (normalization * getValue()) * getRange() / length
float ema               = ta.ema(j_tpo, emaLength)
bool conditionBelow     = (useTrendFilter and ema < 0) and j_tpo < 0
bool conditionAbove     = (useTrendFilter and ema > 0) and j_tpo > 0
color conditionColor    = conditionBelow ? j_tpo < j_tpo[1] ? colorDown1 : colorDown2 : conditionAbove ? j_tpo > j_tpo[1] ? colorUp1 : colorUp2 : color.gray
crossedUp               := conditionBelow and j_tpo[1] >= 0 ? false : conditionAbove and j_tpo[1] <= 0 ? true : crossedUp

hline(0)
barcolor(colorbars ? conditionColor : na)
plot(j_tpo, "J_TPO", conditionColor, 1, plot.style_columns) 
plot(ema, "EMA Baseline", color.yellow, 2)
plotshape(showFirstCross ? crossedUp and not nz(crossedUp[1], false) : false, "Kicking Cross Up", shape.triangleup, location.bottom, colorUp1, size=size.small)
plotshape(showFirstCross ? not crossedUp and nz(crossedUp[1], false) : false, "Kicking Cross Down", shape.triangledown, location.top, colorDown1, size=size.small)
plotshape(showCross ? conditionBelow and j_tpo[1] >= 0 : false, "Cross Down", shape.diamond, location.top, colorDown1, size=size.tiny)
plotshape(showCross ? conditionAbove and j_tpo[1] <= 0 : false, "Cross Up", shape.diamond, location.bottom, colorUp1, size=size.tiny)






