Indicator · Pine Script v6 · On the chart

MTF market analysis toolkit

by TamaraKGreen· code credited to notprofessorgreen

This indicator draws higher-timeframe candles on the price chart so traders can compare a larger timeframe with the current bars.

View on GitHub

Repaints

GitHub stars46on the repository
Pine versionv6current
Lines of code1,012
Settings40inputs
LicenceNone statedfile: MPL-2.0
Last update7 weeks ago4 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

1,012 lines of Pine Script v6 from MTF HTF market analysis toolkit.txt, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

MTF HTF market analysis toolkit.txt
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © notprofessorgreen

//@version=6
indicator('MTF market analysis toolkit', shorttitle = 'HTF', overlay = true, max_bars_back = 500, max_boxes_count = 500, max_lines_count = 500, dynamic_requests = true)

// Inputs
var tf = input.timeframe('60', 'HTF Timeframe Candle Time', inline = 'tf', group = 'HTF Candle Settings')
var tf_auto = input.bool(false, 'Set Automatically', inline = 'tf', group = 'HTF Candle Settings')
var tf_2lvs = input.bool(true, 'Two Levels', inline = 'tf', group = 'HTF Candle Settings')
var num = input.int(4, 'Number of HTF Candles', minval = 1, group = 'HTF Candle Settings')
var offset = input.int(20, 'Offset', group = 'HTF Candle Settings')
var size = input.string('Small', 'Size', options = ['Small', 'Medium', 'Large'], group = 'HTF Candle Settings')
var type = input.string('Candles', 'Type', options = ['Candles', 'Heikin Ashi'], group = 'HTF Candle Settings')
var margin = input.int(1, 'Margin', minval = 1, group = 'HTF Candle Settings')
var htf_data = input.string('Is Weekly', 'Use HTF data to generate candles', options = ['Is Weekly', 'Always', 'Never'], group = 'HTF Candle Settings')

// Inputs for stats table
var stats_table_enabled = input.bool(true, 'Show Stats Table', group = 'HTF Candle Settings: Timeframe Box Stats')
var stats_table_position = input.string('Bottom Left', 'Stats Table Position', options=['Top Right', 'Top Left', 'Bottom Right', 'Bottom Left', 'Top Center', 'Bottom Center'], group='HTF Candle Settings: Timeframe Box Stats')

var up_col = input.color(color.rgb(5, 168, 68, 50), 'Body', inline = 'Candles', group = 'HTF Candles: Up Candles')
var up_col_wick = input.color(color.black, 'Wick', inline = 'Candles', group = 'HTF Candles: Up Candles')
var up_col_border = input.color(color.black, 'Border', inline = 'Candles', group = 'HTF Candles: Up Candles')
var down_col = input.color(color.black, 'Body', inline = 'Candles', group = 'HTF Candles: Down Candles')
var down_col_wick = input.color(color.black, 'Wick', inline = 'Candles', group = 'HTF Candles: Down Candles')
var down_col_border = input.color(color.black, 'Border', inline = 'Candles', group = 'HTF Candles: Down Candles')

// Low line inputs
var low_line_enabled = input.bool(true, 'Show Lowest HTF Low Line', group = 'HTF Candles: Low Line')
var low_line_col = input.color(color.black, 'Color', inline = 'low_line', group = 'HTF Candles: Low Line')
var low_line_style = input.string('Solid', 'Style', options = ['Solid', 'Dotted', 'Dashed'], inline = 'low_line', group = 'HTF Candles: Low Line')
var low_line_width = input.int(1, 'Width', minval = 1, inline = 'low_line', group = 'HTF Candles: Low Line')

// High Line Inputs
var high_line_enabled = input.bool(true, 'Show Highest HTF High Line', group = 'HTF Candles: High Line')
var high_line_col = input.color(color.black, 'Color', inline = 'high_line', group = 'HTF Candles: High Line')
var high_line_style = input.string('Solid', 'Style', options = ['Solid', 'Dotted', 'Dashed'], inline = 'high_line', group = 'HTF Candles: High Line')
var high_line_width = input.int(1, 'Width', minval = 1, inline = 'high_line', group = 'HTF Candles: High Line')

// Midpoint Line Inputs
var mid_line_enabled = input.bool(true, 'Show HTF Midpoint Line', group = 'HTF Candles: Midpoint Line')
var mid_line_col = input.color(color.teal, 'Color', inline = 'mid_line', group = 'HTF Candles: Midpoint Line')
var mid_line_style = input.string('Dotted', 'Style', options = ['Solid', 'Dotted', 'Dashed'], inline = 'mid_line', group = 'HTF Candles: Midpoint Line')
var mid_line_width = input.int(1, 'Width', minval = 1, inline = 'mid_line', group = 'HTF Candles: Midpoint Line')

// Timeframe box
var tfbox_enabled = input.bool(true, 'Show Timeframe Box', group = 'HTF Candles: Timeframe Box')
var tfbox_border_col = input.color(color.rgb(120, 123, 134, 50), 'Border Color', inline = 'tfbox', group = 'HTF Candles: Timeframe Box')
var tfbox_bg_col = input.color(color.rgb(120, 123, 134, 50), 'Background Color', inline = 'tfbox', group = 'HTF Candles: Timeframe Box')
var tfbox_price_mode = input.string('Open to Midpoint', 'Price Range', options = ['Open to Midpoint', 'High to Low'], inline = 'tfbox', group = 'HTF Candles: Timeframe Box')

