Fair Value Gap Chart
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © alexgrover
//Some FVG's are dogs

//@version=5
indicator("Fair Value Gap Chart", "Fair Value Gap Chart", overlay = true, max_lines_count = 500, max_boxes_count = 500)
//------------------------------------------------------------------------------
//Settings
//-----------------------------------------------------------------------------{
showEma = input(false, 'Show EMA', inline = 'ema')
length = input(20, '', inline = 'ema')

//Style
bull = input.color(color.teal, 'Bullish Candle', group = 'Style')
bear = input.color(color.red, 'Bearish Candle', group = 'Style')
emaCSs = input.color(#2157f3, 'EMA Color', group = 'Style')

showDates = input(true, 'Show Start/End Date')

//-----------------------------------------------------------------------------}
//UDT
//-----------------------------------------------------------------------------{
type fvg_candle
    float max
    float top_body
    float btm_body
    float min
    bool  bullish
    int   timestamp

//-----------------------------------------------------------------------------}
//Detect and append FVG's to array
//-----------------------------------------------------------------------------{
var candles = array.new<fvg_candle>(0)

//Bullish fvg
if low > high[2] and close[1] > high[2]
    candles.unshift(fvg_candle.new(high, low, high[2], low[2], true, time))

//Bearish fvg
if high < low[2] and close[1] < low[2]
    candles.unshift(fvg_candle.new(high[2], low[2], high, low, false, time))

//-----------------------------------------------------------------------------}
//Display FVG chart
//-----------------------------------------------------------------------------{
var float minval = na
n = bar_index

//Date labels
var start = label.new(na, na, na, color = color(na)
  , style = label.style_label_up
  , textcolor = chart.fg_color
  , size = size.small)

var end = label.new(na, na, na, color = color(na)
  , style = label.style_label_up
  , textcolor = chart.fg_color
  , size = size.small)

//Delete displayed boxes/lines
if candles.size() < 500
    for l in line.all
        l.delete()
    for b in box.all
        b.delete()

//Set candles/ema
if barstate.islast
    size = math.min(candles.size()-1, 499)
    left = n - (size * 2) - 2
    minval := candles.get(size).min

    //Initial ema values
    float ema = candles.get(size).top_body
    float prev_ema = na

    //Loop trough fvg's array and set candle
    for i = size to 0
        get = candles.get(i)
        right = left + 2
        
        //Candle body
        box.new(left, get.top_body, right, get.btm_body, na
          , bgcolor = get.bullish ? bull : bear)
        
        //Candle wicks
        if not showEma
            line.new(right - 1, get.max, right - 1, get.min
              , color = get.bullish ? bull : bear)

        minval := math.min(get.min, minval)

        //Compute ema value
        if showEma
            ema := ema + 2/(length+1) * ((get.bullish ? get.top_body : get.btm_body) - ema)
            line.new(left - 1, prev_ema, right - 1, ema)
            prev_ema := ema

        left := right
        
        //Set labels
        if showDates
            start_t = candles.get(size).timestamp
            start.set_xy(n - (size * 2) - 2, minval)
            start.set_text(str.format('{0, number, #}-{1}-{2} {3}:{4}', year(start_t), month(start_t), dayofmonth(start_t), hour(start_t), minute(start_t)))

            end_t = candles.get(0).timestamp
            end.set_xy(n, minval)
            end.set_text(str.format('{0, number, #}-{1}-{2} {3}:{4}', year(end_t), month(end_t), dayofmonth(end_t), hour(end_t), minute(end_t)))

//Horizontal line
plot(showDates ? minval : na, 'X axis', chart.fg_color, trackprice = true)

//-----------------------------------------------------------------------------}