Indicator · Pine Script v6 · On the chart

SMC

by TamTH-Dev· code credited to tamth_

SMC is a multi-timeframe indicator that detects and plots Fair Value Gaps (FVGs) directly on the price chart.

View on GitHub

Repaints

GitHub stars2on the repository
Pine versionv6current
Lines of code2,195
Settings40inputs
LicenceNone statedfile: MPL-2.0
Last update5 weeks ago18 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

2,195 lines of Pine Script v6 from strategies/strategies4/SMC.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

SMC.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tamth_

//@version=6
indicator('SMC', overlay = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500, max_bars_back = 5000)

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
// Colors
color TRANSPARENT_COLOR = #ffffff00
color WHITE_COLOR       = #dee2e6
color BLACK_COLOR       = #000000
color RED_COLOR         = #F72585
color ORANGE_COLOR      = #fb5607
color YELLOW_COLOR      = #ffbe0b
color GREEN_COLOR       = #2a9d8f
color AQUA_COLOR        = #4CC9F0
color BLUE_COLOR        = #4361ee
color PURPLE_COLOR      = #3F37C9
color PINK_COLOR        = #B5179E
color LIGHT_GRAY_COLOR  = #364156
color DARK_GRAY_COLOR   = #212d40
color TEXT_COLOR        = #ced4da

//-----------------------------------------------------------------------------
// Common Variables
//-----------------------------------------------------------------------------
series int barIdx = bar_index

//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
type Helper
    string name = 'Helper'

//-----------------------------------------------------------------------------
// Common Methods
//-----------------------------------------------------------------------------
debug(simple string txt) =>
    var label lbl = label.new(barIdx, na, txt, xloc.bar_index, yloc.price, color(na), label.style_none, WHITE_COLOR, size.large, text.align_left)
    label.set_xy(lbl, barIdx, ta.highest(10)[1])
    label.set_text(lbl, txt)

method LineStyle(Helper helper, string style) =>
    helper.name := style
    out = switch style
        '----' => line.style_dashed
        '····' => line.style_dotted
        => line.style_solid
    out

method DayOfWeek(Helper helper, int index) =>
    helper.name := 'DOW'
    switch
        index == 1 => 'M'
        index == 2 => 'T'
        index == 3 => 'W'
        index == 4 => 'T'
        index == 5 => 'F'
        index == 6 => 'S'
        index == 7 => 'S'
        na(index) => ''

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// HTF FVGs
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
type FVGSettings
    string style
    bool open_show
    string open_style
    int open_size
    bool close_show
    string close_style
    int close_size
    bool fill
    int fill_percent
    bool CE_show
    string CE_style
    int CE_size
    color CE_bull_color
    color CE_bear_color
    bool link_show
    string link_style
    int link_size
    int max_sets
    bool mitigated_show
    string mitigated_type
    color mitigated_color_bull
    color mitigated_color_bear
    int mitigated_extend
    bool ltf_hide
    bool ctf_hide
    bool label_show
    bool label_open
    bool label_close
    bool label_ce
    bool label_tf
    bool label_type
    bool label_level
    color label_color
    color label_bgcolor
    string label_size
    int extend
    string extendby
    int buffer
    bool useProximity
    int proximity
    int labelfactor
    float atrfactor

type FVGImbalanceSettings
    bool show
    string htf
    color color_bull
    color color_bear
    color color_bull_ce
    color color_bear_ce
    int max_count

type FVGBox
    line open
    line close
    line ce
    line link
    linefill fill
    label label_open
    label label_close
    label label_ce

type FVGImbalance
    int open_time
    int close_time
    float open
    float middle
    float close
    bool mitigated
    int mitigated_time
    bool isbullish
    FVGBox box2

type FVGImbalanceStructure
    array<FVGImbalance> imbalance
    FVGImbalanceSettings settings
    int order = 1
    int step = 0

//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
Fvg_Settings_HTF = 'FVG HTF'
Fvg_Settings_Display = 'FVG Display'
Fvg_Settings_Labels = 'FVG Labeling'
Fvg_Settings_Labels_Levels = 'FVG Label Levels To Display'
Fvg_Settings_Labels_Content = 'FVG Label Display Content'
Fvg_Settings_Advanced = 'FVG Advanced Settings'

FVGSettings fvg_settings = FVGSettings.new()
FVGImbalanceSettings HTF_1_Settings = FVGImbalanceSettings.new()
FVGImbalanceSettings HTF_2_Settings = FVGImbalanceSettings.new()
FVGImbalanceSettings HTF_3_Settings = FVGImbalanceSettings.new()
FVGImbalanceSettings HTF_4_Settings = FVGImbalanceSettings.new()
FVGImbalanceSettings HTF_5_Settings = FVGImbalanceSettings.new()
FVGImbalanceSettings HTF_6_Settings = FVGImbalanceSettings.new()

string fvg_tooltip1 = 'HTF FVG Settings:\n\tShow/Hide timeframe\n\tTimeframe to display\n\tBullish FVG Color\n\tBearish FVG Color\n\tMaximum number of FVGs to display'
string fvg_tooltip2 = 'Mitigated FVG Settings:\n\tShow/Hide mitigated (Applies to all).\n\tBullish FVG Color\n\tBearish FVG Color\n\tWhen to mark it as mitigated (Based on HTF timeframe, not current timeframe)'

