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

//@version=5
indicator("PhantomFlow Trend Detector", "PhantomFlow TrendDetector", true, max_lines_count = 500)

type fractal
    int fractal_bar
    box bx

type wave
    bool isActive
    bool isSearchCountertrendFormation
    bool isSearchTrendFormation
    int bar_start
    int bar_end
    float high_price
    float low_price
    array<line> lines

var array<wave> waves_down = array.new<wave>()
var array<wave> waves_up = array.new<wave>()
var array<int> fractals_down_zigzag = array.new<int>()
var array<int> fractals_up_zigzag = array.new<int>()

var array<bool> listFractals = array.new<bool>()

var array<fractal> LevelsShort = array.new<fractal>()
var array<fractal> LevelsLong = array.new<fractal>()

var array<fractal> LevelsShortHTF = array.new<fractal>()
var array<fractal> LevelsLongHTF = array.new<fractal>()

var array<int> levelsToCoef = array.new<int>()

ltf = timeframe.period
up_trend_start = input.color(title='Low', defval = color.rgb(255, 253, 106), group="Up Trend Power", inline = "up_trend")
up_trend_end = input.color(title='High', defval = color.rgb(0, 255, 0), group="Up Trend Power", inline = "up_trend")
down_trend_start = input.color(title='Low', defval = color.rgb(255, 89, 255), group="Down Trend Power", inline = "down_trend")
down_trend_end = input.color(title='High', defval = color.rgb(255, 0, 0), group="Down Trend Power", inline = "down_trend")

n_zigzag = 2

is_down_fractal_zigzag() =>
    bool isConfirmFractal = false

    for i = 0 to n_zigzag + n_zigzag
        if low[n_zigzag] > low[i]
            break

        if (i == n_zigzag + n_zigzag)
			isConfirmFractal := true

    isConfirmFractal

is_up_fractal_zigzag() =>
    bool isConfirmFractal = false
    
    for i = 0 to n_zigzag + n_zigzag
        if high[n_zigzag] < high[i]
            break

        if (i == n_zigzag + n_zigzag)
			isConfirmFractal := true
        
    isConfirmFractal

check_is_add_up_liquidity() =>
    if array.size(fractals_up_zigzag) > 2
        item1 = array.last(fractals_up_zigzag)
        item2 = array.get(fractals_up_zigzag, array.size(fractals_up_zigzag) - 2)
        item3 = array.get(fractals_up_zigzag, array.size(fractals_up_zigzag) - 3)
        if (high[bar_index - item1] < high[bar_index - item2] and high[bar_index - item2] < high[bar_index - item3])
            if array.size(waves_up) == 0
                array.push(waves_up, wave.new(true, true, true, item3, item1, high[bar_index - item3], high[bar_index - item1], array.new<line>()))
                true
            else
                wave last_wave = array.last(waves_up)
                if (item3 >= last_wave.bar_start and item3 < last_wave.bar_end)
                    last_wave.bar_end := item1
                    last_wave.low_price := high[bar_index - item1]
                    last_wave.isActive := false
                    true
                else
                    array.push(waves_up, wave.new(true, true, true, item3, item1, high[bar_index - item3], high[bar_index - item1], array.new<line>()))
                    true

check_is_add_down_liquidity() =>
    if array.size(fractals_down_zigzag) > 2
        item1 = array.last(fractals_down_zigzag)
        item2 = array.get(fractals_down_zigzag, array.size(fractals_down_zigzag) - 2)
        item3 = array.get(fractals_down_zigzag, array.size(fractals_down_zigzag) - 3)
        if (low[bar_index - item1] > low[bar_index - item2] and low[bar_index - item2] > low[bar_index - item3])
            if array.size(waves_down) == 0
                array.push(waves_down, wave.new(true, true, true, item3, item1, low[bar_index - item1], low[bar_index - item3], array.new<line>()))
                true
            else
                wave last_wave = array.last(waves_down)
                if (item3 >= last_wave.bar_start and item3 < last_wave.bar_end)
                    last_wave.bar_end := item1
                    last_wave.high_price := low[bar_index - item1]
                    last_wave.isActive := false
                    true
                else
                    array.push(waves_down, wave.new(true, true, true, item3, item1, low[bar_index - item1], low[bar_index - item3], array.new<line>()))
                    true

