MTF Charting
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © theGary

//@version=5
indicator("MTF Charting", overlay = true, max_boxes_count = 500, max_lines_count = 500)


// visual Settings
css_bull_body = input.color(color.green, title = 'Body  ', group = 'Visual Settings', inline = '1')
css_bear_body = input.color(color.rgb(234, 21, 21), title = '', group = 'Visual Settings', inline = '1')

css_bull_border = input.color(color.lime, title = 'Border ', group = 'Visual Settings', inline = '2')
css_bear_border = input.color(color.red, title = '', group = 'Visual Settings', inline = '2')

css_bull_wick = input.color(color.lime, title = 'Wick  ', group = 'Visual Settings', inline = '3')
css_bear_wick = input.color(color.red, title = '', group = 'Visual Settings', inline = '3')

use_label   = input.bool(true, title = 'MTF Label', group = 'Visual Settings', inline = '4')
css_label   = input.color(color.new(#434651,0), title = '', group = 'Visual Settings', inline = '4')
label_size  = input.string('Medium', title = '', group = 'Visual Settings', inline = '4',
 options = ['Small', 'Medium', 'Large'])

padding     = input.int(10, title = 'Padding From Last Candle', minval = 3, maxval = 30, group = 'Visual Settings', inline = '5')
padding_b   = input.int(3, title = 'Padding Between MTF Candles', minval = 1, maxval = 10, group = 'Visual Settings', inline = '6')

// timeframe settings
use_tf1 = input.bool(true, title = 'HTF 1', group = 'Timeframe Settings', inline = '1')
use_tf2 = input.bool(true, title = 'HTF 2', group = 'Timeframe Settings', inline = '2')
use_tf3 = input.bool(true, title = 'HTF 3', group = 'Timeframe Settings', inline = '3')
use_tf4 = input.bool(true, title = 'HTF 4', group = 'Timeframe Settings', inline = '4')
use_tf5 = input.bool(true, title = 'HTF 5', group = 'Timeframe Settings', inline = '5')

tf1     = input.timeframe('5', title = '', group = 'Timeframe Settings', inline = '1')
tf2     = input.timeframe('15', title = '', group = 'Timeframe Settings', inline = '2')
tf3     = input.timeframe('30', title = '', group = 'Timeframe Settings', inline = '3')
tf4     = input.timeframe('60', title = '', group = 'Timeframe Settings', inline = '4')
tf5     = input.timeframe('D', title = '', group = 'Timeframe Settings', inline = '5')

tf1_bars= input.int(8, title = '', minval = 1, maxval = 50, group = 'Timeframe Settings', inline = '1')
tf2_bars= input.int(8, title = '', minval = 1, maxval = 50, group = 'Timeframe Settings', inline = '2')
tf3_bars= input.int(8, title = '', minval = 1, maxval = 50, group = 'Timeframe Settings', inline = '3')
tf4_bars= input.int(8, title = '', minval = 1, maxval = 50, group = 'Timeframe Settings', inline = '4')
tf5_bars= input.int(8, title = '', minval = 1, maxval = 50, group = 'Timeframe Settings', inline = '5')



// functions 
f_bull_candle(o_src, c_src) =>
    c_src >= o_src


f_label_size() =>
    ls = switch label_size
        "Small" => size.normal
        "Medium" => size.large
        "Large" => size.huge
        => size.normal


f_array_htf(array, value_to_add, tf) =>
    last_index = array.size(array)-1
    if ta.change(time(tf))
        array.shift(array)
        array.push(array, value_to_add)
    else
        array.set(array, last_index, value_to_add) 


f_array_ltf(array, array_add, max_array_size) =>
    var joined_array = array.new_float(max_array_size, na)
    joined_array := array.concat(array,array_add)

    array_size = array.size(joined_array)
    number_to_delete = math.max(0, array_size-max_array_size)

    if number_to_delete != 0
        for i = 0 to number_to_delete-1
            array.shift(joined_array)
        
    joined_array


f_array_boxdelete_pop(array) =>
    box.delete(array.first(array))
    array.shift(array)


f_array_linedelete_pop(array) =>
    line.delete(array.first(array))
    array.shift(array)


f_delete_all_boxes() =>
    a_allBoxes = box.all
    if array.size(a_allBoxes) > 0
        for i = 0 to array.size(a_allBoxes) - 1
            box.delete(array.get(a_allBoxes, i))


f_delete_all_lines() =>
    a_allLines = line.all
    if array.size(a_allLines) > 0
        for i = 0 to array.size(a_allLines) - 1
            line.delete(array.get(a_allLines, i))


f_delete_all_labels() =>
    a_allLabels = label.all
    if array.size(a_allLabels) > 0
        for i = 0 to array.size(a_allLabels) - 1
            label.delete(array.get(a_allLabels, i))


f_delete_all() =>
    f_delete_all_boxes()
    f_delete_all_lines()
    f_delete_all_labels()


f_timeframe_text(_timeframe) =>
    if timeframe.in_seconds(_timeframe) < 60
        _timeframe + 's'
    else if timeframe.in_seconds(_timeframe) < 86400
        _timeframe + 'm'
    else if timeframe.in_seconds(_timeframe) < 86400
        _timeframe + 'D'
    else
        _timeframe



f_draw_candles(o_array, h_array, l_array, c_array, box_array, line_array, label_array, start_spacing, end_spacing, label_y, timeframe) =>

    array_size = array.size(o_array)
    for i = 0 to array_size - 1
        new_x1          = bar_index + (start_spacing) + (3*i)
        new_x2          = new_x1 + 2
        new_open        = array.get(o_array, i)
        new_high        = array.get(h_array, i)
        new_low         = array.get(l_array, i)
        new_close       = array.get(c_array, i)

        is_bull_candle  = f_bull_candle(new_open, new_close)
        body_color      = is_bull_candle ? css_bull_body : css_bear_body
        border_color    = is_bull_candle ? css_bull_border : css_bear_border
        wick_color      = is_bull_candle ? css_bull_wick : css_bear_wick

        array.push(box_array, box.new(left = new_x1, top = new_open, right = new_x2, bottom = new_close,
         xloc=xloc.bar_index, border_style=line.style_solid, 
         bgcolor = body_color, border_color = border_color)
         )

        mid_time = (new_x1 + new_x2) / 2
        array.push(line_array, line.new(x1 = mid_time, y1 = new_high, x2 = mid_time, y2 = new_low,
         xloc=xloc.bar_index, style=line.style_solid, 
         color = wick_color)
         )

    middle_index = ((bar_index + start_spacing) + (bar_index + end_spacing)) / 2

    if use_label
        array.push(label_array, label.new(middle_index, label_y, text = f_timeframe_text(timeframe),
         style = label.style_none, textcolor = css_label, size = f_label_size())
         )


f_ltf_values(arr_o, arr_h, arr_l, arr_c, tf, max_array_size) =>
    adjusted_timeframe = timeframe.in_seconds(tf) >= timeframe.in_seconds() ? '' : tf
    [o,h,l,c] = request.security_lower_tf(syminfo.tickerid, adjusted_timeframe, [open, high, low, close])
    f_array_ltf(arr_o, o, max_array_size)
    f_array_ltf(arr_h, h, max_array_size)
    f_array_ltf(arr_l, l, max_array_size)
    f_array_ltf(arr_c, c, max_array_size)



f_htf_values(arr_o, arr_h, arr_l, arr_c, tf) =>
    [o,h,l,c] = request.security(syminfo.tickerid, tf, [open, high, low, close], lookahead = barmerge.lookahead_on)
    f_array_htf(arr_o, o, tf)
    f_array_htf(arr_h, h, tf)
    f_array_htf(arr_l, l, tf)
    f_array_htf(arr_c, c, tf)



// define drawing object arrays
var tf1_bodies  = array.new_box(tf1_bars, na) 
var tf2_bodies  = array.new_box(tf2_bars, na) 
var tf3_bodies  = array.new_box(tf3_bars, na) 
var tf4_bodies  = array.new_box(tf4_bars, na) 
var tf5_bodies  = array.new_box(tf5_bars, na) 

var tf1_wicks   = array.new_line(tf1_bars, na) 
var tf2_wicks   = array.new_line(tf2_bars, na) 
var tf3_wicks   = array.new_line(tf3_bars, na) 
var tf4_wicks   = array.new_line(tf4_bars, na) 
var tf5_wicks   = array.new_line(tf5_bars, na) 

var tf1_lbl     = array.new_label(1, na)
var tf2_lbl     = array.new_label(1, na)
var tf3_lbl     = array.new_label(1, na)
var tf4_lbl     = array.new_label(1, na)
var tf5_lbl     = array.new_label(1, na)


// define value arrays
var tf1_o       = array.new_float(tf1_bars, na)
var tf2_o       = array.new_float(tf2_bars, na)
var tf3_o       = array.new_float(tf3_bars, na)
var tf4_o       = array.new_float(tf4_bars, na)
var tf5_o       = array.new_float(tf5_bars, na)

var tf1_h       = array.new_float(tf1_bars, na)
var tf2_h       = array.new_float(tf2_bars, na)
var tf3_h       = array.new_float(tf3_bars, na)
var tf4_h       = array.new_float(tf4_bars, na)
var tf5_h       = array.new_float(tf5_bars, na)

var tf1_l       = array.new_float(tf1_bars, na)
var tf2_l       = array.new_float(tf2_bars, na)
var tf3_l       = array.new_float(tf3_bars, na)
var tf4_l       = array.new_float(tf4_bars, na)
var tf5_l       = array.new_float(tf5_bars, na)

var tf1_c       = array.new_float(tf1_bars, na)
var tf2_c       = array.new_float(tf2_bars, na)
var tf3_c       = array.new_float(tf3_bars, na)
var tf4_c       = array.new_float(tf4_bars, na)
var tf5_c       = array.new_float(tf5_bars, na)



// store the values 
if use_tf1
    if timeframe.in_seconds() > timeframe.in_seconds(tf1)
        f_ltf_values(tf1_o, tf1_h, tf1_l, tf1_c, tf1, tf1_bars)
    else
        f_htf_values(tf1_o, tf1_h, tf1_l, tf1_c, tf1)

if use_tf2
    if timeframe.in_seconds() > timeframe.in_seconds(tf2)
        f_ltf_values(tf2_o, tf2_h, tf2_l, tf2_c, tf2, tf2_bars)
    else
        f_htf_values(tf2_o, tf2_h, tf2_l, tf2_c, tf2)

if use_tf3
    if timeframe.in_seconds() > timeframe.in_seconds(tf3)
        f_ltf_values(tf3_o, tf3_h, tf3_l, tf3_c, tf3, tf3_bars)
    else
        f_htf_values(tf3_o, tf3_h, tf3_l, tf3_c, tf3)

if use_tf4
    if timeframe.in_seconds() > timeframe.in_seconds(tf4)
        f_ltf_values(tf4_o, tf4_h, tf4_l, tf4_c, tf4, tf4_bars)
    else
        f_htf_values(tf4_o, tf4_h, tf4_l, tf4_c, tf4)

if use_tf5
    if timeframe.in_seconds() > timeframe.in_seconds(tf5)
        f_ltf_values(tf5_o, tf5_h, tf5_l, tf5_c, tf5, tf5_bars)
    else
        f_htf_values(tf5_o, tf5_h, tf5_l, tf5_c, tf5)



// calculate spacing
var int tf1_start   = na
var int tf1_end     = na

var int tf2_start   = na
var int tf2_end     = na

var int tf3_start   = na
var int tf3_end     = na

var int tf4_start   = na
var int tf4_end     = na

var int tf5_start   = na
var int tf5_end     = na

var int last_end    = na


if (barstate.isfirst)
    last_end := padding

    if (use_tf1)
        tf1_start := padding
        tf1_end   := tf1_start + 3 * tf1_bars
        last_end  := tf1_end

    if (use_tf2)
        tf2_start := last_end + (padding_b*3)
        tf2_end   := tf2_start + 3 * tf2_bars
        last_end  := tf2_end

    if (use_tf3)
        tf3_start := last_end + (padding_b*3)
        tf3_end   := tf3_start + 3 * tf3_bars
        last_end  := tf3_end

    if (use_tf4)
        tf4_start := last_end + (padding_b*3)
        tf4_end   := tf4_start + 3 * tf4_bars
        last_end  := tf4_end

    if (use_tf5)
        tf5_start := last_end + (padding_b*3)
        tf5_end   := tf5_start + 3 * tf5_bars



tf1_max = nz(array.max(tf1_h), 0)
tf2_max = nz(array.max(tf2_h), 0)
tf3_max = nz(array.max(tf3_h), 0)
tf4_max = nz(array.max(tf4_h), 0)
tf5_max = nz(array.max(tf5_h), 0)
y_value = math.max(tf1_max, tf2_max, tf3_max, tf4_max, tf5_max)



if barstate.islast
    f_delete_all()

    if use_tf1
        f_draw_candles(tf1_o, tf1_h, tf1_l, tf1_c, tf1_bodies, tf1_wicks, tf1_lbl, tf1_start, tf1_end, y_value, tf1)

    if use_tf2
        f_draw_candles(tf2_o, tf2_h, tf2_l, tf2_c, tf2_bodies, tf2_wicks, tf2_lbl, tf2_start, tf2_end, y_value, tf2)

    if use_tf3
        f_draw_candles(tf3_o, tf3_h, tf3_l, tf3_c, tf3_bodies, tf3_wicks, tf3_lbl, tf3_start, tf3_end, y_value, tf3)

    if use_tf4
        f_draw_candles(tf4_o, tf4_h, tf4_l, tf4_c, tf4_bodies, tf4_wicks, tf4_lbl, tf4_start, tf4_end, y_value, tf4)

    if use_tf5
        f_draw_candles(tf5_o, tf5_h, tf5_l, tf5_c, tf5_bodies, tf5_wicks, tf5_lbl, tf5_start, tf5_end, y_value, tf5)


    // label.new(bar_index+50, 30600, color = color.white,
    //  text = str.tostring(tf4_c)
    //  )



// TODO closing value is not updating because of ta.change, so need closing values to update