HTF_1_Settings.show := input.bool(true, '', inline = 'htf1', group = Fvg_Settings_HTF)
htf_1 = input.timeframe('5', '', inline = 'htf1', group = Fvg_Settings_HTF)
HTF_1_Settings.htf := htf_1
HTF_1_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf1', group = Fvg_Settings_HTF)
HTF_1_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf1', group = Fvg_Settings_HTF)
HTF_1_Settings.max_count := input.int(20, '', inline = 'htf1', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

HTF_2_Settings.show := input.bool(true, '', inline = 'htf2', group = Fvg_Settings_HTF)
htf_2 = input.timeframe('15', '', inline = 'htf2', group = Fvg_Settings_HTF)
HTF_2_Settings.htf := htf_2
HTF_2_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf2', group = Fvg_Settings_HTF)
HTF_2_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf2', group = Fvg_Settings_HTF)
HTF_2_Settings.max_count := input.int(20, '', inline = 'htf2', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

HTF_3_Settings.show := input.bool(true, '', inline = 'htf3', group = Fvg_Settings_HTF)
htf_3 = input.timeframe('60', '', inline = 'htf3', group = Fvg_Settings_HTF)
HTF_3_Settings.htf := htf_3
HTF_3_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf3', group = Fvg_Settings_HTF)
HTF_3_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf3', group = Fvg_Settings_HTF)
HTF_3_Settings.max_count := input.int(20, '', inline = 'htf3', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

HTF_4_Settings.show := input.bool(true, '', inline = 'htf4', group = Fvg_Settings_HTF)
htf_4 = input.timeframe('240', '', inline = 'htf4', group = Fvg_Settings_HTF)
HTF_4_Settings.htf := htf_4
HTF_4_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf4', group = Fvg_Settings_HTF)
HTF_4_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf4', group = Fvg_Settings_HTF)
HTF_4_Settings.max_count := input.int(10, '', inline = 'htf4', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

HTF_5_Settings.show := input.bool(true, '', inline = 'htf5', group = Fvg_Settings_HTF)
htf_5 = input.timeframe('1D', '', inline = 'htf5', group = Fvg_Settings_HTF)
HTF_5_Settings.htf := htf_5
HTF_5_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf5', group = Fvg_Settings_HTF)
HTF_5_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf5', group = Fvg_Settings_HTF)
HTF_5_Settings.max_count := input.int(10, '', inline = 'htf5', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

HTF_6_Settings.show := input.bool(true, '', inline = 'htf6', group = Fvg_Settings_HTF)
htf_6 = input.timeframe('1W', '', inline = 'htf6', group = Fvg_Settings_HTF)
HTF_6_Settings.htf := htf_6
HTF_6_Settings.color_bull := input.color(color.new(GREEN_COLOR, 25), '', inline = 'htf6', group = Fvg_Settings_HTF)
HTF_6_Settings.color_bear := input.color(color.new(RED_COLOR, 25), '', inline = 'htf6', group = Fvg_Settings_HTF)
HTF_6_Settings.max_count := input.int(2, '', inline = 'htf6', tooltip = fvg_tooltip1, group = Fvg_Settings_HTF)

fvg_settings.max_sets := input.int(6, 'Limit to next HTFs only', options = [1, 2, 3, 4, 5, 6])

fvg_settings.ltf_hide := input.bool(true, 'Hide Lower Timeframes')
fvg_settings.ctf_hide := input.bool(true, 'Hide Current Timeframe')

fvg_settings.fill := input.bool(false, 'Background Transparency', inline = 'fill')

fvg_settings.extendby := input.string('When in Range', 'Extend lines', options = ['Extension Only', 'Current Candle Plus Extension', 'When in Range'])
fvg_settings.extend := input.int(4, 'Distance from current candle', minval = 0)
fvg_settings.buffer := input.int(4, 'Spacing between timeframes', minval = 0)
fvg_settings.fill_percent := input.int(50, '', options = [98, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50], inline = 'fill')

fvg_settings.mitigated_show := input.bool(false, 'Mitigated', inline = '2')
fvg_settings.mitigated_color_bull := input.color(color.new(DARK_GRAY_COLOR, 60), '', inline = '2')
fvg_settings.mitigated_color_bear := input.color(color.new(DARK_GRAY_COLOR, 60), '', inline = '2')
fvg_settings.mitigated_type := input.string('Wick filled', 'when', options = ['None', 'Touched', 'Wick filled', 'Body filled', 'Wick filled half', 'Body filled half'], inline = '2', tooltip = fvg_tooltip2)
fvg_settings.mitigated_extend := input.int(5, 'Extend mitigated lines', minval = 0)

fvg_settings.open_show := input.bool(true, 'Open', group = Fvg_Settings_Display, inline = 'open')
fvg_settings.open_style := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group = Fvg_Settings_Display, inline = 'open')
fvg_settings.open_size := input.int(1, '', options = [1, 2, 3, 4], group = Fvg_Settings_Display, inline = 'open')

fvg_settings.close_show := input.bool(true, 'Close', group = Fvg_Settings_Display, inline = 'close')
fvg_settings.close_style := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group = Fvg_Settings_Display, inline = 'close')
fvg_settings.close_size := input.int(1, '', options = [1, 2, 3, 4], group = Fvg_Settings_Display, inline = 'close')

fvg_settings.CE_show := input.bool(true, 'C.E.', group = Fvg_Settings_Display, inline = '3')
fvg_settings.CE_bull_color := input.color(TRANSPARENT_COLOR, '', group = Fvg_Settings_Display, inline = '3')
fvg_settings.CE_bear_color := input.color(TRANSPARENT_COLOR, '', group = Fvg_Settings_Display, inline = '3')
fvg_settings.CE_style := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group = Fvg_Settings_Display, inline = '3')
fvg_settings.CE_size := input.int(1, '', options = [1, 2, 3, 4], group = Fvg_Settings_Display, inline = '3')

fvg_settings.link_show := input.bool(true, 'Link', group = Fvg_Settings_Display, inline = '4')
fvg_settings.link_style := input.string('⎯⎯⎯', '', options = ['⎯⎯⎯', '----', '····'], group = Fvg_Settings_Display, inline = '4')
fvg_settings.link_size := input.int(2, '', options = [1, 2, 3, 4], group = Fvg_Settings_Display, inline = '4')

fvg_settings.label_show := input.bool(true, 'Label', inline = 'label', group = Fvg_Settings_Labels)
fvg_settings.label_color := input.color(color.new(TEXT_COLOR, 50), '', group = Fvg_Settings_Labels, inline = 'label')
fvg_settings.label_bgcolor := input.color(TRANSPARENT_COLOR, '', group = Fvg_Settings_Labels, inline = 'label')
fvg_settings.label_size := input.string(size.small, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = Fvg_Settings_Labels, inline = 'label')

fvg_settings.label_open := input.bool(false, 'Open', group = Fvg_Settings_Labels_Levels, inline = 'level')
fvg_settings.label_close := input.bool(false, 'Close', group = Fvg_Settings_Labels_Levels, inline = 'level')
fvg_settings.label_ce := input.bool(true, 'C.E.', group = Fvg_Settings_Labels_Levels, inline = 'level')

fvg_settings.label_tf := input.bool(true, 'Timeframe', group = Fvg_Settings_Labels_Content, inline = 'level2')
fvg_settings.label_type := input.bool(false, 'BISI / SIBI', group = Fvg_Settings_Labels_Content, inline = 'level3')
fvg_settings.label_level := input.bool(false, 'Open / Close / C.E.', group = Fvg_Settings_Labels_Content, inline = 'level4')

fvg_settings.useProximity := input.bool(true, 'Use Proximity to show to show/hide FVGs', group = Fvg_Settings_Advanced)
fvg_settings.proximity := 11 - input.int(9, 'Proximity factor based on daily range', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], group = Fvg_Settings_Advanced)
fvg_settings.labelfactor := input.int(10, 'Combine labels factor for visibility', options = [20, 15, 10, 6, 5, 4, 3], group = Fvg_Settings_Advanced) / 10
fvg_settings.atrfactor := input.int(10, 'Range should be within X candles', minval = 1, group = Fvg_Settings_Advanced)

//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
Helper fvg_helper = Helper.new()

var FVGImbalanceStructure FVG_1 = FVGImbalanceStructure.new()
var FVGImbalanceStructure FVG_2 = FVGImbalanceStructure.new()
var FVGImbalanceStructure FVG_3 = FVGImbalanceStructure.new()
var FVGImbalanceStructure FVG_4 = FVGImbalanceStructure.new()
var FVGImbalanceStructure FVG_5 = FVGImbalanceStructure.new()
var FVGImbalanceStructure FVG_6 = FVGImbalanceStructure.new()

var array<FVGImbalance> FVGs_1 = array.new<FVGImbalance>()
var array<FVGImbalance> FVGs_2 = array.new<FVGImbalance>()
var array<FVGImbalance> FVGs_3 = array.new<FVGImbalance>()
var array<FVGImbalance> FVGs_4 = array.new<FVGImbalance>()
var array<FVGImbalance> FVGs_5 = array.new<FVGImbalance>()
var array<FVGImbalance> FVGs_6 = array.new<FVGImbalance>()

FVG_1.imbalance := FVGs_1
FVG_1.settings := HTF_1_Settings
FVG_2.imbalance := FVGs_2
FVG_2.settings := HTF_2_Settings
FVG_3.imbalance := FVGs_3
FVG_3.settings := HTF_3_Settings
FVG_4.imbalance := FVGs_4
FVG_4.settings := HTF_4_Settings
FVG_5.imbalance := FVGs_5
FVG_5.settings := HTF_5_Settings
FVG_6.imbalance := FVGs_6
FVG_6.settings := HTF_6_Settings

//Used internally for padding
var int TF_1 = 0
var int TF_2 = 0
var int TF_3 = 0
var int TF_4 = 0
var int TF_5 = 0
var int TF_6 = 0

var float fvg_daily = 0
var float fvg_monthly = 0

int fvg_cspacer = time - time[1]

var array<float> fvg_median = array.new_float()
fvg_length = 500
fvg_median.unshift(high - low)
if fvg_median.size() > fvg_length
    fvg_median.pop()
float fvg_spacing = ta.sma(ta.sma(fvg_median.median(), fvg_length), fvg_length) * fvg_settings.labelfactor

//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------


method FVGText(Helper helper, string htf, string direction, string level, bool truncate) =>
    helper.name := htf

    string formatted = ''

    if fvg_settings.label_tf
        seconds = timeframe.in_seconds(htf)
        if seconds < 60
            formatted := str.tostring(seconds) + 's'
            formatted
        else if seconds / 60 < 60
            formatted := str.tostring(seconds / 60) + 'm'
            formatted
        else if seconds / 60 / 60 < 24
            formatted := str.tostring(seconds / 60 / 60) + 'H'
            formatted
        else
            formatted := htf
            formatted
    if not truncate
        if fvg_settings.label_type
            if formatted != '' and direction != ''
                formatted := formatted + ' '
                formatted
            formatted := formatted + direction
            formatted

        if fvg_settings.label_level
            if formatted != '' and level != ''
                formatted := formatted + ' '
                formatted
            formatted := formatted + level
            formatted

    formatted

method FVGValidTimeframe(Helper helper, tf) =>
    bool valid = true

    helper.name := tf
    n1 = timeframe.in_seconds()
    n2 = timeframe.in_seconds(tf)

    if fvg_settings.ltf_hide and n1 > n2
        valid := false
        valid
    if fvg_settings.ctf_hide and n1 == n2
        valid := false
        valid
    valid

method FVGProximityRange(Helper helper, tf) =>
    helper.name := tf
    float range_high = 0
    float range_low = 0
    if timeframe.isseconds or timeframe.isminutes
        range_high := close + fvg_daily / fvg_settings.proximity
        range_low := close - fvg_daily / fvg_settings.proximity
        range_low
    if timeframe.isdaily
        range_high := close + fvg_monthly * 3
        range_low := close - fvg_monthly * 3
        range_low
    if timeframe.isweekly
        range_high := close + fvg_monthly * 12
        range_low := close - fvg_monthly * 12
        range_low
    [range_low, range_high]

method FVGHTFEnabled(Helper helper) =>
    helper.name := 'HTFEnabled'
    int enabled = 0
    enabled := enabled + (FVG_1.settings.show and helper.FVGValidTimeframe(FVG_1.settings.htf) ? 1 : 0)
    enabled := enabled + (FVG_2.settings.show and helper.FVGValidTimeframe(FVG_2.settings.htf) ? 1 : 0)
    enabled := enabled + (FVG_3.settings.show and helper.FVGValidTimeframe(FVG_3.settings.htf) ? 1 : 0)
    enabled := enabled + (FVG_4.settings.show and helper.FVGValidTimeframe(FVG_4.settings.htf) ? 1 : 0)
    enabled := enabled + (FVG_5.settings.show and helper.FVGValidTimeframe(FVG_5.settings.htf) ? 1 : 0)
    enabled := enabled + (FVG_6.settings.show and helper.FVGValidTimeframe(FVG_6.settings.htf) ? 1 : 0)

    math.min(enabled, fvg_settings.max_sets)


fvgFindLow(float price, int start, int default, bool inverse) =>
    int inc = time - time[1]
    int loc = default
    int x = inverse ? 0 : (time - start) / inc
    int y = inverse ? (time - start) / inc : 0

    if x < 10000 and y < 10000
        for i = x to y by 1
            if low[i] == price
                loc := time[i]
                break
    loc

fvgFindHigh(float price, int start, int default, bool inverse) =>
    int inc = time - time[1]
    int loc = default
    int x = inverse ? 0 : (time - start) / inc
    int y = inverse ? (time - start) / inc : 0

    if x < 10000 and y < 10000
        for i = x to y by 1
            if high[i] == price
                loc := time[i]
                break
    loc

fvgVisibleHTFs() =>
    int step = 1

    FVG_1.step := 1
    for t in FVG_1.imbalance
        if not na(t.box2)
            FVG_1.step := step
            step := step + 1
            break

    FVG_2.step := 1
    for t in FVG_2.imbalance
        if not na(t.box2)
            FVG_2.step := step
            step := step + 1
            break

    FVG_3.step := 1
    for t in FVG_3.imbalance
        if not na(t.box2)
            FVG_3.step := step
            step := step + 1
            break

    FVG_4.step := 1
    for t in FVG_4.imbalance
        if not na(t.box2)
            FVG_4.step := step
            step := step + 1
            break

    FVG_5.step := 1
    for t in FVG_5.imbalance
        if not na(t.box2)
            FVG_5.step := step
            step := step + 1
            break

    FVG_6.step := 1
    for t in FVG_6.imbalance
        if not na(t.box2)
            FVG_6.step := step
            step := step + 1
            break

//-----------------------------------------------------------------------------
// Imbalance Methods
//-----------------------------------------------------------------------------
method FVGClear(FVGImbalance imb) =>
    if not na(imb.box2)
        line.delete(imb.box2.open)
        line.delete(imb.box2.close)
        line.delete(imb.box2.ce)
        line.delete(imb.box2.link)
        linefill.delete(imb.box2.fill)
        label.delete(imb.box2.label_open)
        label.delete(imb.box2.label_close)
        label.delete(imb.box2.label_ce)
        imb.box2 := na
        imb.box2


// AddZone is used to display and manage imbalance related boxes
method FVGAddZone(FVGImbalanceStructure IS, FVGImbalance imb, int step) =>
    bool visible = true
    if IS.settings.show
        int buffer = time + (time - time[1]) * (fvg_settings.extend + 1 + fvg_settings.buffer * (step - 1))

        if imb.mitigated and not fvg_settings.mitigated_show
            if not na(imb.box2)
                visible := false
                visible
            imb.FVGClear()

        if na(imb.box2)
            color c = imb.isbullish ? IS.settings.color_bull : IS.settings.color_bear
            color cce = imb.isbullish ? fvg_settings.CE_bull_color : fvg_settings.CE_bear_color

            imb.box2 := FVGBox.new()
            imb.box2.open := line.new(imb.open_time, imb.open, buffer, imb.open, xloc = xloc.bar_time, style = fvg_helper.LineStyle(fvg_settings.open_style), color = fvg_settings.open_show ? c : TRANSPARENT_COLOR, width = fvg_settings.open_size)
            imb.box2.close := line.new(imb.close_time, imb.close, buffer, imb.close, xloc = xloc.bar_time, style = fvg_helper.LineStyle(fvg_settings.close_style), color = fvg_settings.close_show ? c : TRANSPARENT_COLOR, width = fvg_settings.close_size)
            if fvg_settings.link_show
                imb.box2.link := line.new(buffer, imb.open, buffer, imb.close, xloc = xloc.bar_time, style = fvg_helper.LineStyle(fvg_settings.link_style), color = c, width = fvg_settings.link_size)
                imb.box2.link
            if fvg_settings.fill
                imb.box2.fill := linefill.new(imb.box2.open, imb.box2.close, color.new(c, fvg_settings.fill_percent))
                imb.box2.fill

            if fvg_settings.CE_show
                imb.box2.ce := line.new((imb.open_time + imb.close_time) / 2, imb.middle, buffer, imb.middle, xloc = xloc.bar_time, style = fvg_helper.LineStyle(fvg_settings.CE_style), color = cce, width = fvg_settings.CE_size)
                imb.box2.ce
            if fvg_settings.label_show
                if math.abs(imb.open - imb.close) >= fvg_spacing
                    if fvg_settings.open_show or fvg_settings.fill
                        if fvg_settings.label_open
                            imb.box2.label_open := label.new(buffer, imb.open, text = fvg_helper.FVGText(IS.settings.htf, imb.isbullish ? 'BISI' : 'SIBI', 'Open', false), xloc = xloc.bar_time, textcolor = fvg_settings.label_color, style = label.style_label_left, color = fvg_settings.label_bgcolor, size = fvg_settings.label_size)
                            imb.box2.label_open
                    if fvg_settings.close_show or fvg_settings.fill
                        if fvg_settings.label_close
                            imb.box2.label_close := label.new(buffer, imb.close, text = fvg_helper.FVGText(IS.settings.htf, imb.isbullish ? 'BISI' : 'SIBI', 'Close', false), xloc = xloc.bar_time, textcolor = fvg_settings.label_color, style = label.style_label_left, color = fvg_settings.label_bgcolor, size = fvg_settings.label_size)
                            imb.box2.label_close
                    if fvg_settings.CE_show and fvg_settings.label_ce
                        imb.box2.label_ce := label.new(buffer, imb.middle, text = fvg_helper.FVGText(IS.settings.htf, imb.isbullish ? 'BISI' : 'SIBI', 'ce', false), xloc = xloc.bar_time, textcolor = fvg_settings.label_color, style = label.style_label_left, color = fvg_settings.label_bgcolor, size = fvg_settings.label_size)
                        imb.box2.label_ce
                else
                    if fvg_settings.CE_show
                        imb.box2.label_ce := label.new(buffer, imb.middle, text = fvg_helper.FVGText(IS.settings.htf, imb.isbullish ? 'BISI' : 'SIBI', '', false), xloc = xloc.bar_time, textcolor = fvg_settings.label_color, style = label.style_label_left, color = fvg_settings.label_bgcolor, size = fvg_settings.label_size)
                        imb.box2.label_ce
    visible

method FVGUpdateZone(FVGImbalanceStructure IS) =>
    if barstate.islast
        fvgVisibleHTFs()
        int level = IS.step
        for imb in IS.imbalance
            if not na(imb.box2)
                int buffer = 0
                if imb.mitigated
                    buffer := imb.close_time + fvg_cspacer * fvg_settings.mitigated_extend
                    line.set_color(imb.box2.open, imb.isbullish ? fvg_settings.mitigated_color_bull : fvg_settings.mitigated_color_bear)
                    line.set_color(imb.box2.close, imb.isbullish ? fvg_settings.mitigated_color_bull : fvg_settings.mitigated_color_bear)
                    line.set_color(imb.box2.ce, imb.isbullish ? fvg_settings.mitigated_color_bull : fvg_settings.mitigated_color_bear)
                    line.set_color(imb.box2.link, imb.isbullish ? fvg_settings.mitigated_color_bull : fvg_settings.mitigated_color_bear)
                    linefill.set_color(imb.box2.fill, color.new(imb.isbullish ? fvg_settings.mitigated_color_bull : fvg_settings.mitigated_color_bear, fvg_settings.fill_percent))
                else
                    if fvg_settings.extendby == 'Extension Only'
                        buffer := (imb.close_time < chart.left_visible_bar_time ? chart.left_visible_bar_time : imb.close_time) + fvg_cspacer * (fvg_settings.extend + 1)
                        buffer
                    else
                        if fvg_settings.extendby == 'When in Range'
                            float atrlength = ta.atr(14) * fvg_settings.atrfactor
                            if math.max(imb.open, imb.close) > close - atrlength and math.min(imb.open, imb.close) < close + atrlength
                                buffer := time + fvg_cspacer * (fvg_settings.extend + 1 + (level - 1) * fvg_settings.buffer)
                                buffer
                            else
                                buffer := imb.close_time + fvg_cspacer * (fvg_settings.extend + 1)
                                buffer
                        else
                            buffer := time + fvg_cspacer * (fvg_settings.extend + 1 + (level - 1) * fvg_settings.buffer)
                            buffer

                line.set_x2(imb.box2.open, buffer)
                line.set_x2(imb.box2.close, buffer)
                line.set_x1(imb.box2.link, buffer)
                line.set_x2(imb.box2.link, buffer)
                if fvg_settings.label_show
                    label.set_x(imb.box2.label_open, buffer)
                    label.set_x(imb.box2.label_close, buffer)
                    label.set_x(imb.box2.label_ce, buffer)

                if fvg_settings.CE_show
                    line.set_x2(imb.box2.ce, buffer)
                if imb.mitigated
                    if na(imb.box2.label_ce)
                        imb.box2.label_ce := label.new(buffer, imb.middle, text = fvg_helper.FVGText(IS.settings.htf, '', '', true), xloc = xloc.bar_time, textcolor = fvg_settings.label_color, style = label.style_label_left, color = fvg_settings.label_bgcolor, size = fvg_settings.label_size)
                        imb.box2.label_ce
                    else
                        label.set_text(imb.box2.label_ce, fvg_helper.FVGText(IS.settings.htf, '', '', true))
                    label.delete(imb.box2.label_open)
                    label.delete(imb.box2.label_close)

// AddImbalance adds a newly discovered imbalance. this applies for both FVG and Volume Imbalance
method FVGAddImbalance(FVGImbalanceStructure IS, float o, float c, int o_time, int c_time) =>
    FVGImbalance imb = FVGImbalance.new()
    imb.open_time := o < c ? fvgFindHigh(o, o_time, o_time, false) : fvgFindLow(o, o_time, o_time, false) // o_time
    imb.close_time := o < c ? fvgFindLow(c, o_time, c_time, true) : fvgFindHigh(c, o_time, c_time, true) // c_time
    imb.open := o
    imb.middle := (o + c) / 2
    imb.close := c
    imb.isbullish := o < c
    IS.imbalance.unshift(imb)

    if IS.imbalance.size() > IS.settings.max_count
        temp = IS.imbalance.pop()
        temp.FVGClear()
    IS

// CheckMitigated checks if the imbalance has been mitigated based on the settings
method FVGCheckMitigated(FVGImbalanceStructure IS, o, h, l, c, bool isHTF) =>
    if IS.imbalance.size() > 0
        for i = IS.imbalance.size() - 1 to 0 by 1
            imb = IS.imbalance.get(i)

            if not imb.mitigated
                switch fvg_settings.mitigated_type
                    'None' => 
                        imb.mitigated := false
                        imb.mitigated
                    'Touched' => 
                        imb.mitigated := (imb.open <= imb.close ? low < imb.close : high > imb.close)
                        imb.mitigated
                    'Wick filled' => 
                        imb.mitigated := (imb.open <= imb.close ? low <= imb.open : high >= imb.open)
                        imb.mitigated
                    'Body filled' => 
                        imb.mitigated := isHTF and (imb.open < imb.close ? math.min(o, c) <= imb.open : math.max(o, c) >= imb.open)
                        imb.mitigated
                    'Wick filled half' => 
                        imb.mitigated := imb.open <= imb.close ? low <= imb.middle : high >= imb.middle
                        imb.mitigated
                    'Body filled half' => 
                        imb.mitigated := isHTF and (imb.open <= imb.close ? math.min(o, c) <= imb.middle : math.max(o, c) >= imb.middle)
                        imb.mitigated
                if imb.mitigated
                    if not fvg_settings.mitigated_show
                        imb.FVGClear()
                        IS.imbalance.remove(i)
                    else
                        imb.mitigated_time := time
                        imb.mitigated_time
                    IS.FVGUpdateZone()
    IS

method FVGProximityTest(FVGImbalanceStructure IS) =>
    if IS.imbalance.size() > 0
        [rl, rh] = fvg_helper.FVGProximityRange(IS.settings.htf)
        for i = 0 to IS.imbalance.size() - 1 by 1
            imb = IS.imbalance.get(i)
            if (math.max(imb.open, imb.close) > rl and math.min(imb.open, imb.close) < rh) or not fvg_settings.useProximity
                IS.FVGAddZone(imb, IS.order)
            else
                imb.FVGClear()
    IS

// FindImbalance looks for imbalances and, if found, adds it to the list
method FVGFindImbalance(FVGImbalanceStructure IS, o, h, l, c, t, o1, h1, l1, c1, t1, o2, h2, l2, c2, t2) =>
    if IS.settings.show
        if h < l2
            IS.FVGAddImbalance(l2, h, t2, t)
        if l > h2
            IS.FVGAddImbalance(h2, l, t2, t)
    IS

method FVGProcess(FVGImbalanceStructure IS, float o, float h, float l, float c, int t, float o1, float h1, float l1, float c1, int t1, float o2, float h2, float l2, float c2, int t2) =>
    bool show = false

    if IS.settings.show
        if fvg_helper.FVGValidTimeframe(IS.settings.htf)
            IS.FVGFindImbalance(o, h, l, c, t, o1, h1, l1, c1, t1, o2, h2, l2, c2, t2)

fvgGetHTF(string htf, int i) =>
    [open[i], high[i], low[i], close[i], time[i]]

method fvgCheck(FVGImbalanceStructure IS, string htf) =>
    bool newCandle = bool(ta.change(time(htf, "america/New_York")))
    if newCandle
        int inc = 1 //barstate.isrealtime ? 1 : 0
        [o, h, l, c, t]        = request.security(syminfo.tickerid, htf, fvgGetHTF(htf, inc), lookahead = barmerge.lookahead_on)
        [o1, h1, l1, c1, t1]   = request.security(syminfo.tickerid, htf, fvgGetHTF(htf, inc+1), lookahead = barmerge.lookahead_on)
        [o2, h2, l2, c2, t2]   = request.security(syminfo.tickerid, htf, fvgGetHTF(htf, inc+2), lookahead = barmerge.lookahead_on)
        if not na(o)
            IS.FVGProcess(o, h, l, c, t, o1, h1, l1, c1, t1, o2, h2, l2, c2, t2)
            IS.FVGProximityTest()
            IS.FVGCheckMitigated(o, h, l, c, bool(ta.change(time(htf, "america/New_York"))))

    IS.FVGCheckMitigated(open, high, low, close, newCandle)

    IS.FVGUpdateZone()

//-----------------------------------------------------------------------------
// Calculate & Render
//-----------------------------------------------------------------------------
// daily and monthly are used for proximity test on higher timeframes
fvg_daily := request.security(syminfo.tickerid, '1D', ta.atr(14))
fvg_monthly := request.security(syminfo.tickerid, '1M', ta.atr(14))

int fvg_cnt = 0
int fvg_last = fvg_helper.FVGHTFEnabled()

if true// barstate.isconfirmed
    if FVG_1.settings.show
        if fvg_helper.FVGValidTimeframe(htf_1)
            fvg_cnt := fvg_cnt + 1
            FVG_1.order := fvg_cnt
            FVG_1.fvgCheck(htf_1)

    if FVG_2.settings.show
        if fvg_helper.FVGValidTimeframe(htf_2)
            if fvg_cnt < fvg_last
                fvg_cnt := fvg_cnt + 1
                FVG_2.order := fvg_cnt
                FVG_2.fvgCheck(htf_2)

    if FVG_3.settings.show
        if fvg_helper.FVGValidTimeframe(htf_3)
            if fvg_cnt < fvg_last
                fvg_cnt := fvg_cnt + 1
                FVG_3.order := fvg_cnt
                FVG_3.fvgCheck(htf_3)

    if FVG_4.settings.show
        if fvg_helper.FVGValidTimeframe(htf_4)
            if fvg_cnt < fvg_last
                fvg_cnt := fvg_cnt + 1
                FVG_4.order := fvg_cnt
                FVG_4.fvgCheck(htf_4)

    if FVG_5.settings.show
        if fvg_helper.FVGValidTimeframe(htf_5)
            if fvg_cnt < fvg_last
                fvg_cnt := fvg_cnt + 1
                FVG_5.order := fvg_cnt
                FVG_5.fvgCheck(htf_5)

    if FVG_6.settings.show
        if fvg_helper.FVGValidTimeframe(htf_6)
            if fvg_cnt < fvg_last
                fvg_cnt := fvg_cnt + 1
                FVG_6.order := fvg_cnt
                FVG_6.fvgCheck(htf_6)

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// HTF Candles
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
type Candle
    float o
    float c
    float h
    float l
    int o_time
    int o_idx
    int c_idx
    int h_idx
    int l_idx
    string dow
    box body
    line wick_up
    line wick_down
    label dow_label

type CandeTrace
    line o
    line c
    line h
    line l
    label o_l
    label c_l
    label h_l
    label l_l

type CandeImbalance
    box b
    int idx

type CandeSettingsHTF
    bool show
    string htf
    int max_display

type CandleSettings
    int max_sets
    color bull_body
    color bull_border
    color bull_wick
    color bear_body
    color bear_border
    color bear_wick
    int offset
    int buffer
    int htf_buffer
    int width
    bool use_custom_daily
    string custom_daily
    bool daily_name
    bool trace_show
    color trace_o_color
    string trace_o_style
    int trace_o_size
    color trace_c_color
    string trace_c_style
    int trace_c_size
    color trace_h_color
    string trace_h_style
    int trace_h_size
    color trace_l_color
    string trace_l_style
    int trace_l_size
    string trace_anchor
    bool label_show
    color label_color
    string label_size
    string label_position
    string label_alignment
    bool fvg_show
    color fvg_color
    bool vi_show
    color vi_color
    bool htf_label_show
    color htf_label_color
    string htf_label_size
    bool htf_timer_show
    color htf_timer_color
    string htf_timer_size
    color dow_color
    string dow_size

type CandleSet
    array<Candle> candles
    array<CandeImbalance> imbalances
    CandeSettingsHTF settings
    label tfNameTop
    label tfNameBottom
    label tfTimerTop
    label tfTimerBottom

CandleSettings candle_settings = CandleSettings.new()

var CandeSettingsHTF CandleSettingsHTF1 = CandeSettingsHTF.new()
var CandeSettingsHTF CandleSettingsHTF2 = CandeSettingsHTF.new()
var CandeSettingsHTF CandleSettingsHTF3 = CandeSettingsHTF.new()
var CandeSettingsHTF CandleSettingsHTF4 = CandeSettingsHTF.new()
var CandeSettingsHTF CandleSettingsHTF5 = CandeSettingsHTF.new()
var CandeSettingsHTF CandleSettingsHTF6 = CandeSettingsHTF.new()

var array<Candle> candles_1 = array.new<Candle>(0)
var array<Candle> candles_2 = array.new<Candle>(0)
var array<Candle> candles_3 = array.new<Candle>(0)
var array<Candle> candles_4 = array.new<Candle>(0)
var array<Candle> candles_5 = array.new<Candle>(0)
var array<Candle> candles_6 = array.new<Candle>(0)

var array<CandeImbalance> candles_imbalances_1 = array.new<CandeImbalance>()
var array<CandeImbalance> candles_imbalances_2 = array.new<CandeImbalance>()
var array<CandeImbalance> candles_imbalances_3 = array.new<CandeImbalance>()
var array<CandeImbalance> candles_imbalances_4 = array.new<CandeImbalance>()
var array<CandeImbalance> candles_imbalances_5 = array.new<CandeImbalance>()
var array<CandeImbalance> candles_imbalances_6 = array.new<CandeImbalance>()

var CandleSet candle_htf1 = CandleSet.new()
candle_htf1.settings := CandleSettingsHTF1
candle_htf1.candles := candles_1
candle_htf1.imbalances := candles_imbalances_1

var CandleSet candle_htf2 = CandleSet.new()
candle_htf2.settings := CandleSettingsHTF2
candle_htf2.candles := candles_2
candle_htf2.imbalances := candles_imbalances_2

var CandleSet candle_htf3 = CandleSet.new()
candle_htf3.settings := CandleSettingsHTF3
candle_htf3.candles := candles_3
candle_htf3.imbalances := candles_imbalances_3

var CandleSet candle_htf4 = CandleSet.new()
candle_htf4.settings := CandleSettingsHTF4
candle_htf4.candles := candles_4
candle_htf4.imbalances := candles_imbalances_4

var CandleSet candle_htf5 = CandleSet.new()
candle_htf5.settings := CandleSettingsHTF5
candle_htf5.candles := candles_5
candle_htf5.imbalances := candles_imbalances_5

var CandleSet candle_htf6 = CandleSet.new()
candle_htf6.settings := CandleSettingsHTF6
candle_htf6.candles := candles_6
candle_htf6.imbalances := candles_imbalances_6

//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
string group_htf_candles        = "HTF Candles  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
string group_style              = "Styling  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
string group_label              = "Label  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
string group_imbalance          = "Imbalance  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
string group_trace              = "Trace  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

candle_htf1.settings.show              := input.bool(false, 'HTF 1', inline = 'htf1', group = group_htf_candles)
cancle_htf_1_input                      = input.timeframe('5', '', inline = 'htf1', group = group_htf_candles)
candle_htf1.settings.htf := cancle_htf_1_input
candle_htf1.settings.max_display       := input.int(10, '', inline = 'htf1', group = group_htf_candles)

candle_htf2.settings.show              := input.bool(false, 'HTF 2', inline = 'htf2', group = group_htf_candles)
cancle_htf_2_input                      = input.timeframe('15', '', inline = 'htf2', group = group_htf_candles)
candle_htf2.settings.htf := cancle_htf_2_input
candle_htf2.settings.max_display       := input.int(10, '', inline = 'htf2', group = group_htf_candles)

candle_htf3.settings.show              := input.bool(true, 'HTF 3', inline = 'htf3', group = group_htf_candles)
cancle_htf_3_input                      = input.timeframe('60', '', inline = 'htf3', group = group_htf_candles)
candle_htf3.settings.htf := cancle_htf_3_input
candle_htf3.settings.max_display       := input.int(10, '', inline = 'htf3', group = group_htf_candles)

candle_htf4.settings.show              := input.bool(true, 'HTF 4', inline = 'htf4', group = group_htf_candles)
cancle_htf_4_input                      = input.timeframe('240', '', inline = 'htf4', group = group_htf_candles)
candle_htf4.settings.htf               := cancle_htf_4_input
candle_htf4.settings.max_display       := input.int(10, '', inline = 'htf4', group = group_htf_candles)

candle_htf5.settings.show              := input.bool(true, 'HTF 5', inline = 'htf5', group = group_htf_candles)
cancle_htf_5_input                      = input.timeframe('1D', '', inline = 'htf5', group = group_htf_candles)
candle_htf5.settings.htf := cancle_htf_5_input
candle_htf5.settings.max_display       := input.int(10, '', inline = 'htf5', group = group_htf_candles)

candle_htf6.settings.show              := input.bool(true, 'HTF 6', inline = 'htf6', group = group_htf_candles)
cancle_htf_6_input                      = input.timeframe('1W', '', inline = 'htf6', group = group_htf_candles)
candle_htf6.settings.htf               := cancle_htf_6_input
candle_htf6.settings.max_display       := input.int(10, '', inline = 'htf6', group = group_htf_candles)

candle_settings.max_sets               := input.int(6, 'Limit to next HTFs only', minval = 1, maxval = 6)
candle_settings.use_custom_daily       := input.bool(false, 'Custom daily candle open', inline='customdaily')
candle_settings.custom_daily           := input.string('Midnight', '', options=['Midnight', '8:30', '9:30'], inline='customdaily')
candle_settings.bull_body              := input.color(WHITE_COLOR, 'Body', inline = 'body', group = group_style)
candle_settings.bear_body              := input.color(BLUE_COLOR, '', inline = 'body', group = group_style)
candle_settings.bull_border            := input.color(WHITE_COLOR, 'Borders', inline = 'borders', group = group_style)
candle_settings.bear_border            := input.color(BLUE_COLOR, '', inline = 'borders', group = group_style)
candle_settings.bull_wick              := input.color(LIGHT_GRAY_COLOR, 'Wick', inline = 'wick', group = group_style)
candle_settings.bear_wick              := input.color(LIGHT_GRAY_COLOR, '', inline = 'wick', group = group_style)

candle_settings.offset                 := input.int(30, 'padding from current candles', minval = 1, group = group_style)
candle_settings.buffer                 := input.int(1, 'space between candles', minval = 1, maxval = 4, group = group_style)
candle_settings.htf_buffer             := input.int(10, 'space between Higher Timeframes', minval = 1, maxval = 10, group = group_style)
candle_settings.width                  := input.int(1, 'Candle Width', minval = 1, maxval = 4, group = group_style) * 2

candle_settings.htf_label_show         := input.bool(true, 'HTF Label', group = group_label, inline = 'HTFlabel')
candle_settings.htf_label_color        := input.color(LIGHT_GRAY_COLOR, '', group = group_label, inline = 'HTFlabel')
candle_settings.htf_label_size         := input.string(size.large, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = group_label, inline = 'HTFlabel')

candle_settings.label_position         := input.string("Top", 'Label Positions', options=['Both', 'Top', 'Bottom'], group = group_label)
candle_settings.label_alignment        := input.string("Align", "Label Alignment", options=['Align', 'Follow Candles'], group = group_label)

candle_settings.htf_timer_show         := input.bool(true, 'Remaining time', inline = 'timer', group = group_label)
candle_settings.htf_timer_color        := input.color(LIGHT_GRAY_COLOR, '', inline = 'timer', group = group_label)
candle_settings.htf_timer_size         := input.string(size.normal, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = group_label, inline = 'timer')

candle_settings.daily_name             := input.bool(false, 'Interval Value', group = group_label, inline = 'dow')
candle_settings.dow_color              := input.color(LIGHT_GRAY_COLOR , '', group = group_label, inline = 'dow')
candle_settings.dow_size               := input.string(size.small, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = group_label, inline = 'dow')

candle_settings.fvg_show               := input.bool(true, 'Fair Value Gap', group = group_imbalance, inline = 'fvg')
candle_settings.fvg_color              := input.color(color.new(DARK_GRAY_COLOR, 60), '', inline = 'fvg', group = group_imbalance)

candle_settings.vi_show                := input.bool(false, 'Volume Imbalance', group = group_imbalance, inline = 'vi')
candle_settings.vi_color               := input.color(color.new(PINK_COLOR, 80), '', inline = 'vi', group = group_imbalance)

candle_settings.trace_show             := input.bool(false, 'Trace lines', group = group_trace)
candle_settings.trace_o_color          := input.color(DARK_GRAY_COLOR, 'Open', inline = '1', group = group_trace)
candle_settings.trace_o_style          := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline = '1', group = group_trace)
candle_settings.trace_o_size           := input.int(1, '', options = [1, 2, 3, 4], inline = '1', group = group_trace)
candle_settings.trace_c_color          := input.color(DARK_GRAY_COLOR, 'Close', inline = '2', group = group_trace)
candle_settings.trace_c_style          := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline = '2', group = group_trace)
candle_settings.trace_c_size           := input.int(1, '', options = [1, 2, 3, 4], inline = '2', group = group_trace)
candle_settings.trace_h_color          := input.color(DARK_GRAY_COLOR, 'High', inline = '3', group = group_trace)
candle_settings.trace_h_style          := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline = '3', group = group_trace)
candle_settings.trace_h_size           := input.int(1, '', options = [1, 2, 3, 4], inline = '3', group = group_trace)
candle_settings.trace_l_color          := input.color(DARK_GRAY_COLOR, 'Low', inline = '4', group = group_trace)
candle_settings.trace_l_style          := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], inline = '4', group = group_trace)
candle_settings.trace_l_size           := input.int(1, '', options = [1, 2, 3, 4], inline = '4', group = group_trace)
candle_settings.trace_anchor           := input.string('First Timeframe', 'Anchor to', options = ['First Timeframe', 'Last Timeframe'], group = group_trace)