bool is_search_fractal_zigzag = bar_index - n_zigzag * 2 >= 0 

if is_search_fractal_zigzag and true
    if is_up_fractal_zigzag()
        if array.size(fractals_up_zigzag) == 0
            array.push(fractals_up_zigzag, bar_index - (n_zigzag))
            array.push(listFractals, true)
        else 
            isUpLastFractal = array.last(listFractals)
            lastFractal = array.last(fractals_up_zigzag)

            if isUpLastFractal and high[bar_index - lastFractal] < high[n_zigzag]
                array.pop(fractals_up_zigzag)
                array.push(fractals_up_zigzag, bar_index - (n_zigzag))
                check_is_add_up_liquidity()

            if not isUpLastFractal
                lastFractalDown = array.last(fractals_down_zigzag)
                if (low[bar_index - lastFractalDown] < high[n_zigzag])
                    array.push(fractals_up_zigzag, bar_index - (n_zigzag))
                    array.push(listFractals, true)
                    check_is_add_up_liquidity()
    if is_down_fractal_zigzag()
        if array.size(fractals_down_zigzag) == 0
            array.push(fractals_down_zigzag, bar_index - (n_zigzag))
            array.push(listFractals, false)
        else
            isUpLastFractal = array.last(listFractals)
            lastFractal = array.last(fractals_down_zigzag)

            if not isUpLastFractal and low[bar_index - lastFractal] > low[n_zigzag]
                array.pop(fractals_down_zigzag)
                array.push(fractals_down_zigzag, bar_index - (n_zigzag))
                check_is_add_down_liquidity()

            if isUpLastFractal
                lastFractalUp = array.last(fractals_up_zigzag)
                if (high[bar_index - lastFractalUp] > low[n_zigzag])
                    array.push(fractals_down_zigzag, bar_index - (n_zigzag))
                    array.push(listFractals, false)
                    check_is_add_down_liquidity()

bool isDownTrend = false
bool isUpTrend = false

var float last_low = na
var float last_high = na

if (array.size(waves_up) != 0 and array.size(waves_down) != 0)
    wave lastWaveUp = array.last(waves_up)
    wave lastWaveDown = array.last(waves_down)

    if (close < lastWaveDown.high_price and close > lastWaveUp.low_price)
        if (lastWaveDown.bar_end < lastWaveUp.bar_end)
            isUpTrend := true
            last_low := lastWaveUp.low_price
            last_high := lastWaveUp.high_price
        else
            isDownTrend := true
            last_low := lastWaveDown.low_price
            last_high := lastWaveDown.high_price
        
    if (close >= lastWaveDown.high_price and close > lastWaveUp.low_price)
        isUpTrend := true
        last_low := lastWaveUp.low_price
        last_high := lastWaveUp.high_price

    if (close < lastWaveDown.high_price and close <= lastWaveUp.low_price)
        isDownTrend := true
        last_low := lastWaveDown.low_price
        last_high := lastWaveDown.high_price


if (array.size(waves_up) != 0 and array.size(waves_down) == 0)
    wave lastWave = array.last(waves_up)
    if (close > lastWave.low_price)
        isUpTrend := true
        last_low := lastWave.low_price
        last_high := lastWave.high_price

if (array.size(waves_down) != 0 and array.size(waves_up) == 0)
    wave lastWave = array.last(waves_down)
    if (close < lastWave.high_price)
        isDownTrend := true
        last_low := lastWave.low_price
        last_high := lastWave.high_price

var color trend_css = na
float signal = ta.ema(close, 1)

color signalColorDown = color.from_gradient(signal, last_low, last_high, up_trend_start, up_trend_end)
color signalColorUp = color.from_gradient(signal, last_low, last_high, down_trend_end, down_trend_start)

if isDownTrend
    trend_css := signalColorUp
if isUpTrend
    trend_css := signalColorDown

plotcandle(open, high, low, close
  , color = trend_css
  , wickcolor = trend_css
  , bordercolor = trend_css
  , editable = false
  , display = display.pane)