//OHLC lines
var proj_enabled = input.bool(true, 'Show OHLC Lines', group = 'HTF Candles: OHLC Projections')
var proj_o_col = input.color(color.gray, 'Open', inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_h_col = input.color(color.gray, 'High', inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_l_col = input.color(color.gray, 'Low', inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_c_col = input.color(color.gray, 'Close', inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_style = input.string('Dashed', 'Style', options = ['Solid', 'Dotted', 'Dashed'], inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_width = input.int(1, 'Width', minval = 1, inline = 'proj', group = 'HTF Candles: OHLC Projections')
var proj_extend = input.int(50, 'Extend Bars', minval = 0, group = 'HTF Candles: OHLC Projections')
var label_enabled = input.bool(false, 'Show Labels', group = 'HTF Candles: OHLC Projections')

// Timeframe separators
var vert_enabled = input.bool(true, 'Show Timeframe Start Vertical Lines', group = 'HTF time separators: Vertical Lines')
var vert_col = input.color(color.gray, 'Color', inline = 'vert', group = 'HTF time separators: Vertical Lines')
var vert_style = input.string('Dotted', 'Style', options = ['Solid', 'Dotted', 'Dashed'], inline = 'vert', group = 'HTF time separators: Vertical Lines')
var vert_width = input.int(1, 'Width', minval = 1, inline = 'vert', group = 'HTF time separators: Vertical Lines')

type Candle
    box body
    line upperWick
    line lowerWick
    line lowLine
    line highLine
    line midLine
    int start_bar
    float openPrice
    float highPrice
    float lowPrice
    float closePrice
    box midpointBox
    line o
    line h
    line l
    line c
    label labelO
    label labelH
    label labelL
    label labelC
    line vertLine

getAutoTimeframe(s, m5, m15, m60, m240, m, d, w, q, y) =>
    timeframe.isseconds ? s : timeframe.isminutes ? timeframe.multiplier < 5 ? m5 : timeframe.multiplier < 15 ? m15 : timeframe.multiplier < 60 ? m60 : timeframe.multiplier < 240 ? m240 : m : timeframe.isdaily ? d : timeframe.isweekly ? w : timeframe.ismonthly and timeframe.multiplier < 6 ? q : y

determineAutoTimeframe() =>
    if tf_2lvs
        getAutoTimeframe('5', '15', '60', '240', '1D', '1W', '1M', '3M', '12M', '12M')
    else
        getAutoTimeframe('1', '5', '15', '60', '240', '1D', '1W', '1M', '3M', '12M')

getSizeMultiplier() =>
    result = switch size
        'Small' => 1
        'Medium' => 2
        'Large' => 3
    result

getLineStyle(style) =>
    result = switch style
        'Solid' => line.style_solid
        'Dotted' => line.style_dotted
        'Dashed' => line.style_dashed
    result

getChartPriceRange(array<Candle> candles_array) =>
    var float max_high = na
    var float min_low = na
    for candle in candles_array
        if not na(candle.highPrice) and (na(max_high) or candle.highPrice > max_high)
            max_high := candle.highPrice
            max_high
        if not na(candle.lowPrice) and (na(min_low) or candle.lowPrice < min_low)
            min_low := candle.lowPrice
            min_low
    [max_high, min_low]

var maxIndex = num - 1
var curr_tf = tf_auto ? determineAutoTimeframe() : tf
var useHtfData = timeframe.isweekly and htf_data == 'Is Weekly' or htf_data == 'Always'
var sizeMultiplier = getSizeMultiplier()
newCandle = ta.change(time(curr_tf)) != 0
var initialized_candles = 0

ohlc() =>
    [htf_o, htf_h, htf_l, htf_c] = request.security(syminfo.tickerid, curr_tf, [open, high, low, close], lookahead = barmerge.lookahead_on)
    var o = 0.
    var h = 0.
    var l = 0.
    c = close
    if newCandle
        o := open
        h := high
        l := low
        l
    else
        h := math.max(high, h)
        l := math.min(low, l)
        l
    [o, h, l, c, htf_o, htf_h, htf_l, htf_c]

getCandlePostion(l_pos) =>
    m_pos = l_pos + sizeMultiplier
    r_pos = l_pos + sizeMultiplier * 2
    [m_pos, r_pos]

createProjections(Candle candle, o, h, l, c, curr_o, curr_h, curr_l, curr_c, htf_o, htf_h, htf_l, htf_c, l_pos, array<Candle> candles_array) =>
    [m_pos, r_pos] = getCandlePostion(l_pos)
    if proj_enabled
        candle.o := line.new(bar_index, curr_o, bar_index + proj_extend, curr_o, style = getLineStyle(proj_style), color = proj_o_col, width = proj_width)
        candle.h := line.new(bar_index, curr_h, bar_index + proj_extend, curr_h, style = getLineStyle(proj_style), color = proj_h_col, width = proj_width)
        candle.l := line.new(bar_index, curr_l, bar_index + proj_extend, curr_l, style = getLineStyle(proj_style), color = proj_l_col, width = proj_width)
        candle.c := line.new(bar_index, curr_c, bar_index + proj_extend, curr_c, style = getLineStyle(proj_style), color = proj_c_col, width = proj_width)
        if label_enabled
            candle.labelO := label.new(bar_index, curr_o, 'O: ' + str.tostring(curr_o, format.mintick), style = label.style_label_down, color = proj_o_col, textcolor = color.white)
            candle.labelH := label.new(bar_index, curr_h, 'H: ' + str.tostring(curr_h, format.mintick), style = label.style_label_down, color = proj_h_col, textcolor = color.white)
            candle.labelL := label.new(bar_index, curr_l, 'L: ' + str.tostring(curr_l, format.mintick), style = label.style_label_up, color = proj_l_col, textcolor = color.white)
            candle.labelC := label.new(bar_index, curr_c, 'C: ' + str.tostring(curr_c, format.mintick), style = label.style_label_up, color = proj_c_col, textcolor = color.white)
            candle.labelC
    if vert_enabled
        [max_high, min_low] = getChartPriceRange(candles_array)
        if not na(max_high) and not na(min_low)
            candle.vertLine := line.new(candle.start_bar, max_high, candle.start_bar, min_low, style = getLineStyle(vert_style), color = vert_col, width = vert_width)
            candle.vertLine

moveProjections(Candle candle, l_pos, o, h, l, c, curr_o, curr_h, curr_l, curr_c, array<Candle> candles_array) =>
    [m_pos, r_pos] = getCandlePostion(l_pos)
    if proj_enabled
        if not na(candle.o)
            candle.o.set_xy1(bar_index, curr_o)
            candle.o.set_xy2(bar_index + proj_extend, curr_o)
        if not na(candle.h)
            candle.h.set_xy1(bar_index, curr_h)
            candle.h.set_xy2(bar_index + proj_extend, curr_h)
        if not na(candle.l)
            candle.l.set_xy1(bar_index, curr_l)
            candle.l.set_xy2(bar_index + proj_extend, curr_l)
        if not na(candle.c)
            candle.c.set_xy1(bar_index, curr_c)
            candle.c.set_xy2(bar_index + proj_extend, curr_c)
        if label_enabled
            if not na(candle.labelO)
                candle.labelO.set_xy(bar_index, curr_o)
                candle.labelO.set_text('O: ' + str.tostring(curr_o, format.mintick))
            if not na(candle.labelH)
                candle.labelH.set_xy(bar_index, curr_h)
                candle.labelH.set_text('H: ' + str.tostring(curr_h, format.mintick))
            if not na(candle.labelL)
                candle.labelL.set_xy(bar_index, curr_l)
                candle.labelL.set_text('L: ' + str.tostring(curr_l, format.mintick))
            if not na(candle.labelC)
                candle.labelC.set_xy(bar_index, curr_c)
                candle.labelC.set_text('C: ' + str.tostring(curr_c, format.mintick))
    if vert_enabled and not na(candle.vertLine)
        [max_high, min_low] = getChartPriceRange(candles_array)
        if not na(max_high) and not na(min_low)
            candle.vertLine.set_xy1(candle.start_bar, max_high)
            candle.vertLine.set_xy2(candle.start_bar, min_low)

deleteProjections(Candle candle) =>
    if not na(candle.o)
        candle.o.delete()
    if not na(candle.h)
        candle.h.delete()
    if not na(candle.l)
        candle.l.delete()
    if not na(candle.c)
        candle.c.delete()
    if not na(candle.labelO)
        candle.labelO.delete()
    if not na(candle.labelH)
        candle.labelH.delete()
    if not na(candle.labelL)
        candle.labelL.delete()
    if not na(candle.labelC)
        candle.labelC.delete()
    if not na(candle.vertLine)
        candle.vertLine.delete()

getCandleProperties(o, h, l, c) =>
    h_body = math.max(o, c)
    l_body = math.min(o, c)
    body_col = o > c ? down_col : up_col
    wick_col = o > c ? down_col_wick : up_col_wick
    border_col = o > c ? down_col_border : up_col_border
    [h_body, l_body, body_col, wick_col, border_col]

createCandle(l_pos, o, h, l, c, curr_tf) =>
    [m_pos, r_pos] = getCandlePostion(l_pos)
    [h_body, l_body, body_col, wick_col, border_col] = getCandleProperties(o, h, l, c)
    candle = Candle.new()
    candle.body := box.new(l_pos, h_body, r_pos, l_body, border_col, bgcolor = body_col)
    candle.upperWick := line.new(m_pos, h_body, m_pos, h, color = wick_col)
    candle.lowerWick := line.new(m_pos, l_body, m_pos, l, color = wick_col)
    candle.start_bar := bar_index
    candle.openPrice := o
    candle.highPrice := h
    candle.lowPrice := l
    candle.closePrice := c
    candle

moveCandle(Candle candle, l_pos) =>
    [m_pos, r_pos] = getCandlePostion(l_pos)
    candle.body.set_left(l_pos)
    candle.body.set_right(r_pos)
    candle.upperWick.set_x1(m_pos)
    candle.upperWick.set_x2(m_pos)
    candle.lowerWick.set_x1(m_pos)
    candle.lowerWick.set_x2(m_pos)

updateCandle(Candle candle, l_pos, o, h, l, c, curr_tf, is_current) =>
    [m_pos, r_pos] = getCandlePostion(l_pos)
    [h_body, l_body, body_col, wick_col, border_col] = getCandleProperties(o, h, l, c)
    candle.body.set_bgcolor(body_col)
    candle.body.set_lefttop(l_pos, h_body)
    candle.body.set_rightbottom(r_pos, l_body)
    candle.body.set_border_color(border_col)
    candle.upperWick.set_color(wick_col)
    candle.upperWick.set_xy1(m_pos, h_body)
    candle.upperWick.set_xy2(m_pos, h)
    candle.lowerWick.set_color(wick_col)
    candle.lowerWick.set_xy1(m_pos, l_body)
    candle.lowerWick.set_xy2(m_pos, l)
    if is_current
        candle.openPrice := o
        candle.highPrice := h
        candle.lowPrice := l
        candle.closePrice := c
        if tfbox_enabled
            var float box_top = na
            var float box_bottom = na
            if tfbox_price_mode == 'Open to Midpoint'
                [prev_open, prev_close] = request.security(syminfo.tickerid, curr_tf, [open[1], close[1]], lookahead = barmerge.lookahead_on)
                prev_open := nz(prev_open, o)
                prev_close := nz(prev_close, c)
                prev_body_midpoint = (prev_open + prev_close) / 2
                box_top := math.max(o, prev_body_midpoint)
                box_bottom := math.min(o, prev_body_midpoint)
                box_bottom
            else
                box_top := h
                box_bottom := l
                box_bottom
            if na(candle.midpointBox)
                candle.midpointBox := box.new(candle.start_bar, box_top, bar_index, box_bottom, border_color = tfbox_border_col, bgcolor = tfbox_bg_col)
                candle.midpointBox
            else
                candle.midpointBox.set_lefttop(candle.start_bar, box_top)
                candle.midpointBox.set_rightbottom(bar_index, box_bottom)
                candle.midpointBox.set_border_color(tfbox_border_col)
                candle.midpointBox.set_bgcolor(tfbox_bg_col)
    else
        if not na(candle.midpointBox)
            candle.midpointBox.delete()
            candle.midpointBox := na
            candle.midpointBox
    candle

deleteCandle(Candle candle) =>
    candle.body.delete()
    candle.upperWick.delete()
    candle.lowerWick.delete()
    if not na(candle.lowLine)
        candle.lowLine.delete()
    if not na(candle.highLine)
        candle.highLine.delete()
    if not na(candle.midLine)
        candle.midLine.delete()
    if not na(candle.midpointBox)
        candle.midpointBox.delete()
    deleteProjections(candle)

var candles = array.new<Candle>(num, Candle.new())
[o, h, l, c, htf_o, htf_h, htf_l, htf_c] = ohlc()
curr_o = o
curr_h = h
curr_l = l
curr_c = c

if useHtfData
    curr_o := htf_o
    curr_h := htf_h
    curr_l := htf_l
    curr_c := htf_c
    curr_c

candle_o = curr_o
candle_h = curr_h
candle_l = curr_l
candle_c = curr_c

if type == 'Heikin Ashi' and not chart.is_heikinashi
    candle_c := (curr_o + curr_h + curr_l + curr_c) / 4
    if newCandle
        candle_o := na(candle_o[1]) ? (curr_o + curr_c) / 2 : (nz(candle_o[1]) + nz(candle_c[1])) / 2
        candle_o
    else
        candle_o := nz(candle_o[1])
        candle_o
    candle_h := math.max(curr_h, candle_o, candle_c)
    candle_l := math.min(curr_l, candle_o, candle_c)
    candle_l

// Increment initialized_candles
if newCandle
    initialized_candles := math.min(initialized_candles + 1, num)
    initialized_candles

// Draw lines for the lowest low, highest high, and midpoint
if (low_line_enabled or high_line_enabled or mid_line_enabled) and initialized_candles == num
    var lows = array.new_float(num, na)
    var highs = array.new_float(num, na)
    var bar_indices = array.new_int(num, na)
    for [i, candle] in candles
        lows.set(i, candle.lowPrice)
        highs.set(i, candle.highPrice)
        bar_indices.set(i, candle.start_bar)

    if not array.includes(lows, na) and not array.includes(highs, na)
        // Lowest Low
        if low_line_enabled
            min_low_idx = array.indexof(lows, array.min(lows))
            if min_low_idx >= 0
                min_low = array.get(lows, min_low_idx)
                min_low_bar = array.get(bar_indices, min_low_idx)
                low_candle = array.get(candles, min_low_idx)

                // Delete existing low lines from other candles
                for [i, c] in candles
                    if i != min_low_idx and not na(c.lowLine)
                        c.lowLine.delete()
                        c.lowLine := na
                        c.lowLine

                // Draw or update the low line to the current bar
                if na(low_candle.lowLine)
                    low_candle.lowLine := line.new(min_low_bar, min_low, bar_index, min_low, style = getLineStyle(low_line_style), color = low_line_col, width = low_line_width)
                    low_candle.lowLine
                else
                    low_candle.lowLine.set_xy1(min_low_bar, min_low)
                    low_candle.lowLine.set_xy2(bar_index, min_low)

        // Highest High
        if high_line_enabled
            max_high_idx = array.indexof(highs, array.max(highs))
            if max_high_idx >= 0
                max_high = array.get(highs, max_high_idx)
                max_high_bar = array.get(bar_indices, max_high_idx)
                high_candle = array.get(candles, max_high_idx)

                // Delete existing high lines from other candles
                for [i, c] in candles
                    if i != max_high_idx and not na(c.highLine)
                        c.highLine.delete()
                        c.highLine := na
                        c.highLine

                // Draw or update the high line to the current bar
                if na(high_candle.highLine)
                    high_candle.highLine := line.new(max_high_bar, max_high, bar_index, max_high, style = getLineStyle(high_line_style), color = high_line_col, width = high_line_width)
                    high_candle.highLine
                else
                    high_candle.highLine.set_xy1(max_high_bar, max_high)
                    high_candle.highLine.set_xy2(bar_index, max_high)

        // Midpoint of Range
        if mid_line_enabled
            min_low = array.min(lows)
            max_high = array.max(highs)
            midpoint = (min_low + max_high) / 2
            // Find the candle closest to the midpoint
            var float min_diff = math.abs(array.get(lows, 0) - midpoint)
            var int mid_idx = 0
            for i = 1 to num - 1 by 1
                float diff = math.abs(array.get(lows, i) - midpoint)
                if diff < min_diff
                    min_diff := diff
                    mid_idx := i
                    mid_idx
            mid_bar = array.get(bar_indices, mid_idx)
            mid_candle = array.get(candles, mid_idx)

            // Delete existing midpoint lines from other candles
            for [i, c] in candles
                if i != mid_idx and not na(c.midLine)
                    c.midLine.delete()
                    c.midLine := na
                    c.midLine

            // Draw or update the midpoint line to the current bar
            if na(mid_candle.midLine)
                mid_candle.midLine := line.new(mid_bar, midpoint, bar_index, midpoint, style = getLineStyle(mid_line_style), color = mid_line_col, width = mid_line_width)
                mid_candle.midLine
            else
                mid_candle.midLine.set_xy1(mid_bar, midpoint)
                mid_candle.midLine.set_xy2(bar_index, midpoint)


if newCandle
    oldCandle = candles.shift()
    deleteCandle(oldCandle)
    pos = bar_index + offset + maxIndex * (3 + sizeMultiplier)
    candle = createCandle(pos, candle_o, candle_h, candle_l, candle_c, curr_tf)
    createProjections(candle, o, h, l, c, candle_o, candle_h, candle_l, candle_c, htf_o, htf_h, htf_l, htf_c, pos, candles)
    candles.push(candle)

for [i, candle] in candles
    new_pos = bar_index + offset + i * (margin + 2 * sizeMultiplier)
    is_current = i == maxIndex
    updateCandle(candle, new_pos, is_current ? candle_o : candle.openPrice, is_current ? candle_h : candle.highPrice, is_current ? candle_l : candle.lowPrice, is_current ? candle_c : candle.closePrice, curr_tf, is_current)
    moveProjections(candle, new_pos, o, h, l, c, is_current ? candle_o : candle.openPrice, is_current ? candle_h : candle.highPrice, is_current ? candle_l : candle.lowPrice, is_current ? candle_c : candle.closePrice, candles)
    if not is_current and proj_enabled
        // Delete only OHLC projections and labels, not the vertical line
        if not na(candle.o)
            candle.o.delete()
        if not na(candle.h)
            candle.h.delete()
        if not na(candle.l)
            candle.l.delete()
        if not na(candle.c)
            candle.c.delete()
        if label_enabled
            if not na(candle.labelO)
                candle.labelO.delete()
            if not na(candle.labelH)
                candle.labelH.delete()
            if not na(candle.labelL)
                candle.labelL.delete()
            if not na(candle.labelC)
                candle.labelC.delete()

// HTF Trend Table

// Trend Calculation Inputs
length = input.int(70, 'Length', tooltip = 'The Look-Back Window for HTF Trend Calculations', group = 'HTF Trend Calculations')
mult = 1.2

// Timeframe Inputs
t1 = input.timeframe('15', 'Time frame 1', group = 'Table: Higher Timeframes')
t2 = input.timeframe('30', 'Time frame 2', group = 'Table: Higher Timeframes')
t3 = input.timeframe('60', 'Time frame 3', group = 'Table: Higher Timeframes')
t4 = input.timeframe('240', 'Time frame 4', group = 'Table: Higher Timeframes')
t5 = input.timeframe('1D', 'Time frame 5', group = 'Table: Higher Timeframes')

// Table Appearance Inputs
table_enabled = input.bool(true, 'Show Table', group = 'HTF Trend Table Appearance')
table_text_size = input.string('Small', 'Text Size', options = ['Tiny', 'Small', 'Normal', 'Large'], group = 'HTF Trend Table Appearance')
table_position = input.string('Top Right', 'Position', options = ['Top Right', 'Top Left', 'Bottom Right', 'Bottom Left', 'Top Center', 'Bottom Center'], group = 'HTF Trend Table Appearance')
table_text_color = input.color(color.black, 'Text Color', group = 'HTF Trend Table Appearance')
table_bg_color = input.color(color.white, 'Table Background Color', group = 'HTF Trend Table Appearance')
table_border_color = input.color(color.black, 'Border Color', group = 'HTF Trend Table Appearance')
table_border_width = input.int(1, 'Border Width', minval = 0, group = 'HTF Trend Table Appearance')
green = input.color(color.green, 'Bullish Color', group = 'HTF Trend Table Appearance')
red = input.color(color.purple, 'Bearish Color', group = 'HTF Trend Table Appearance')
table_bg_transparency = input.int(0, 'Table Background Transparency', minval = 0, maxval = 100, group = 'HTF Trend Table Appearance')
signal_transparency = input.int(70, 'Table Bullish/Bearish Background Transparency', minval = 0, maxval = 100, group = 'HTF Trend Table Appearance')

// Core Calculations
src = close
lag = math.floor((length - 1) / 2)
zlema = ta.ema(src + src - src[lag], length)
volatility = ta.highest(ta.atr(length), length * 3) * mult

// Trend Logic
var trend = 0
if ta.crossover(close, zlema + volatility)
    trend := 1
    trend
if ta.crossunder(close, zlema - volatility)
    trend := -1
    trend

// MTF Analysis
s1 = request.security(syminfo.tickerid, t1, trend)
s2 = request.security(syminfo.tickerid, t2, trend)
s3 = request.security(syminfo.tickerid, t3, trend)
s4 = request.security(syminfo.tickerid, t4, trend)
s5 = request.security(syminfo.tickerid, t5, trend)

s1a = s1 == 1 ? 'Bullish' : 'Bearish'
s2a = s2 == 1 ? 'Bullish' : 'Bearish'
s3a = s3 == 1 ? 'Bullish' : 'Bearish'
s4a = s4 == 1 ? 'Bullish' : 'Bearish'
s5a = s5 == 1 ? 'Bullish' : 'Bearish'

// Map Text Size to Pine Script Size
getTableTextSize() =>
    switch table_text_size
        'Tiny' => size.tiny
        'Small' => size.small
        'Normal' => size.normal
        'Large' => size.large

// Map Position to Pine Script Position
getTablePosition() =>
    switch table_position
        'Top Right' => position.top_right
        'Top Left' => position.top_left
        'Bottom Right' => position.bottom_right
        'Bottom Left' => position.bottom_left
        'Top Center' => position.top_center
        'Bottom Center' => position.bottom_center

// MTF Table
if barstate.islast and table_enabled
    var data_table = table.new(position = getTablePosition(), columns = 2, rows = 6, bgcolor = color.new(table_bg_color, table_bg_transparency), border_width = table_border_width, border_color = table_border_color, frame_color = table_border_color, frame_width = table_border_width)
    table.cell(data_table, text_halign = text.align_center, column = 0, row = 0, text = 'Time Frame', text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 0, text = 'Signal', text_color = table_text_color, text_size = getTableTextSize())

    table.cell(data_table, text_halign = text.align_center, column = 0, row = 1, text = t1, text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 1, text = s1a, text_color = table_text_color, bgcolor = color.new(s1a == 'Bullish' ? green : red, signal_transparency), text_size = getTableTextSize())

    table.cell(data_table, text_halign = text.align_center, column = 0, row = 2, text = t2, text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 2, text = s2a, text_color = table_text_color, bgcolor = color.new(s2a == 'Bullish' ? green : red, signal_transparency), text_size = getTableTextSize())

    table.cell(data_table, text_halign = text.align_center, column = 0, row = 3, text = t3, text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 3, text = s3a, text_color = table_text_color, bgcolor = color.new(s3a == 'Bullish' ? green : red, signal_transparency), text_size = getTableTextSize())

    table.cell(data_table, text_halign = text.align_center, column = 0, row = 4, text = t4, text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 4, text = s4a, text_color = table_text_color, bgcolor = color.new(s4a == 'Bullish' ? green : red, signal_transparency), text_size = getTableTextSize())

    table.cell(data_table, text_halign = text.align_center, column = 0, row = 5, text = t5, text_color = table_text_color, text_size = getTableTextSize())
    table.cell(data_table, text_halign = text.align_center, column = 1, row = 5, text = s5a, text_color = table_text_color, bgcolor = color.new(s5a == 'Bullish' ? green : red, signal_transparency), text_size = getTableTextSize())

// CISD

// User Inputs for Customization
bullishBreakColor = input.color(color.black, "Bull CISD colour", inline = "bup", group = 'CISD Settings')
bearishBreakColor = input.color(color.black, "Bear CISD colour", inline = "bep", group = 'CISD Settings')

bullStr = input.string("+CISD", " ", tooltip = "Text to be displayed next to the CISD level.", inline = "bup", group = 'CISD Settings')
bearStr = input.string("-CISD", " ", tooltip = "Text to be displayed next to the CISD level.", inline = "bep", group = 'CISD Settings')


lineWidth = input.int(1, "Line Width", minval=1, maxval=5, group = 'CISD Settings')
lookAheadBars = input.int(5, "Line Extension Bars", minval=1, maxval = 5, group = 'CISD Settings')
styleOption = input.string("Solid (─)", title="Line Style", options=["Solid (─)", "Dotted (┈)", "Dashed (╌)"], group = 'CISD Settings')
keepLevels = input.bool(false, "Keep old CISD levels", group = 'CISD Settings')
// User Input for Pullback Size Filter
pullbackBodyPct = input.int(20, "Min Pullback Body % of Prev Range", minval=1, maxval=100, group = 'CISD Settings') / 100.0

// Structure Definitions
type MarketStructure
    float topPrice
    float bottomPrice
    bool isBullish

type cisd
    line level
    label txt
    bool completed

lineStyle = styleOption == "Dotted (┈)" ? line.style_dotted : styleOption == "Dashed (╌)" ? line.style_dashed : line.style_solid

// Variable Declarations
var line lastTopLine = na
var line lastBottomLine = na
var MarketStructure currentStructure = MarketStructure.new(0, 0, false)

var cisdLevelsBu = array.new<cisd>()
var cisdLevelsBe = array.new<cisd>()

var bool isBullishPullback = false
var bool isBearishPullback = false

var float potentialTopPrice = na
var float potentialBottomPrice = na

var int bullishBreakIndex = na
var int bearishBreakIndex = na

var float bullishChangeLevel = na
var float bearishChangeLevel = na

var bool currentState = false

gettablePos(pos) =>
    switch pos
        "Top Right" => position.top_right
        "Bottom Right" => position.bottom_right
        "Middle Right" => position.middle_right
        "Bottom Center" => position.bottom_center
        "Middle Left" => position.bottom_left


// Pullback Detection with Size and Multi-Bar Confirmation
prevRange = high[1] - low[1]
bearishPullbackCandleBody = math.abs(open[1] - close[1])
bullishPullbackCandleBody = math.abs(open[1] - close[1])

bearishPullbackDetected = close[1] < open[1] and open[1] > close[2] and bearishPullbackCandleBody >= prevRange * pullbackBodyPct
bullishPullbackDetected = close[1] > open[1] and open[1] < close[2] and bullishPullbackCandleBody >= prevRange * pullbackBodyPct

// Bearish Pullback Logic
if bearishPullbackDetected and not isBearishPullback
    isBearishPullback := true
    potentialTopPrice := open[1]
    bullishBreakIndex := bar_index[1]

// Bullish Pullback Logic
if bullishPullbackDetected and not isBullishPullback
    isBullishPullback := true
    potentialBottomPrice := open[1]
    bearishBreakIndex := bar_index[1]

// Update Potential Levels During Pullbacks
if isBullishPullback
    if open < potentialBottomPrice
        potentialBottomPrice := open
        bearishBreakIndex := bar_index
    if (close < open) and (open > potentialBottomPrice)
        potentialBottomPrice := open
        bearishBreakIndex := bar_index

if isBearishPullback
    if open > potentialTopPrice
        potentialTopPrice := open
        bullishBreakIndex := bar_index
    if (close > open) and open < potentialTopPrice
        potentialTopPrice := open
        bullishBreakIndex := bar_index

// Structure Updates - Bearish Break
if low < currentStructure.bottomPrice
    currentStructure.bottomPrice := low
    currentStructure.isBullish := false

    if isBearishPullback and (bar_index-bullishBreakIndex != 0)
        currentStructure.topPrice := math.max(high[bar_index-bullishBreakIndex],high[bar_index-bullishBreakIndex+1])
        isBearishPullback := false
        bearishLine = line.new(bullishBreakIndex, potentialTopPrice, bar_index + lookAheadBars, potentialTopPrice, color=bearishBreakColor, width=lineWidth, style = lineStyle)
        bearishLabel = label.new(bar_index + lookAheadBars, potentialTopPrice, bullStr, color=color.new(color.white,100), textcolor=bearishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        b = cisd.new(bearishLine, bearishLabel, false)
        cisdLevelsBe.push(b)
    else if close[1] > open[1] and close < open
        currentStructure.topPrice := high[1]

        isBearishPullback := false
        bearishLine = line.new(bullishBreakIndex, potentialTopPrice, bar_index + lookAheadBars, potentialTopPrice, color=bearishBreakColor, width=lineWidth, style = lineStyle)
        bearishLabel = label.new(bar_index + lookAheadBars, potentialTopPrice, bullStr, color=color.new(color.white,100), textcolor=bearishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        b = cisd.new(bearishLine, bearishLabel, false)
        cisdLevelsBe.push(b)

// Structure Updates - Bullish Break
if high > currentStructure.topPrice
    currentStructure.isBullish := true
    currentStructure.topPrice := high

    if isBullishPullback and (bar_index-bearishBreakIndex != 0)
        currentStructure.bottomPrice := math.min(low[bar_index-bearishBreakIndex],low[bar_index-bearishBreakIndex+1])
        isBullishPullback := false

        bullishLine = line.new(bearishBreakIndex, potentialBottomPrice, bar_index + lookAheadBars, potentialBottomPrice, color=bullishBreakColor, width=lineWidth, style = lineStyle)
        bullishLabel = label.new(bar_index + lookAheadBars, potentialBottomPrice, bearStr, color=color.new(color.white,100), textcolor=bullishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        bu = cisd.new(bullishLine, bullishLabel, false)
        cisdLevelsBu.push(bu)
    else if close[1] < open[1] and close > open
        currentStructure.bottomPrice := low[1]

        isBullishPullback := false

        bullishLine = line.new(bearishBreakIndex, potentialBottomPrice, bar_index + lookAheadBars, potentialBottomPrice, color=bullishBreakColor, width=lineWidth, style = lineStyle)
        bullishLabel = label.new(bar_index + lookAheadBars, potentialBottomPrice, bearStr, color=color.new(color.white,100), textcolor=bullishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        bu = cisd.new(bullishLine, bullishLabel, false)
        cisdLevelsBu.push(bu)


if array.size(cisdLevelsBu) > 1 and not keepLevels
    latest = array.shift(cisdLevelsBu)
    line.delete(latest.level)
    label.delete(latest.txt)

if array.size(cisdLevelsBe) > 1 and not keepLevels
    latest = array.shift(cisdLevelsBe)
    line.delete(latest.level)
    label.delete(latest.txt)

if array.size(cisdLevelsBu) >= 1
    latest = array.get(cisdLevelsBu,0)
    if not (close < latest.level.get_y2()) and not latest.completed
        line.set_x2(latest.level, bar_index+lookAheadBars)
        label.set_x(latest.txt, bar_index+lookAheadBars)
    if close < latest.level.get_y2() and not latest.completed
        latest.completed := true

        bearishLine = line.new(bullishBreakIndex, potentialTopPrice, bar_index + lookAheadBars, potentialTopPrice, color=bearishBreakColor, width=lineWidth, style = lineStyle)
        bearishLabel = label.new(bar_index + lookAheadBars, potentialTopPrice, bullStr, color=color.new(color.white,100), textcolor=bearishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        b = cisd.new(bearishLine, bearishLabel, false)
        cisdLevelsBe.push(b)

        currentState := false


if array.size(cisdLevelsBe) >= 1 and not keepLevels
    latest = array.get(cisdLevelsBe,0)
    if not (close > latest.level.get_y2()) and not latest.completed
        line.set_x2(latest.level, bar_index+lookAheadBars)
        label.set_x(latest.txt, bar_index+lookAheadBars)
    if close > latest.level.get_y2() and not latest.completed
        latest.completed := true

        bullishLine = line.new(bearishBreakIndex, potentialBottomPrice, bar_index + lookAheadBars, potentialBottomPrice, color=bullishBreakColor, width=lineWidth, style = lineStyle)
        bullishLabel = label.new(bar_index + lookAheadBars, potentialBottomPrice, bearStr, color=color.new(color.white,100), textcolor=bullishBreakColor, style=label.style_label_left, text_font_family = font.family_monospace, size = size.small)

        bu = cisd.new(bullishLine, bullishLabel, false)
        cisdLevelsBu.push(bu)

        currentState := true

// Timeframe box statistics

// Add variables to track open price positions, close outcomes, price moves, and lines
var int count_open_above = 0
var int count_open_below = 0
var int count_open_inside = 0
var int total_count = 0

// Counters for close outcomes per open category
var int count_open_above_close_above = 0
var int count_open_above_close_below = 0
var int count_open_above_close_inside = 0
var int count_open_below_close_above = 0
var int count_open_below_close_below = 0
var int count_open_below_close_inside = 0
var int count_open_inside_close_above = 0
var int count_open_inside_close_below = 0
var int count_open_inside_close_inside = 0

// Variables for tracking price moves (percentage and points)
var float sum_up_move_above = 0.0
var float sum_down_move_above = 0.0
var float sum_up_move_below = 0.0
var float sum_down_move_below = 0.0
var float sum_up_move_inside = 0.0
var float sum_down_move_inside = 0.0
var float sum_up_move_points_above = 0.0
var float sum_down_move_points_above = 0.0
var float sum_up_move_points_below = 0.0
var float sum_down_move_points_below = 0.0
var float sum_up_move_points_inside = 0.0
var float sum_down_move_points_inside = 0.0
var float current_open_price = na
var float current_high = na
var float current_low = na

// Variables for managing lines and labels
var line up_line = na
var line down_line = na
var label up_label = na
var label down_label = na


// Function to get timeframe box top and bottom prices
getBoxLevels(Candle candle) =>
    var float box_top = na
    var float box_bottom = na
    if not na(candle.midpointBox)
        box_top := box.get_top(candle.midpointBox)
        box_bottom := box.get_bottom(candle.midpointBox)
    [box_top, box_bottom]

// Function to map stats table position input to Pine Script position
getStatsTablePosition() =>
    switch stats_table_position
        'Top Right' => position.top_right
        'Top Left' => position.top_left
        'Bottom Right' => position.bottom_right
        'Bottom Left' => position.bottom_left
        'Top Center' => position.top_center
        'Bottom Center' => position.bottom_center

// Variables to store current HTF candle’s box levels, open category, and close price
var float current_box_top = na
var float current_box_bottom = na
var string current_open_category = na
var float last_close = na

// Calculate percentages and average moves
float perc_open_above = total_count > 0 ? (count_open_above / total_count) * 100 : 0
float perc_open_below = total_count > 0 ? (count_open_below / total_count) * 100 : 0
float perc_open_inside = total_count > 0 ? (count_open_inside / total_count) * 100 : 0
float perc_open_above_close_above = count_open_above > 0 ? (count_open_above_close_above / count_open_above) * 100 : 0
float perc_open_above_close_below = count_open_above > 0 ? (count_open_above_close_below / count_open_above) * 100 : 0
float perc_open_above_close_inside = count_open_above > 0 ? (count_open_above_close_inside / count_open_above) * 100 : 0
float perc_open_below_close_above = count_open_below > 0 ? (count_open_below_close_above / count_open_below) * 100 : 0
float perc_open_below_close_below = count_open_below > 0 ? (count_open_below_close_below / count_open_below) * 100 : 0
float perc_open_below_close_inside = count_open_below > 0 ? (count_open_below_close_inside / count_open_below) * 100 : 0
float perc_open_inside_close_above = count_open_inside > 0 ? (count_open_inside_close_above / count_open_inside) * 100 : 0
float perc_open_inside_close_below = count_open_inside > 0 ? (count_open_inside_close_below / count_open_inside) * 100 : 0
float perc_open_inside_close_inside = count_open_inside > 0 ? (count_open_inside_close_inside / count_open_inside) * 100 : 0
float avg_up_move_above = count_open_above > 0 ? sum_up_move_above / count_open_above : 0
float avg_down_move_above = count_open_above > 0 ? sum_down_move_above / count_open_above : 0
float avg_up_move_below = count_open_below > 0 ? sum_up_move_below / count_open_below : 0
float avg_down_move_below = count_open_below > 0 ? sum_down_move_below / count_open_below : 0
float avg_up_move_inside = count_open_inside > 0 ? sum_up_move_inside / count_open_inside : 0
float avg_down_move_inside = count_open_inside > 0 ? sum_down_move_inside / count_open_inside : 0
float avg_up_move_points_above = count_open_above > 0 ? sum_up_move_points_above / count_open_above : 0
float avg_down_move_points_above = count_open_above > 0 ? sum_down_move_points_above / count_open_above : 0
float avg_up_move_points_below = count_open_below > 0 ? sum_up_move_points_below / count_open_below : 0
float avg_down_move_points_below = count_open_below > 0 ? sum_down_move_points_below / count_open_below : 0
float avg_up_move_points_inside = count_open_inside > 0 ? sum_up_move_points_inside / count_open_inside : 0
float avg_down_move_points_inside = count_open_inside > 0 ? sum_down_move_points_inside / count_open_inside : 0
float avg_up_move_total = total_count > 0 ? (sum_up_move_above + sum_up_move_below + sum_up_move_inside) / total_count : 0
float avg_down_move_total = total_count > 0 ? (sum_down_move_above + sum_down_move_below + sum_down_move_inside) / total_count : 0
float avg_up_move_points_total = total_count > 0 ? (sum_up_move_points_above + sum_up_move_points_below + sum_up_move_points_inside) / total_count : 0
float avg_down_move_points_total = total_count > 0 ? (sum_up_move_points_above + sum_down_move_points_below + sum_down_move_points_inside) / total_count : 0

// Track open position, close, price moves, and draw lines
if newCandle and tfbox_enabled
    // Use the latest candle (the one being created)
    var candle = candles.get(maxIndex)
    [box_top, box_bottom] = getBoxLevels(candle)
    if not na(box_top) and not na(box_bottom)
        // Process previous HTF candle’s final close and price moves
        if not na(current_box_top) and not na(current_box_bottom) and not na(current_open_category) and not na(last_close) and not na(current_open_price)
            // Classify final close
            if last_close > current_box_top
                if current_open_category == "above"
                    count_open_above_close_above := count_open_above_close_above + 1
                else if current_open_category == "below"
                    count_open_below_close_above := count_open_below_close_above + 1
                else
                    count_open_inside_close_above := count_open_inside_close_above + 1
            else if last_close < current_box_bottom
                if current_open_category == "above"
                    count_open_above_close_below := count_open_above_close_below + 1
                else if current_open_category == "below"
                    count_open_below_close_below := count_open_below_close_below + 1
                else
                    count_open_inside_close_below := count_open_inside_close_below + 1
            else
                if current_open_category == "above"
                    count_open_above_close_inside := count_open_above_close_inside + 1
                else if current_open_category == "below"
                    count_open_below_close_inside := count_open_below_close_inside + 1
                else
                    count_open_inside_close_inside := count_open_inside_close_inside + 1
            // Calculate price moves (percentage and points)
            float up_move = current_open_price > 0 ? (current_high - current_open_price) / current_open_price * 100 : 0
            float down_move = current_open_price > 0 ? (current_open_price - current_low) / current_open_price * 100 : 0
            float up_move_points = current_high - current_open_price
            float down_move_points = current_open_price - current_low
            if current_open_category == "above"
                sum_up_move_above := sum_up_move_above + up_move
                sum_down_move_above := sum_down_move_above + down_move
                sum_up_move_points_above := sum_up_move_points_above + up_move_points
                sum_down_move_points_above := sum_down_move_points_above + down_move_points
            else if current_open_category == "below"
                sum_up_move_below := sum_up_move_below + up_move
                sum_down_move_below := sum_down_move_below + down_move
                sum_up_move_points_below := sum_up_move_points_below + up_move_points
                sum_down_move_points_below := sum_down_move_points_below + down_move_points
            else
                sum_up_move_inside := sum_up_move_inside + up_move
                sum_down_move_inside := sum_down_move_inside + down_move
                sum_up_move_points_inside := sum_up_move_points_inside + up_move_points
                sum_down_move_points_inside := sum_down_move_points_inside + down_move_points
        // Delete previous lines and labels
        if not na(up_line)
            line.delete(up_line[1])
        if not na(down_line)
            line.delete(down_line[1])
        if not na(up_label)
            label.delete(up_label[1])
        if not na(down_label)
            label.delete(down_label[1])
        // Update for the new HTF candle
        current_box_top := box_top
        current_box_bottom := box_bottom
        if open > box_top
            count_open_above := count_open_above + 1
            current_open_category := "above"
        else if open < box_bottom
            count_open_below := count_open_below + 1
            current_open_category := "below"
        else
            count_open_inside := count_open_inside + 1
            current_open_category := "inside"
        total_count := total_count + 1
        current_open_price := open
        current_high := high
        current_low := low
        last_close := close

// Update high, low, and last close for the current HTF candle
if not na(current_box_top) and not na(current_box_bottom) and not na(current_open_category) and tfbox_enabled
    current_high := math.max(current_high, high)
    current_low := math.min(current_low, low)
    last_close := close

// Display statistics in a table
var table stats_table = na
if stats_table_enabled
    if na(stats_table)
        stats_table := table.new(getStatsTablePosition(), 7, 5, bgcolor=color.new(color.white, 0), border_width=1, border_color=color.black)
        // Headers
        table.cell(stats_table, 0, 0, "Statistic", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 1, 0, "Open %", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 2, 0, "Close Above %", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 3, 0, "Close Below %", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 4, 0, "Close Inside %", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 5, 0, "Avg Up Move % ($)", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 6, 0, "Avg Down Move % ($)", text_color=color.black, text_size=size.small)
        // Open Above
        table.cell(stats_table, 0, 1, "Open Above Box", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 1, 1, str.tostring(perc_open_above, "#.##") + "% (" + str.tostring(count_open_above) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 2, 1, str.tostring(perc_open_above_close_above, "#.##") + "% (" + str.tostring(count_open_above_close_above) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 3, 1, str.tostring(perc_open_above_close_below, "#.##") + "% (" + str.tostring(count_open_above_close_below) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 4, 1, str.tostring(perc_open_above_close_inside, "#.##") + "% (" + str.tostring(count_open_above_close_inside) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 5, 1, str.tostring(avg_up_move_above, "#.##") + "% (" + str.tostring(avg_up_move_points_above, "#.##") + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 6, 1, str.tostring(avg_down_move_above, "#.##") + "% (" + str.tostring(avg_down_move_points_above, "#.##") + ")", text_color=color.black, text_size=size.small)
        // Open Below
        table.cell(stats_table, 0, 2, "Open Below Box", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 1, 2, str.tostring(perc_open_below, "#.##") + "% (" + str.tostring(count_open_below) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 2, 2, str.tostring(perc_open_below_close_above, "#.##") + "% (" + str.tostring(count_open_below_close_above) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 3, 2, str.tostring(perc_open_below_close_below, "#.##") + "% (" + str.tostring(count_open_below_close_below) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 4, 2, str.tostring(perc_open_below_close_inside, "#.##") + "% (" + str.tostring(count_open_below_close_inside) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 5, 2, str.tostring(avg_up_move_below, "#.##") + "% (" + str.tostring(avg_up_move_points_below, "#.##") + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 6, 2, str.tostring(avg_down_move_below, "#.##") + "% (" + str.tostring(avg_down_move_points_below, "#.##") + ")", text_color=color.black, text_size=size.small)
        // Open Inside
        table.cell(stats_table, 0, 3, "Open Inside Box", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 1, 3, str.tostring(perc_open_inside, "#.##") + "% (" + str.tostring(count_open_inside) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 2, 3, str.tostring(perc_open_inside_close_above, "#.##") + "% (" + str.tostring(count_open_inside_close_above) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 3, 3, str.tostring(perc_open_inside_close_below, "#.##") + "% (" + str.tostring(count_open_inside_close_below) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 4, 3, str.tostring(perc_open_inside_close_inside, "#.##") + "% (" + str.tostring(count_open_inside_close_inside) + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 5, 3, str.tostring(avg_up_move_inside, "#.##") + "% (" + str.tostring(avg_up_move_points_inside, "#.##") + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 6, 3, str.tostring(avg_down_move_inside, "#.##") + "% (" + str.tostring(avg_down_move_points_inside, "#.##") + ")", text_color=color.black, text_size=size.small)
        // Total Boxes
        table.cell(stats_table, 0, 4, "Total Boxes", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 1, 4, str.tostring(total_count), text_color=color.black, text_size=size.small)
        table.cell(stats_table, 2, 4, "", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 3, 4, "", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 4, 4, "", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 5, 4, str.tostring(avg_up_move_total, "#.##") + "% (" + str.tostring(avg_up_move_points_total, "#.##") + ")", text_color=color.black, text_size=size.small)
        table.cell(stats_table, 6, 4, str.tostring(avg_down_move_total, "#.##") + "% (" + str.tostring(avg_down_move_points_total, "#.##") + ")", text_color=color.black, text_size=size.small)
    // Update data cells
    table.cell(stats_table, 1, 1, str.tostring(perc_open_above, "#.##") + "% (" + str.tostring(count_open_above) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 2, 1, str.tostring(perc_open_above_close_above, "#.##") + "% (" + str.tostring(count_open_above_close_above) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 3, 1, str.tostring(perc_open_above_close_below, "#.##") + "% (" + str.tostring(count_open_above_close_below) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 4, 1, str.tostring(perc_open_above_close_inside, "#.##") + "% (" + str.tostring(count_open_above_close_inside) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 5, 1, str.tostring(avg_up_move_above, "#.##") + "% (" + str.tostring(avg_up_move_points_above, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 6, 1, str.tostring(avg_down_move_above, "#.##") + "% (" + str.tostring(avg_down_move_points_above, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 1, 2, str.tostring(perc_open_below, "#.##") + "% (" + str.tostring(count_open_below) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 2, 2, str.tostring(perc_open_below_close_above, "#.##") + "% (" + str.tostring(count_open_below_close_above) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 3, 2, str.tostring(perc_open_below_close_below, "#.##") + "% (" + str.tostring(count_open_below_close_below) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 4, 2, str.tostring(perc_open_below_close_inside, "#.##") + "% (" + str.tostring(count_open_below_close_inside) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 5, 2, str.tostring(avg_up_move_below, "#.##") + "% (" + str.tostring(avg_up_move_points_below, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 6, 2, str.tostring(avg_down_move_below, "#.##") + "% (" + str.tostring(avg_down_move_points_below, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 1, 3, str.tostring(perc_open_inside, "#.##") + "% (" + str.tostring(count_open_inside) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 2, 3, str.tostring(perc_open_inside_close_above, "#.##") + "% (" + str.tostring(count_open_inside_close_above) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 3, 3, str.tostring(perc_open_inside_close_below, "#.##") + "% (" + str.tostring(count_open_inside_close_below) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 4, 3, str.tostring(perc_open_inside_close_inside, "#.##") + "% (" + str.tostring(count_open_inside_close_inside) + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 5, 3, str.tostring(avg_up_move_inside, "#.##") + "% (" + str.tostring(avg_up_move_points_inside, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 6, 3, str.tostring(avg_down_move_inside, "#.##") + "% (" + str.tostring(avg_down_move_points_inside, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 1, 4, str.tostring(total_count), text_color=color.black, text_size=size.small)
    table.cell(stats_table, 5, 4, str.tostring(avg_up_move_total, "#.##") + "% (" + str.tostring(avg_up_move_points_total, "#.##") + ")", text_color=color.black, text_size=size.small)
    table.cell(stats_table, 6, 4, str.tostring(avg_down_move_total, "#.##") + "% (" + str.tostring(avg_down_move_points_total, "#.##") + ")", text_color=color.black, text_size=size.small)

Overview

MTF market analysis toolkit can show regular candles or Heikin Ashi, with optional automatic timeframe selection and a second level. A stats table and a timeframe box summarize the higher-timeframe range. Highest high, lowest low and midpoint lines can be drawn across those candles. Candle count, offset, size, colors and weekly-data handling are adjustable. The script reads higher-timeframe data with lookahead.

Details

Published by

TamaraKGreen on GitHub

Code credit

notprofessorgreen, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Support & resistance, Screeners & dashboards

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
HTF Timeframe Candle Timetimeframe60tf
Set Automaticallyboolfalsetf_auto
Two Levelsbooltruetf_2lvs
Number of HTF Candlesint4num
Offsetint20offset
SizestringSmallsize
TypestringCandlestype
Marginint1margin
Use HTF data to generate candlesstringIs Weeklyhtf_data
Show Stats Tablebooltruestats_table_enabled
Stats Table PositionstringBottom Leftstats_table_position
Bodycolorcolor.rgb(5, 168, 68, 50)up_col
Show all 40 settings
SettingTypeDefaultVariable
Wickcolorcolor.blackup_col_wick
Bordercolorcolor.blackup_col_border
Bodycolorcolor.blackdown_col
Wickcolorcolor.blackdown_col_wick
Bordercolorcolor.blackdown_col_border
Show Lowest HTF Low Linebooltruelow_line_enabled
Colorcolorcolor.blacklow_line_col
StylestringSolidlow_line_style
Widthint1low_line_width
Show Highest HTF High Linebooltruehigh_line_enabled
Colorcolorcolor.blackhigh_line_col
StylestringSolidhigh_line_style
Widthint1high_line_width
Show HTF Midpoint Linebooltruemid_line_enabled
Colorcolorcolor.tealmid_line_col
StylestringDottedmid_line_style
Widthint1mid_line_width
Show Timeframe Boxbooltruetfbox_enabled
Border Colorcolorcolor.rgb(120, 123, 134, 50)tfbox_border_col
Background Colorcolorcolor.rgb(120, 123, 134, 50)tfbox_bg_col
Price RangestringOpen to Midpointtfbox_price_mode
Show OHLC Linesbooltrueproj_enabled
Opencolorcolor.grayproj_o_col
Highcolorcolor.grayproj_h_col
Lowcolorcolor.grayproj_l_col
Closecolorcolor.grayproj_c_col
StylestringDashedproj_style
Widthint1proj_width
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

575 stars

This overlay indicator scans a pasted list of symbols for ICT liquidity sweep patterns using prior swing sweeps. The screening method looks back one, two, or three swings and can list long and short signals in a results table with adjustable rows, position, an

Indicator v5 SMC / ICT / price actionScreeners & dashboards
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Liquidity Sweep Pattern Scanner
330 stars

This indicator monitors multiple cryptocurrency symbols for trading signals. It calculates and plots entry prices, take profit, and stop loss levels for each symbol including BTCUSDT, ETHUSDT, BNBUSDT and others. Price crossovers trigger buy, sell or close ale

Indicator v5 Support & resistanceScreeners & dashboards
Updated 2 months ago · None stated GitHub repository of Multi Alert Long/Short [Alorse]

BZ-tracker

by Allen1212
303 stars

The BZ-tracker indicator marks ARK Invest buy and sell transactions on stock charts with labels. It plots green labels for purchases and red labels for sales, each annotated with a multiplier such as X1 or X2 to show the number of ARK ETFs trading the stock on

Indicator v4 Support & resistanceScreeners & dashboards
Updated 2 years ago · None stated GitHub repository of BZ-tracker
257 stars

This indicator overlays an intraday SPX and ES chart with a midnight session range, regular-trading-hours opening levels, and a VWAP projection box. It draws the midnight high, mid, and low, flags edge rejections within an absolute tolerance, and plots optiona

Indicator v6 TrendSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of SPX Midnight Box + Snag Logic

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

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