candle_settings.label_show             := input.bool(false, 'Price Label', inline = 'label')
candle_settings.label_color            := input.color(color.new(TEXT_COLOR, 10), '', inline = 'label')
candle_settings.label_size             := input.string(size.small, '', [size.tiny, size.small, size.normal, size.large, size.huge], inline = 'label')

//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
Helper candle_helper = Helper.new()
var CandeTrace candle_trace = CandeTrace.new()

//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------


method CandleValidTimeframe(Helper helper, string HTF) =>
    helper.name := HTF
    if timeframe.in_seconds(HTF) >= timeframe.in_seconds('D') and timeframe.in_seconds(HTF) > timeframe.in_seconds()
        true
    else
        n1 = timeframe.in_seconds()
        n2 = timeframe.in_seconds(HTF)
        n3 = n1 % n2
        n1 < n2 and math.round(n2 / n1) == n2 / n1


method CandleRemainingTime(Helper helper, string HTF) =>
    helper.name := HTF
    if barstate.isrealtime
        timeRemaining = (time_close(HTF) - timenow) / 1000
        days = math.floor(timeRemaining / 86400)
        hours = math.floor((timeRemaining - days * 86400) / 3600)
        minutes = math.floor((timeRemaining - days * 86400 - hours * 3600) / 60)
        seconds = math.floor(timeRemaining - days * 86400 - hours * 3600 - minutes * 60)

        r = str.tostring(seconds, '00')
        if minutes > 0 or hours > 0 or days > 0
            r := str.tostring(minutes, '00') + ':' + r
            r
        if hours > 0 or days > 0
            r := str.tostring(hours, '00') + ':' + r
            r
        if days > 0
            r := str.tostring(days) + 'D ' + r
            r
        r
    else
        'n/a'

method CandleHTFName(Helper helper, string HTF) =>
    helper.name := 'HTFName'
    formatted = HTF

    seconds = timeframe.in_seconds(HTF)
    if seconds < 60
        formatted := str.tostring(seconds) + 's'
        formatted
    else if seconds / 60 < 60
        formatted := str.tostring(seconds / 60) + 'm'
        formatted
    else if seconds / 60 / 60 < 24
        formatted := str.tostring(seconds / 60 / 60) + 'H'
        formatted
    formatted

method CandleHTFEnabled(Helper helper) =>
    helper.name := 'HTFEnabled'
    int enabled = 0
    enabled := enabled + (candle_htf1.settings.show ? 1 : 0)
    enabled := enabled + (candle_htf2.settings.show ? 1 : 0)
    enabled := enabled + (candle_htf3.settings.show ? 1 : 0)
    enabled := enabled + (candle_htf4.settings.show ? 1 : 0)
    enabled := enabled + (candle_htf5.settings.show ? 1 : 0)
    enabled := enabled + (candle_htf6.settings.show ? 1 : 0)
    int last = math.min(enabled, candle_settings.max_sets)

    last

method CandleSetHigh(Helper helper, array<Candle> candles, float h) =>
    helper.name := 'CandlesSetHigh'
    float _h = h
    if array.size(candles) > 0
        for i = 0 to array.size(candles) - 1 by 1
            Candle c = array.get(candles, i)
            if c.h > _h
                _h := c.h
                _h
    _h

method CandleSetLow(Helper helper, array<Candle> candles, float l) =>
    helper.name := 'CandlesSetLow'
    float _l = l
    if array.size(candles) > 0
        for i = 0 to array.size(candles) - 1 by 1
            Candle c = array.get(candles, i)
            if c.l < _l
                _l := c.l
                _l
    _l

method CandlesHigh(Helper helper, array<Candle> candles) =>
    helper.name := 'CandlesHigh'
    h = 0.0
    int candle_cnt = 0
    int last = helper.CandleHTFEnabled()

    if candle_htf1.settings.show and helper.CandleValidTimeframe(candle_htf1.settings.htf)
        h := helper.CandleSetHigh(candle_htf1.candles, h)
        candle_cnt := candle_cnt + 1
    if candle_htf2.settings.show and helper.CandleValidTimeframe(candle_htf2.settings.htf) and candle_cnt < last
        h := helper.CandleSetHigh(candle_htf2.candles, h)
        candle_cnt := candle_cnt + 1
    if candle_htf3.settings.show and helper.CandleValidTimeframe(candle_htf3.settings.htf) and candle_cnt < last
        h := helper.CandleSetHigh(candle_htf3.candles, h)
        candle_cnt := candle_cnt + 1
    if candle_htf4.settings.show and helper.CandleValidTimeframe(candle_htf4.settings.htf) and candle_cnt < last
        h := helper.CandleSetHigh(candle_htf4.candles, h)
        candle_cnt := candle_cnt + 1
    if candle_htf5.settings.show and helper.CandleValidTimeframe(candle_htf5.settings.htf) and candle_cnt < last
        h := helper.CandleSetHigh(candle_htf5.candles, h)
        candle_cnt := candle_cnt + 1
    if candle_htf6.settings.show and helper.CandleValidTimeframe(candle_htf6.settings.htf) and candle_cnt < last
        h := helper.CandleSetHigh(candle_htf6.candles, h)

    if array.size(candles) > 0
        for i = 0 to array.size(candles) - 1 by 1
            Candle c = array.get(candles, i)
            if c.h > h
                h := c.h
    h

method CandlesLow(Helper helper, array<Candle> candles, float h) =>
    helper.name := 'CandlesLow'
    l = h
    int candle_cnt = 0
    int last = helper.CandleHTFEnabled()

    if candle_htf1.settings.show and helper.CandleValidTimeframe(candle_htf1.settings.htf)
        l := helper.CandleSetLow(candle_htf1.candles, l)
        candle_cnt := candle_cnt + 1
    if candle_htf2.settings.show and helper.CandleValidTimeframe(candle_htf2.settings.htf) and candle_cnt < last
        l := helper.CandleSetLow(candle_htf2.candles, l)
        candle_cnt := candle_cnt + 1
    if candle_htf3.settings.show and helper.CandleValidTimeframe(candle_htf3.settings.htf) and candle_cnt < last
        l := helper.CandleSetLow(candle_htf3.candles, l)
        candle_cnt := candle_cnt + 1
    if candle_htf4.settings.show and helper.CandleValidTimeframe(candle_htf4.settings.htf) and candle_cnt < last
        l := helper.CandleSetLow(candle_htf4.candles, l)
        candle_cnt := candle_cnt + 1
    if candle_htf5.settings.show and helper.CandleValidTimeframe(candle_htf5.settings.htf) and candle_cnt < last
        l := helper.CandleSetLow(candle_htf5.candles, l)
        candle_cnt := candle_cnt + 1
    if candle_htf6.settings.show and helper.CandleValidTimeframe(candle_htf6.settings.htf) and candle_cnt < last
        l := helper.CandleSetLow(candle_htf6.candles, l)

    if array.size(candles) > 0
        for i = 0 to array.size(candles) - 1 by 1
            Candle c = array.get(candles, i)
            if c.l < l
                l := c.l
    l

method CandleUpdateTime(CandleSet candleSet, int offset) =>
    if candle_settings.htf_timer_show and (barstate.isrealtime or barstate.islast)
        string tmr = '(' + candle_helper.CandleRemainingTime(candleSet.settings.htf) + ')'

        if not na(candleSet.tfTimerTop)
            candleSet.tfTimerTop.set_text(tmr)

        if not na(candleSet.tfTimerBottom)
            candleSet.tfTimerBottom.set_text(tmr)
    candleSet

method CandleReorder(CandleSet candleSet, int offset) =>
    size = candleSet.candles.size()

    if size > 0
        for i = size - 1 to 0 by 1
            Candle candle = candleSet.candles.get(i)
            t_buffer = offset + (candle_settings.width + candle_settings.buffer) * (size - i - 1)
            box.set_left(candle.body, bar_index + t_buffer)
            box.set_right(candle.body, bar_index + candle_settings.width + t_buffer)
            line.set_x1(candle.wick_up, bar_index + candle_settings.width / 2 + t_buffer)
            line.set_x2(candle.wick_up, bar_index + candle_settings.width / 2 + t_buffer)
            line.set_x1(candle.wick_down, bar_index + candle_settings.width / 2 + t_buffer)
            line.set_x2(candle.wick_down, bar_index + candle_settings.width / 2 + t_buffer)

            if candle_settings.daily_name //and candleSet.settings.htf == '1D'
                if not na(candle.dow_label)
                    candle.dow_label.set_y(candle.h)
                    candle.dow_label.set_x(bar_index + candle_settings.width / 2 + t_buffer)
                    candle.dow_label.set_text(candle.dow)
                else
                    candle.dow_label := label.new(bar_index + candle_settings.width / 2 + t_buffer, candle.h, candle.dow, color = TRANSPARENT_COLOR, textcolor = candle_settings.dow_color, style = label.style_label_down, size = candle_settings.dow_size)

    top = 0.0
    bottom = 0.0

    if candle_settings.label_alignment == 'Align'
        top := candle_helper.CandlesHigh(candleSet.candles)
        bottom := candle_helper.CandlesLow(candleSet.candles, top)
    if candle_settings.label_alignment == 'Follow Candles'
        top := candle_helper.CandleSetHigh(candleSet.candles, 0)
        bottom := candle_helper.CandleSetLow(candleSet.candles, top)

    left = bar_index + offset + (candle_settings.width + candle_settings.buffer) * (size - 1) / 2

    if candle_settings.htf_label_show
        string lblt = candle_helper.CandleHTFName(candleSet.settings.htf)
        string lbll = lblt
        if candle_settings.htf_timer_show
            lblt := lblt + '\n'
            lbll := '\n' + lbll
        if candle_settings.daily_name
            lblt := lblt + '\n'

        string tmr = '(' + candle_helper.CandleRemainingTime(candleSet.settings.htf) + ')' + (candle_settings.daily_name ? '\n' : '')
        if candle_settings.label_position == 'Both' or candle_settings.label_position == 'Top'
            
            if not na(candleSet.tfNameTop)
                candleSet.tfNameTop.set_xy(left, top)
            else
                candleSet.tfNameTop := label.new(left, top, lblt, color = TRANSPARENT_COLOR, textcolor = candle_settings.htf_label_color, style = label.style_label_down, size = candle_settings.htf_label_size)
            if candle_settings.htf_timer_show
                if not na(candleSet.tfTimerTop)
                    candleSet.tfTimerTop.set_xy(left, top)
                else
                    candleSet.tfTimerTop := label.new(left, top, tmr, color = TRANSPARENT_COLOR, textcolor = candle_settings.htf_timer_color, style = label.style_label_down, size = candle_settings.htf_timer_size)

        if candle_settings.label_position == 'Both' or candle_settings.label_position == 'Bottom'
            if not na(candleSet.tfNameBottom)
                candleSet.tfNameBottom.set_xy(left, bottom)
            else
                candleSet.tfNameBottom := label.new(left, bottom, lbll, color = TRANSPARENT_COLOR, textcolor = candle_settings.htf_label_color, style = label.style_label_up, size = candle_settings.htf_label_size)
            if candle_settings.htf_timer_show
                if candle_settings.htf_timer_show
                    if not na(candleSet.tfTimerBottom)
                        candleSet.tfTimerBottom.set_xy(left, bottom)
                    else
                        candleSet.tfTimerBottom := label.new(left, bottom, tmr, color = TRANSPARENT_COLOR, textcolor = candle_settings.htf_timer_color, style = label.style_label_up, size = candle_settings.htf_timer_size)

    candleSet

method CandleFindImbalance(CandleSet candleSet) =>
    if barstate.isrealtime or barstate.islast
        if candleSet.imbalances.size() > 0
            for i = candleSet.imbalances.size() - 1 to 0 by 1
                CandeImbalance del = candleSet.imbalances.get(i)
                box.delete(del.b)
                candleSet.imbalances.pop()

        if candleSet.candles.size() > 3 and candle_settings.fvg_show
            for i = 0 to candleSet.candles.size() - 3 by 1
                candle1 = candleSet.candles.get(i)
                candle2 = candleSet.candles.get(i + 2)
                candle3 = candleSet.candles.get(i + 1)

                if candle1.l > candle2.h and math.min(candle1.o, candle1.c) > math.max(candle2.o, candle2.c)
                    CandeImbalance imb = CandeImbalance.new()
                    imb.b := box.new(box.get_left(candle2.body), candle2.h, box.get_right(candle1.body), candle1.l, bgcolor = candle_settings.fvg_color, border_color = candle_settings.fvg_color, xloc = xloc.bar_index)
                    candleSet.imbalances.push(imb)
                if candle1.h < candle2.l and math.max(candle1.o, candle1.c) < math.min(candle2.o, candle2.c)
                    CandeImbalance imb = CandeImbalance.new()
                    imb.b := box.new(box.get_right(candle1.body), candle1.h, box.get_left(candle2.body), candle2.l, bgcolor = candle_settings.fvg_color, border_color = candle_settings.fvg_color)
                    candleSet.imbalances.push(imb)
                box temp = box.copy(candle3.body)
                box.delete(candle3.body)
                candle3.body := temp
                candle3.body

        if candleSet.candles.size() > 2 and candle_settings.vi_show
            for i = 0 to candleSet.candles.size() - 2 by 1
                candle1 = candleSet.candles.get(i)
                candle2 = candleSet.candles.get(i + 1)
                if candle1.l < candle2.h and math.min(candle1.o, candle1.c) > math.max(candle2.o, candle2.c)
                    CandeImbalance imb = CandeImbalance.new()
                    imb.b := box.new(box.get_left(candle2.body), math.min(candle1.o, candle1.c), box.get_right(candle1.body), math.max(candle2.o, candle2.c), bgcolor = candle_settings.vi_color, border_color = TRANSPARENT_COLOR)
                    candleSet.imbalances.push(imb)
                if candle1.h > candle2.l and math.max(candle1.o, candle1.c) < math.min(candle2.o, candle2.c)
                    CandeImbalance imb = CandeImbalance.new()
                    imb.b := box.new(box.get_right(candle1.body), math.min(candle2.o, candle2.c), box.get_left(candle2.body), math.max(candle1.o, candle1.c), bgcolor = candle_settings.vi_color, border_color = TRANSPARENT_COLOR)
                    candleSet.imbalances.push(imb)
    candleSet

method CandleMonitor(CandleSet candleSet) =>
    HTFBarTime = time(candleSet.settings.htf, 'america/New_York')
    isNewHTFCandle = ta.change(HTFBarTime) > 0

    if candle_settings.use_custom_daily
        int _830 = 0
        if isNewHTFCandle
            _830 := timestamp("America/New_York", year(time), month(time), dayofmonth(time), 0, 0) + 30600000
        if candleSet.settings.htf == '1D'
            if candle_settings.custom_daily == 'Midnight'
                isNewHTFCandle := dayofweek(time, 'America/New_York') != dayofweek(time - (time - time[1]), 'America/New_York')
            if candle_settings.custom_daily == '8:30'    
                // Get 8:30 AM New York time for today 
                isNewHTFCandle := not na(time(timeframe.period, "0830-0831:123456", 'America/New_York')) and na(time(timeframe.period, "0830-0831:123456", 'America/New_York')[1])
            if candle_settings.custom_daily == '9:30'    
                // Get 9:30 AM New York time for today 
                isNewHTFCandle := not na(time(timeframe.period, "0930-0931:123456", 'America/New_York')) and na(time(timeframe.period, "0930-0931:123456", 'America/New_York')[1])
    if isNewHTFCandle
        Candle candle = Candle.new()
        candle.o := open
        candle.c := close
        candle.h := high
        candle.l := low
        candle.o_time := time
        candle.o_idx := bar_index
        candle.c_idx := bar_index
        candle.h_idx := bar_index
        candle.l_idx := bar_index
        candle.dow := switch
            candleSet.settings.htf == '1D' =>
                candle_helper.DayOfWeek(dayofweek(time_tradingday, "America/New_York"))
            str.tonumber(candleSet.settings.htf) < 60 =>
                str.format_time(candle.o_time, 'm', 'America/New_York')
            str.tonumber(candleSet.settings.htf) >= 60 =>
                str.format_time(candle.o_time, 'H', 'America/New_York')
            candleSet.settings.htf == '1M' =>
                str.format_time(candle.o_time, 'M', 'America/New_York')
            =>
                ''
        log.info('dow: {1} |{0}|', candle.dow, candleSet.settings.htf)
        bull = candle.c > candle.o

        candle.body := box.new(bar_index, math.max(candle.o, candle.c), bar_index + 2, math.min(candle.o, candle.c), bull ? candle_settings.bull_border : candle_settings.bear_border, 1, bgcolor = bull ? candle_settings.bull_body : candle_settings.bear_body)
        candle.wick_up := line.new(bar_index + 1, candle.h, bar_index, math.max(candle.o, candle.c), color = bull ? candle_settings.bull_wick : candle_settings.bear_wick)
        candle.wick_down := line.new(bar_index + 1, math.min(candle.o, candle.c), bar_index, candle.l, color = bull ? candle_settings.bull_wick : candle_settings.bear_wick)

        candleSet.candles.unshift(candle)

        if candleSet.candles.size() > candleSet.settings.max_display
            Candle delCandle = array.pop(candleSet.candles)
            box.delete(delCandle.body)
            line.delete(delCandle.wick_up)
            line.delete(delCandle.wick_down)
            delCandle.dow_label.delete()

    candleSet

method CandleUpdate(CandleSet candleSet, int offset, bool showTrace) =>
    if candleSet.candles.size() > 0
        Candle candle = candleSet.candles.first()
        candle.h_idx := high > candle.h ? bar_index : candle.h_idx
        candle.h := high > candle.h ? high : candle.h
        candle.l_idx := low < candle.l ? bar_index : candle.l_idx
        candle.l := low < candle.l ? low : candle.l
        candle.c := close
        candle.c_idx := bar_index

        bull = candle.c > candle.o

        box.set_top(candle.body, candle.o)
        box.set_bottom(candle.body, candle.c)
        box.set_bgcolor(candle.body, bull ? candle_settings.bull_body : candle_settings.bear_body)
        box.set_border_color(candle.body, bull ? candle_settings.bull_border : candle_settings.bear_border)
        line.set_color(candle.wick_up, bull ? candle_settings.bull_wick : candle_settings.bear_wick)
        line.set_color(candle.wick_down, bull ? candle_settings.bull_wick : candle_settings.bear_wick)
        line.set_y1(candle.wick_up, candle.h)
        line.set_y2(candle.wick_up, math.max(candle.o, candle.c))
        line.set_y1(candle.wick_down, candle.l)
        line.set_y2(candle.wick_down, math.min(candle.o, candle.c))

        if barstate.isrealtime or barstate.islast
            candleSet.CandleReorder(offset)
            if candle_settings.trace_show and showTrace
                if bar_index - candle.o_idx < 5000
                    if na(candle_trace.o)
                        candle_trace.o := line.new(candle.o_idx, candle.o, box.get_left(candle.body), candle.o, xloc = xloc.bar_index, color = candle_settings.trace_o_color, style = candle_helper.LineStyle(candle_settings.trace_o_style), width = candle_settings.trace_o_size)
                        candle_trace.o
                    else
                        line.set_xy1(candle_trace.o, candle.o_idx, candle.o)
                        line.set_xy2(candle_trace.o, box.get_left(candle.body), candle.o)

                    if candle_settings.label_show
                        if na(candle_trace.o_l)
                            candle_trace.o_l := label.new(box.get_right(candle.body), candle.o, str.tostring(candle.o), textalign = text.align_center, style = label.style_label_left, size = candle_settings.label_size, color = TRANSPARENT_COLOR, textcolor = candle_settings.label_color)
                            candle_trace.o_l
                        else
                            label.set_xy(candle_trace.o_l, box.get_right(candle.body), candle.o)
                            label.set_text(candle_trace.o_l, str.tostring(candle.o))

                if bar_index - candle.c_idx < 5000
                    if na(candle_trace.c)
                        candle_trace.c := line.new(candle.c_idx, candle.c, box.get_left(candle.body), candle.c, xloc = xloc.bar_index, color = candle_settings.trace_c_color, style = candle_helper.LineStyle(candle_settings.trace_c_style), width = candle_settings.trace_c_size)
                        candle_trace.c
                    else
                        line.set_xy1(candle_trace.c, candle.c_idx, candle.c)
                        line.set_xy2(candle_trace.c, box.get_left(candle.body), candle.c)

                    if candle_settings.label_show
                        if na(candle_trace.c_l)
                            candle_trace.c_l := label.new(box.get_right(candle.body), candle.c, str.tostring(candle.c), textalign = text.align_center, style = label.style_label_left, size = candle_settings.label_size, color = TRANSPARENT_COLOR, textcolor = candle_settings.label_color)
                            candle_trace.c_l
                        else
                            label.set_xy(candle_trace.c_l, box.get_right(candle.body), candle.c)
                            label.set_text(candle_trace.c_l, str.tostring(candle.c))

                if bar_index - candle.h_idx < 5000
                    if na(candle_trace.h)
                        candle_trace.h := line.new(candle.h_idx, candle.h, line.get_x1(candle.wick_up), candle.h, xloc = xloc.bar_index, color = candle_settings.trace_h_color, style = candle_helper.LineStyle(candle_settings.trace_h_style), width = candle_settings.trace_h_size)
                        candle_trace.h
                    else
                        line.set_xy1(candle_trace.h, candle.h_idx, candle.h)
                        line.set_xy2(candle_trace.h, line.get_x1(candle.wick_up), candle.h)

                    if candle_settings.label_show
                        if na(candle_trace.h_l)
                            candle_trace.h_l := label.new(box.get_right(candle.body), candle.h, str.tostring(candle.h), textalign = text.align_center, style = label.style_label_left, size = candle_settings.label_size, color = TRANSPARENT_COLOR, textcolor = candle_settings.label_color)
                            candle_trace.h_l
                        else
                            label.set_xy(candle_trace.h_l, box.get_right(candle.body), candle.h)
                            label.set_text(candle_trace.h_l, str.tostring(candle.h))

                if bar_index - candle.l_idx < 5000
                    if na(candle_trace.l)
                        candle_trace.l := line.new(candle.l_idx, candle.l, line.get_x1(candle.wick_down), candle.l, xloc = xloc.bar_index, color = candle_settings.trace_l_color, style = candle_helper.LineStyle(candle_settings.trace_l_style), width = candle_settings.trace_l_size)
                        candle_trace.l
                    else
                        line.set_xy1(candle_trace.l, candle.l_idx, candle.l)
                        line.set_xy2(candle_trace.l, line.get_x1(candle.wick_down), candle.l)

                    if candle_settings.label_show
                        if na(candle_trace.l_l)
                            candle_trace.l_l := label.new(box.get_right(candle.body), candle.l, str.tostring(candle.l), textalign = text.align_center, style = label.style_label_left, size = candle_settings.label_size, color = TRANSPARENT_COLOR, textcolor = candle_settings.label_color)
                            candle_trace.l_l
                        else
                            label.set_xy(candle_trace.l_l, box.get_right(candle.body), candle.l)
                            label.set_text(candle_trace.l_l, str.tostring(candle.l))
    candleSet


//-----------------------------------------------------------------------------
// Calculate & Render
//-----------------------------------------------------------------------------
int candle_cnt = 0
int candle_last = candle_helper.CandleHTFEnabled()

int candle_offset = candle_settings.offset
if candle_htf1.settings.show and candle_helper.CandleValidTimeframe(candle_htf1.settings.htf)
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe'
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe' and candle_settings.max_sets == 1
        showTrace := true
        showTrace
    candle_htf1.CandleUpdateTime(candle_offset)
    candle_htf1.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()
    candle_cnt := candle_cnt + 1
    candle_offset := candle_offset + (candle_cnt > 0 ? candle_htf1.candles.size() * candle_settings.width + (candle_htf1.candles.size() > 0 ? (candle_htf1.candles.size() - 1) * candle_settings.buffer : 0) + candle_settings.htf_buffer : 0)
    candle_offset
if candle_htf2.settings.show and candle_helper.CandleValidTimeframe(candle_htf2.settings.htf) and candle_cnt < candle_last
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe' and candle_cnt == 0
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe' and candle_cnt == candle_last - 1
        showTrace := true
        showTrace
    candle_htf2.CandleUpdateTime(candle_offset)
    candle_htf2.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()
    candle_cnt := candle_cnt + 1
    candle_offset := candle_offset + (candle_cnt > 0 ? candle_htf2.candles.size() * candle_settings.width + (candle_htf2.candles.size() > 0 ? (candle_htf2.candles.size() - 1) * candle_settings.buffer : 0) + candle_settings.htf_buffer : 0)
    candle_offset
if candle_htf3.settings.show and candle_helper.CandleValidTimeframe(candle_htf3.settings.htf) and candle_cnt < candle_last
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe' and candle_cnt == 0
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe' and candle_cnt == candle_last - 1
        showTrace := true
        showTrace
    candle_htf3.CandleUpdateTime(candle_offset)
    candle_htf3.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()
    candle_cnt := candle_cnt + 1
    candle_offset := candle_offset + (candle_cnt > 0 ? candle_htf3.candles.size() * candle_settings.width + (candle_htf3.candles.size() > 0 ? (candle_htf3.candles.size() - 1) * candle_settings.buffer : 0) + candle_settings.htf_buffer : 0)
    candle_offset
if candle_htf4.settings.show and candle_helper.CandleValidTimeframe(candle_htf4.settings.htf) and candle_cnt < candle_last
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe' and candle_cnt == 0
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe' and candle_cnt == candle_last - 1
        showTrace := true
        showTrace
    candle_htf4.CandleUpdateTime(candle_offset)
    candle_htf4.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()
    candle_cnt := candle_cnt + 1
    candle_offset := candle_offset + (candle_cnt > 0 ? candle_htf4.candles.size() * candle_settings.width + (candle_htf4.candles.size() > 0 ? (candle_htf4.candles.size() - 1) * candle_settings.buffer : 0) + candle_settings.htf_buffer : 0)
    candle_offset
if candle_htf5.settings.show and candle_helper.CandleValidTimeframe(candle_htf5.settings.htf) and candle_cnt < candle_last
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe' and candle_cnt == 0
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe' and candle_cnt == candle_last - 1
        showTrace := true
        showTrace
    candle_htf5.CandleUpdateTime(candle_offset)
    candle_htf5.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()
    candle_cnt := candle_cnt + 1
    candle_offset := candle_offset + (candle_cnt > 0 ? candle_htf5.candles.size() * candle_settings.width + (candle_htf5.candles.size() > 0 ? (candle_htf5.candles.size() - 1) * candle_settings.buffer : 0) + candle_settings.htf_buffer : 0)
    candle_offset
if candle_htf6.settings.show and candle_helper.CandleValidTimeframe(candle_htf6.settings.htf) and candle_cnt < candle_last
    bool showTrace = false
    if candle_settings.trace_anchor == 'First Timeframe' and candle_cnt == 0
        showTrace := true
        showTrace
    if candle_settings.trace_anchor == 'Last Timeframe'
        showTrace := true
        showTrace
    candle_htf6.CandleUpdateTime(candle_offset)
    candle_htf6.CandleMonitor().CandleUpdate(candle_offset, showTrace).CandleFindImbalance()

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Order Flow
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
type OFSettings
    string liquidity_open_style
    string liquidity_claimed_style

    string ST_label
    string IT_label
    string LT_label

    bool ST_show
    string ST_text_size
    color ST_color_bull
    color ST_color_bear
    color ST_label_color
    bool ST_liquidity_show
    color ST_liquidity_open_color
    int ST_liquidity_size
    color ST_liquidity_claimed_color

    bool IT_show
    string IT_text_size
    color IT_color_bull
    color IT_color_bear
    color IT_label_color
    bool IT_liquidity_show
    color IT_liquidity_open_color
    int IT_liquidity_size
    color IT_liquidity_claimed_color

    bool LT_show
    string LT_text_size
    color LT_color_bull
    color LT_color_bear
    color LT_label_color
    bool LT_liquidity_show
    color LT_liquidity_open_color
    int LT_liquidity_size
    color LT_liquidity_claimed_color

    int max_labels

    bool liquidity_open_show
    int max_lines
    int max_claimed_lines
    int extend

    bool EQ_show
    int EQ_max
    int EQ_max_claimed
    bool EQ_link_show
    color EQ_link_color
    string EQ_link_style
    int EQ_link_size
    bool EQ_line_extend
    color EQ_color_bull
    color EQ_color_bear
    string EQ_style
    string EQ_claimed_style

    int EQ_size
    bool EQ_shade
    color EQ_shade_bull
    color EQ_shade_bear

    int EQ_Tolerance

    bool displacement_show
    bool displacement_fvg
    int displacement_length
    int displacement_factor
    color displacement_bull
    color displacement_bear

type Pivot
    int index = 0
    int time = 0
    float price = 0
    int time_last = 0
    bool claimed = false
    bool isHigh = false
    bool isLow = false
    bool isSHigherHigh = false
    bool isSLowerLow = false
    bool isIHigherHigh = false
    bool isILowerLow = false
    bool isLHigherHigh = false
    bool isLLowerLow = false
    bool isST = true
    bool isIT = false
    bool isLT = false
    label lbl = na
    line ln = na

type MarketStructure
    string name
    array<Pivot> ST
    array<Pivot> STH
    array<Pivot> ITH
    array<Pivot> LTH
    array<Pivot> STL
    array<Pivot> ITL
    array<Pivot> LTL
    OFSettings settings

type EqualLevels
    float price
    float start
    float end
    int start_time
    int end_time
    int start_index
    int end_index
    bool isHigh
    bool isLow
    bool isClaimed
    int claimed_time
    line line_eq
    line line_link
    box box_link

//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
int MAX_BUFFER = 1000 // internal maximum node count limit for performance

Market_Structure_Group = 'Market Structure ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
Label_Format_Group = 'Label Format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'

settings_liquidity = 'Liquidity Levels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
settings_liquidity_style = 'Liquidity Style ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
settings_eq = 'Relative Equal Highs and Lows ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
settings_displacement = 'Displacement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
FVG_Group = 'Fair Value Gap ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
FVG_HP_Group = 'For High Probability Fair Value Gap ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
Imb_Group = 'Volume Imbalance ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'
Gap_Group = 'Open Gaps ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'

inline_st = 'ST'
inline_st_liquidity = 'ST liquidity'

inline_it = 'IT'
inline_it_liquidity = 'IT liquidity'
inline_lt = 'LT'
inline_lt_liquidity = 'LT liquidity'

inline_liquidity_open = 'open liquidity'
inline_liquidity_claimed = 'claimed liquidity'

inline_eq = 'EQ'
inline_eq_link = 'EQ Link'
inline_eq_shade = 'EQ Shade'
inline_displacement = 'displacement'

OFSettings Trend_Settings = OFSettings.new()

Trend_Settings.ST_show := input.bool(false, 'Short', group = Market_Structure_Group, inline = inline_st)
Trend_Settings.ST_color_bull := input.color(color.black, '', group = Market_Structure_Group, inline = inline_st)
Trend_Settings.ST_color_bear := input.color(color.black, '', group = Market_Structure_Group, inline = inline_st)
Trend_Settings.ST_label_color := input.color(TRANSPARENT_COLOR, '', group = Market_Structure_Group, inline = inline_st)

Trend_Settings.IT_show := input.bool(false, 'Intermediate', group = Market_Structure_Group, inline = inline_it)
Trend_Settings.IT_color_bull := input.color(color.new(AQUA_COLOR, 0), '', group = Market_Structure_Group, inline = inline_it)
Trend_Settings.IT_color_bear := input.color(color.new(AQUA_COLOR, 0), '', group = Market_Structure_Group, inline = inline_it)
Trend_Settings.IT_label_color := input.color(TRANSPARENT_COLOR, '', group = Market_Structure_Group, inline = inline_it)

Trend_Settings.LT_show := input.bool(false, 'Long', group = Market_Structure_Group, inline = inline_lt)
Trend_Settings.LT_color_bull := input.color(color.new(PURPLE_COLOR, 0), '', group = Market_Structure_Group, inline = inline_lt)
Trend_Settings.LT_color_bear := input.color(color.new(PURPLE_COLOR, 0), '', group = Market_Structure_Group, inline = inline_lt)
Trend_Settings.LT_label_color := input.color(TRANSPARENT_COLOR, '', group = Market_Structure_Group, inline = inline_lt)

Trend_Settings.ST_label := input.string('High/Low', 'Short', options = ['■', '□', '▣', '◆', '◇', '◈', '●', '○', '◉', '▲▼', '△▽', '↑↓', 'S/I/L Term', 'High/Low'], group = Label_Format_Group, inline = '1')
Trend_Settings.ST_text_size := input.string(size.tiny, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = Label_Format_Group, inline = '1')

Trend_Settings.IT_label := input.string('High/Low', 'Intermediate', options = ['■', '□', '▣', '◆', '◇', '◈', '●', '○', '◉', '▲▼', '△▽', '↑↓', 'S/I/L Term', 'High/Low'], group = Label_Format_Group, inline = '2')
Trend_Settings.IT_text_size := input.string(size.small, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = Label_Format_Group, inline = '2')
Trend_Settings.LT_label := input.string('High/Low', 'Long', options = ['■', '□', '▣', '◆', '◇', '◈', '●', '○', '◉', '▲▼', '△▽', '↑↓', 'S/I/L Term', 'High/Low'], group = Label_Format_Group, inline = '3')
Trend_Settings.LT_text_size := input.string(size.normal, '', [size.tiny, size.small, size.normal, size.large, size.huge], group = Label_Format_Group, inline = '3')

Trend_Settings.max_labels := input.int(50, 'Maximum number of labels', group = Label_Format_Group)

Trend_Settings.ST_liquidity_show := input.bool(false, 'Short', group = settings_liquidity, inline = inline_st_liquidity)
Trend_Settings.ST_liquidity_open_color := input.color(color.new(color.black, 50), '', group = settings_liquidity, inline = inline_st_liquidity)
Trend_Settings.ST_liquidity_claimed_color := input.color(color.new(color.black, 50), '', group = settings_liquidity, inline = inline_st_liquidity)
Trend_Settings.ST_liquidity_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_liquidity, inline = inline_st_liquidity)

Trend_Settings.IT_liquidity_show := input.bool(false, 'Intermediate', group = settings_liquidity, inline = inline_it_liquidity)
Trend_Settings.IT_liquidity_open_color := input.color(color.new(AQUA_COLOR, 60), '', group = settings_liquidity, inline = inline_it_liquidity)
Trend_Settings.IT_liquidity_claimed_color := input.color(color.new(AQUA_COLOR, 40), '', group = settings_liquidity, inline = inline_it_liquidity)
Trend_Settings.IT_liquidity_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_liquidity, inline = inline_it_liquidity)

Trend_Settings.LT_liquidity_show := input.bool(true, 'Long', group = settings_liquidity, inline = inline_lt_liquidity)
Trend_Settings.LT_liquidity_open_color := input.color(color.new(PURPLE_COLOR, 60), '', group = settings_liquidity, inline = inline_lt_liquidity)
Trend_Settings.LT_liquidity_claimed_color := input.color(color.new(PURPLE_COLOR, 40), '', group = settings_liquidity, inline = inline_lt_liquidity)
Trend_Settings.LT_liquidity_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_liquidity, inline = inline_lt_liquidity)

Trend_Settings.liquidity_open_style := input.string('⎯⎯⎯', 'Open', options = ['⎯⎯⎯', '----', '····'], group = settings_liquidity_style)
Trend_Settings.liquidity_claimed_style := input.string('----', 'Claimed', options = ['⎯⎯⎯', '----', '····'], group = settings_liquidity_style)
Trend_Settings.extend := input.int(2, title = 'Extend', minval = 1, group = settings_liquidity_style)
Trend_Settings.max_lines := input.int(50, 'Maximum number of lines', minval = 1, maxval = 250, group = settings_liquidity_style)
Trend_Settings.max_claimed_lines := input.int(5, 'Maximum number of claimed lines', minval = 0, maxval = 250, group = settings_liquidity_style)

Trend_Settings.EQ_show := input.bool(true, 'Equal Levels', group = settings_eq, inline = inline_eq)
Trend_Settings.EQ_color_bull := input.color(TRANSPARENT_COLOR, '', group = settings_eq, inline = inline_eq)
Trend_Settings.EQ_color_bear := input.color(TRANSPARENT_COLOR, '', group = settings_eq, inline = inline_eq)
Trend_Settings.EQ_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_eq, inline = inline_eq)

Trend_Settings.EQ_style := input.string('⎯⎯⎯', '', options = ['⎯⎯⎯', '----', '····'], group = settings_eq, inline = inline_eq)

Trend_Settings.EQ_link_show := input.bool(true, 'Link Levels', group = settings_eq, inline = inline_eq_link)
Trend_Settings.EQ_link_color := input.color(LIGHT_GRAY_COLOR, '', group = settings_eq, inline = inline_eq_link)
Trend_Settings.EQ_link_size := input.int(1, '', options = [1, 2, 3, 4], group = settings_eq, inline = inline_eq_link)
Trend_Settings.EQ_link_style := input.string('····', '', options = ['⎯⎯⎯', '----', '····'], group = settings_eq, inline = inline_eq_link)

Trend_Settings.EQ_shade := input.bool(true, 'Highlight', group = settings_eq, inline = inline_eq_shade)
Trend_Settings.EQ_shade_bull := input.color(color.new(AQUA_COLOR, 95), '', group = settings_eq, inline = inline_eq_shade)
Trend_Settings.EQ_shade_bear := input.color(color.new(PURPLE_COLOR, 90), '', group = settings_eq, inline = inline_eq_shade)
Trend_Settings.EQ_claimed_style := input.string('····', 'Claimed Style', options = ['⎯⎯⎯', '----', '····'], group = settings_eq)
Trend_Settings.EQ_Tolerance := input.int(2, 'Distance Tolerance', options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], group = settings_eq) / 10

Trend_Settings.EQ_max := input.int(20, 'Maximum number of Equal Levels', minval = 1, group = settings_eq)
Trend_Settings.EQ_max_claimed := input.int(5, 'Maximum number of Claimed Levels', minval = 1, group = settings_eq)

//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
Helper of_helper = Helper.new()

var MarketStructure Term = MarketStructure.new('Term')
var array<Pivot> ST_array = array.new<Pivot>()
var array<Pivot> IT_array = array.new<Pivot>()
var array<Pivot> LT_array = array.new<Pivot>()
var array<Pivot> STH_array = array.new<Pivot>()
var array<Pivot> ITH_array = array.new<Pivot>()
var array<Pivot> LTH_array = array.new<Pivot>()
var array<Pivot> STL_array = array.new<Pivot>()
var array<Pivot> ITL_array = array.new<Pivot>()
var array<Pivot> LTL_array = array.new<Pivot>()
Term.ST := ST_array
Term.STH := STH_array
Term.ITH := ITH_array
Term.LTH := LTH_array
Term.STL := STL_array
Term.ITL := ITL_array
Term.LTL := LTL_array
Term.settings := Trend_Settings

var array<EqualLevels> EQs = array.new<EqualLevels>()

var array<label> labels = array.new_label()
var array<EqualLevels> EQ_claimed = array.new<EqualLevels>()
var line tester = line.new(na, na, na, na, color = TRANSPARENT_COLOR)

body = math.abs(open - close)
std = ta.stdev(math.abs(open - close), Trend_Settings.displacement_length)

var array<float> median = array.new_float()
length = 14
median.unshift(ta.atr(length))
if median.size() > length
    median.pop()
float spacing = median.median() * Trend_Settings.EQ_Tolerance

//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------
// SkipEQHigh returns the first bar_index of before the equal highs
// This is used to compare pivot points, if two at equal levels
// then we need to compare it to previous high, otherwise it will
// not identify the right STH/STL
method SkipEQHigh(Helper helper, int idx) =>
    helper.name := 'Skip EQ Highs'
    i = idx
    while high[i] == high[i - 1]
        i := i + 1
        i
    i
    // SkipEQLows returns the first bar_index of before the equal lows
method SkipEQLow(Helper helper, int idx) =>
    helper.name := 'Skip EQ Lows'
    i = idx
    while low[i] == low[i - 1]
        i := i + 1
        i
    i

// Same as above, but works on pivot points. it also doesn't care for
// high or low since Pivot is a single price point
method SkipEQPivot(array<Pivot> p, int idx) =>
    i = idx
    if p.size() >= i
        while p.get(i).price == p.get(i - 1).price and p.size() <= i - 1
            i := i + 1
            i
    i

method OFAddEQ(array<EqualLevels> this, Pivot p1, Pivot p2) =>
    EqualLevels eq = EqualLevels.new()
    eq.start := p1.price
    eq.start_time := p1.time
    eq.start_index := p1.index
    eq.end := p2.price
    eq.end_time := p2.time
    eq.end_index := p2.index
    eq.isHigh := p1.isHigh
    eq.isLow := p1.isLow

    if Trend_Settings.EQ_show
        int start_time = 0
        if eq.isHigh
            eq.price := eq.start > eq.end ? eq.start : eq.end
            start_time := eq.start > eq.end ? eq.start_time : eq.end_time
            start_time
        else
            eq.price := eq.start < eq.end ? eq.start : eq.end
            start_time := eq.start < eq.end ? eq.start_time : eq.end_time
            start_time
        eq.line_eq := line.new(eq.start_time, eq.price, time, eq.price, xloc = xloc.bar_time, style = of_helper.LineStyle(Trend_Settings.EQ_style), color = eq.isHigh ? Trend_Settings.EQ_color_bull : Trend_Settings.EQ_color_bear, width = Trend_Settings.EQ_size)
        if Trend_Settings.EQ_link_show
            eq.line_link := line.new(eq.start_time, eq.start, eq.end_time, eq.end, xloc = xloc.bar_time, style = of_helper.LineStyle(Trend_Settings.EQ_link_style), color = Trend_Settings.EQ_link_color, width = Trend_Settings.EQ_link_size)
            eq.line_link
        if Trend_Settings.EQ_shade
            eq.box_link := box.new(eq.start_time, eq.start, eq.end_time, eq.end, xloc = xloc.bar_time, border_color = TRANSPARENT_COLOR, bgcolor = eq.isHigh ? Trend_Settings.EQ_shade_bull : Trend_Settings.EQ_shade_bear)
            eq.box_link
        this.unshift(eq)

        if this.size() > Trend_Settings.EQ_max + Trend_Settings.EQ_max_claimed
            EqualLevels t = this.pop()
            t.line_eq.delete()
            t.line_link.delete()
            t.box_link.delete()
    this

OFTestEQ(Pivot p1, Pivot p2) =>
    bool valid = true
    tester.set_xy1(p1.index, p1.price)
    tester.set_xy2(p2.index, p2.price)
    for i = p1.index + 1 to p2.index - 1 by 1
        bool isHigh = p1.isHigh
        float p = tester.get_price(i)
        int j = bar_index - i
        if isHigh and high[j] > p or not isHigh and low[j] < p
            valid := false
            valid
    valid

method OFProcessEQ(array<EqualLevels> this, Pivot p1, Pivot p2) =>
    bool matched = false
    for p in this
        if p.start_index == p1.index and not p.isClaimed

            if p.end <= p2.price and p.isHigh or p.end >= p2.price and p.isLow

                if OFTestEQ(p1, p2)
                    p.end := p2.price
                    p.end_time := p2.time
                    p.end_index := p2.index
                    p.line_link.set_xy2(p.end_time, p.end)
                    p.box_link.set_rightbottom(p.end_time, p.end)
            matched := true
            break
        if (p.end_index == p2.index or p.end_index == p1.index) and (p.isLow == p1.isLow or p.isLow == p2.isLow)
            matched := true
            break

    if not matched
        if OFTestEQ(p1, p2)
            this.OFAddEQ(p1, p2)
    this

method OFFindEQ(MarketStructure MS, Pivot pivot) =>
    if MS.settings.EQ_show or MS.settings.EQ_link_show

        if MS.ST.size() > 2
            for p in MS.ST
                if (p.isHigh and pivot.isHigh or p.isLow and pivot.isLow) and p.index != pivot.index

                    if math.abs(p.price - pivot.price) < spacing
                        EQs.OFProcessEQ(p, pivot)
    MS

method OfGetLabel(Pivot pivot) =>
    string lbl = ''
    if Trend_Settings.ST_show and pivot.isST and (not pivot.isIT or not Trend_Settings.IT_show) and (not pivot.isLT or not Trend_Settings.LT_show)
        switch Trend_Settings.ST_label
            'S/I/L Term' => 
                lbl := lbl + 'ST'
                lbl := lbl + (pivot.isHigh ? 'H' : 'L')
                lbl
            'High/Low' => 
                lbl := lbl + 'ST'
                lbl := lbl + (pivot.isHigh ? pivot.isSHigherHigh ? '-HH' : '-LH' : pivot.isSLowerLow ? '-LL' : '-HL')
                lbl
            => 
                if str.length(Trend_Settings.ST_label) == 1
                    lbl := Trend_Settings.ST_label
                    lbl
                else
                    array<string> symb = str.split(Trend_Settings.ST_label, '')
                    lbl := lbl + (pivot.isHigh ? symb.get(1) : symb.get(0))
                    lbl

    if Trend_Settings.IT_show and pivot.isIT and (not pivot.isLT or not Trend_Settings.LT_show)
        switch Trend_Settings.IT_label
            'S/I/L Term' => 
                lbl := lbl + 'IT'
                lbl := lbl + (pivot.isHigh ? 'H' : 'L')
                lbl
            'High/Low' => 
                lbl := lbl + 'IT'
                lbl := lbl + (pivot.isHigh ? pivot.isIHigherHigh ? '-HH' : '-LH' : pivot.isILowerLow ? '-LL' : '-HL')
                lbl
            => 
                if str.length(Trend_Settings.IT_label) == 1
                    lbl := Trend_Settings.IT_label
                    lbl
                else
                    array<string> symb = str.split(Trend_Settings.IT_label, '')
                    lbl := lbl + (pivot.isHigh ? symb.get(1) : symb.get(0))
                    lbl
    if Trend_Settings.LT_show and pivot.isLT
        switch Trend_Settings.LT_label
            'S/I/L Term' => 
                lbl := lbl + 'LT'
                lbl := lbl + (pivot.isHigh ? 'H' : 'L')
                lbl
            'High/Low' => 
                lbl := lbl + 'LT'
                lbl := lbl + (pivot.isHigh ? pivot.isLHigherHigh ? '-HH' : '-LH' : pivot.isLLowerLow ? '-LL' : '-HL')
                lbl
            => 
                if str.length(Trend_Settings.LT_label) == 1
                    lbl := Trend_Settings.LT_label
                    lbl
                else
                    array<string> symb = str.split(Trend_Settings.LT_label, '')
                    lbl := lbl + (pivot.isHigh ? symb.get(1) : symb.get(0))
                    lbl
    lbl

// Calculates and returns the Pivot Point settings
// based on what is configured in the properties window
method OFGetLabelSettings(MarketStructure MS, Pivot pivot) =>
    color lbl_color = na
    string lbl_text_size = na
    color txt_color = na
    string lbl_style = na

    if MS.settings.ST_show
        lbl_color := MS.settings.ST_label_color
        lbl_text_size := MS.settings.ST_text_size
        txt_color := pivot.isHigh ? MS.settings.ST_color_bull : MS.settings.ST_color_bear
        txt_color

    if MS.settings.IT_show
        if pivot.isIT
            lbl_color := MS.settings.IT_label_color
            lbl_text_size := MS.settings.IT_text_size
            txt_color := pivot.isHigh ? MS.settings.IT_color_bull : MS.settings.IT_color_bear
            txt_color

    if MS.settings.LT_show
        if pivot.isLT
            lbl_color := MS.settings.LT_label_color
            lbl_text_size := MS.settings.LT_text_size
            txt_color := pivot.isHigh ? MS.settings.LT_color_bull : MS.settings.LT_color_bear
            txt_color

    if MS.settings.ST_show or MS.settings.IT_show or MS.settings.LT_show
        lbl_style := pivot.isHigh ? label.style_label_down : label.style_label_up
        lbl_style

    [lbl_color, lbl_text_size, txt_color, lbl_style, pivot.OfGetLabel()]

// Displays the Pivot label with the proper settings. it is used for both adding the initial
// Pivot and renaming/adjusting it if it is converted from STH to ITH for example
method OFDrawLabel(MarketStructure MS, Pivot pivot) =>
    [lbl_color, lbl_text_size, txt_color, lbl_style, lbl] = MS.OFGetLabelSettings(pivot)
    if na(pivot.lbl)
        pivot.lbl := label.new(pivot.time, pivot.price, xloc = xloc.bar_time, color = lbl_color, size = lbl_text_size, textcolor = txt_color, style = lbl_style, text = lbl)
    else
        label.set_style(pivot.lbl, lbl_style)
        label.set_color(pivot.lbl, lbl_color)
        label.set_size(pivot.lbl, lbl_text_size)
        label.set_textcolor(pivot.lbl, txt_color)
        label.set_text(pivot.lbl, lbl)
    MS

// Adds the liquidity lines
method OFDrawLiquidity(MarketStructure MS, Pivot pivot) =>
    color liquidity_open_color = pivot.isLT and MS.settings.LT_liquidity_show ? MS.settings.LT_liquidity_open_color : pivot.isIT and MS.settings.IT_liquidity_show ? MS.settings.IT_liquidity_open_color : MS.settings.ST_liquidity_open_color
    color liquidity_claimed_color = pivot.isLT and MS.settings.LT_liquidity_show ? MS.settings.LT_liquidity_claimed_color : pivot.isIT and MS.settings.IT_liquidity_show ? MS.settings.IT_liquidity_claimed_color : MS.settings.ST_liquidity_claimed_color
    int liquidity_size = pivot.isLT and MS.settings.LT_liquidity_show ? MS.settings.LT_liquidity_size : pivot.isIT and MS.settings.IT_liquidity_show ? MS.settings.IT_liquidity_size : MS.settings.ST_liquidity_size

    if MS.settings.ST_liquidity_show or MS.settings.IT_liquidity_show and pivot.isIT or MS.settings.LT_liquidity_show and pivot.isLT
        if na(pivot.ln)
            pivot.ln := line.new(pivot.time, pivot.price, pivot.claimed ? pivot.time_last : time + (time - time[1]) * MS.settings.extend, pivot.price, xloc = xloc.bar_time, style = of_helper.LineStyle(pivot.claimed ? MS.settings.liquidity_claimed_style : MS.settings.liquidity_open_style), color = pivot.claimed ? liquidity_claimed_color : liquidity_open_color, width = liquidity_size)
            pivot.ln
        else
            line.set_color(pivot.ln, pivot.claimed ? liquidity_claimed_color : liquidity_open_color)
            line.set_width(pivot.ln, liquidity_size)
            line.set_x2(pivot.ln, pivot.claimed ? pivot.time_last : time + (time - time[1]) * MS.settings.extend)
            line.set_style(pivot.ln, of_helper.LineStyle(pivot.claimed ? MS.settings.liquidity_claimed_style : MS.settings.liquidity_open_style))
    MS

// Handles the addition of newly discovered ST[H/L] Pivot Point
method OFAddMS(MarketStructure MS, float p_price, int p_time, int p_index, bool isHigh) =>
    Pivot pivot = Pivot.new()
    pivot.price := p_price
    pivot.time := p_time
    pivot.isST := true
    pivot.index := p_index

    MS.ST.unshift(pivot)

    if isHigh
        pivot.isHigh := true
        if MS.STH.size() > 0
            Pivot p = MS.STH.first()
            if p.price <= p_price
                pivot.isSHigherHigh := true
                pivot.isSHigherHigh
        MS.STH.unshift(pivot)
    else
        pivot.isLow := true
        if MS.STL.size() > 0
            Pivot p = MS.STL.first()
            if p.price >= p_price
                pivot.isSLowerLow := true
                pivot.isSLowerLow
        MS.STL.unshift(pivot)
    MS.OFFindEQ(pivot)

    if MS.ST.size() > MAX_BUFFER
        Pivot temp = MS.ST.pop()
        line.delete(temp.ln)
        label.delete(temp.lbl)

    MS

// Rechecks the Pivot points and renames the Pivot point from ST to IT
method OFFindIT(MarketStructure MS) =>
    if MS.STH.size() > 3
        h1 = MS.STH.first()
        h2 = MS.STH.get(1)
        h3 = MS.STH.get(MS.STH.SkipEQPivot(2))
        if h2.price > h3.price and h2.price > h1.price and not h2.isIT
            h2.isIT := true
            if MS.ITH.size() > 0
                Pivot p = MS.ITH.first()
                if p.price <= h2.price
                    h2.isIHigherHigh := true
                    h2.isIHigherHigh
            MS.ITH.unshift(h2)

    if MS.STL.size() > 2
        l1 = MS.STL.first()
        l2 = MS.STL.get(1)
        l3 = MS.STL.get(MS.STL.SkipEQPivot(2))
        if l2.price < l3.price and l2.price < l1.price and not l2.isIT
            l2.isIT := true
            if MS.ITL.size() > 0
                Pivot p = MS.ITL.first()
                if p.price >= l2.price
                    l2.isILowerLow := true
                    l2.isILowerLow
            MS.ITL.unshift(l2)
    MS

// Rechecks the IT Pivot points and renames the Pivot point from IT to LT
method OFFindLT(MarketStructure MS) =>
    if MS.ITH.size() > 2
        h1 = MS.ITH.first()
        h2 = MS.ITH.get(1)
        h3 = MS.ITH.get(2)
        if h2.price > h3.price and h2.price > h1.price and not h2.isLT
            h2.isLT := true

            if MS.LTH.size() > 0
                Pivot p = MS.LTH.first()
                if p.price <= h2.price
                    h2.isLHigherHigh := true
                    h2.isLHigherHigh

            MS.LTH.unshift(h2)

    if MS.ITL.size() > 2
        l1 = MS.ITL.first()
        l2 = MS.ITL.get(1)
        l3 = MS.ITL.get(MS.ITL.SkipEQPivot(2))

        if l2.price < l3.price and l2.price < l1.price and not l2.isLT
            l2.isLT := true

            if MS.LTL.size() > 0
                Pivot p = MS.LTL.first()
                if p.price >= l2.price
                    l2.isLLowerLow := true
                    l2.isLLowerLow

            MS.LTL.unshift(l2)
    MS

// Checks for ST[H/L] and calls the Add method
method OFFindST(MarketStructure MS) =>
    h = high[1] > high[of_helper.SkipEQHigh(2)] and high[1] > high
    l = low[1] < low[of_helper.SkipEQLow(2)] and low[1] < low

    if h
        MS.OFAddMS(high[1], time[1], bar_index[1], true)
    if l
        MS.OFAddMS(low[1], time[1], bar_index[1], false)
    MS

// Checks if liquidity has been swept
method OFCheckClaimed(MarketStructure MS) =>
    Pivot claimed = na
    if MS.ST.size() > 0
        for i = MS.ST.size() - 1 to 0 by 1
            pivot = MS.ST.get(i)
            if not pivot.claimed
                if pivot.isHigh and high > pivot.price or pivot.isLow and low < pivot.price
                    pivot.claimed := true
                    pivot.time_last := time
                    pivot.time_last
    for eq in EQs
        if not eq.isClaimed
            if eq.isHigh
                eq.isClaimed := high > eq.price
                eq.isClaimed
            if eq.isLow
                eq.isClaimed := low < eq.price
                eq.isClaimed
            if eq.isClaimed
                eq.claimed_time := time
                EQ_claimed.unshift(eq)

                if EQ_claimed.size() > Trend_Settings.EQ_max_claimed
                    EqualLevels t = EQ_claimed.pop()
                    t.line_eq.delete()
                    t.line_link.delete()
                    t.box_link.delete()

            if not na(eq.line_eq)
                if not eq.isClaimed
                    eq.line_eq.set_x2(time + (time - time[1]) * MS.settings.extend)
                else 
                    eq.line_eq.set_x2(time)
                    eq.line_eq.set_style(of_helper.LineStyle(Trend_Settings.EQ_claimed_style))
    claimed

method OFRenderMS(MarketStructure MS) =>
    int add = 0
    int claim = 0
    for pivot in MS.ST
        if pivot.claimed and claim < MS.settings.max_claimed_lines or not pivot.claimed and add < MS.settings.max_lines
            MS.OFDrawLiquidity(pivot)
            if pivot.claimed
                claim := claim + 1
                claim
            else
                add := add + 1
                add
        if claim == MS.settings.max_claimed_lines and add == MS.settings.max_lines
            break
    add := 0

    for pivot in MS.ST
        if MS.settings.ST_show or MS.settings.IT_show and pivot.isIT or MS.settings.LT_show and pivot.isLT and add < MS.settings.max_labels
            MS.OFDrawLabel(pivot)
            add := add + 1
        if add == MS.settings.max_labels
            break

//-----------------------------------------------------------------------------
// Process
//-----------------------------------------------------------------------------
if last_bar_index - bar_index < 1000
    if barstate.isconfirmed
        Term.OFFindST().OFFindIT().OFFindLT()
        Term.OFCheckClaimed()

    if barstate.islast
        Term.OFRenderMS()

//-----------------------------------------------------------------------------

Overview

SMC scans across up to six user-selected higher timeframes—ranging from intraday minutes to daily and weekly intervals—to identify bullish and bearish imbalance zones. The script draws boundary boxes, consequent encroachment midpoints, and tracks zone mitigation. Users can toggle individual timeframes, customize bullish and bearish colors, and adjust display limits. Because it requests higher-timeframe data with lookahead enabled, historical zones can reflect future price information.

Details

Published by

TamTH-Dev on GitHub

Code credit

tamth_, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

SMC / ICT / price action, Support & resistance

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
showbooltrueshow
htf_1timeframe5htf_1
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint20max_count
showbooltrueshow
htf_2timeframe15htf_2
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint20max_count
showbooltrueshow
htf_3timeframe60htf_3
Show all 40 settings
SettingTypeDefaultVariable
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint20max_count
showbooltrueshow
htf_4timeframe240htf_4
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint10max_count
showbooltrueshow
htf_5timeframe1Dhtf_5
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint10max_count
showbooltrueshow
htf_6timeframe1Whtf_6
color_bullcolorcolor.new(GREEN_COLOR, 25)color_bull
color_bearcolorcolor.new(RED_COLOR, 25)color_bear
max_countint2max_count
Limit to next HTFs onlyint6max_sets
Hide Lower Timeframesbooltrueltf_hide
Hide Current Timeframebooltruectf_hide
Background Transparencyboolfalsefill
Extend linesstringWhen in Rangeextendby
Distance from current candleint4extend
Spacing between timeframesint4buffer
fill_percentint50fill_percent
Mitigatedboolfalsemitigated_show
mitigated_color_bullcolorcolor.new(DARK_GRAY_COLOR, 60)mitigated_color_bull
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows

DE-tracker

by Allen1212
303 stars

This indicator plots labels on the TradingView price chart to mark ARK Invest's buy and sell trades for the DE stock. Buy transactions appear in green with X1 or X2 multipliers showing the number of ARK ETFs involved on the same day; sells appear in red. The m

Indicator v4 Support & resistanceSMC / ICT / price action
Updated 2 years ago · None stated GitHub repository of DE-tracker

This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm

Indicator v4 TrendSupport & resistance

Golden Bullet Strategy

by TradersPost
218 stars

The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy

Open Source Fractal

by cantolab
183 stars

This indicator implements the Fractal Model concept to plot market structure shifts, liquidity sweeps, and Change in State of Delivery (CISD) levels. It overlays custom higher-timeframe candle previews, open prices, and time markers directly on the price chart

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · MIT GitHub repository of Open Source Fractal

Swing Failure Signals

by Ganador1
154 stars

This indicator calculates pivot highs and pivot lows to detect liquidity sweeps and Swing Failure Patterns. It identifies when price breaks past recent key swing highs or lows within a configurable historical window, then looks for a quick reversal or change i

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · Apache-2.0 GitHub repository of Swing Failure Signals

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers