SMC Structures and FVG
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LudoGH68
//@version=5
indicator("SMC Structures and FVG", overlay = true)
import LudoGH68/Drawings_public/1 as d

getLineStyle(lineOption) =>
    lineOption == "┈" ? line.style_dotted : lineOption == "╌" ? line.style_dashed : line.style_solid

get_structure_highest_bar(lookback) =>

	var int idx = 0
    maxBar = bar_index > lookback ? ta.highestbars(high, lookback) : ta.highestbars(high, bar_index + 1)

	for i = 0 to lookback - 1 by 1
		if high[i+1] > high[i+2] and high[i] <= high[i+1] and ((i+1) * -1) >= maxBar
			idx := (i+1) * -1
			//break
            
	idx := idx == 0 ? maxBar : idx 

get_structure_lowest_bar(lookback) =>

	var int idx = 0
    minBar = bar_index > lookback ? ta.lowestbars(low, lookback) : ta.lowestbars(low, bar_index + 1)

	for i = 0 to lookback - 1 by 1
		if low[i+1] < low[i+2] and low[i] >= low[i+1]  and ((i+1) * -1) >= minBar
			idx := (i+1) * -1
            //break
			
	idx := idx == 0 ? minBar : idx 

is_structure_high_broken(_highStructBreakPrice, _structureHigh, _structureHighStartIndex, _structureDirection) =>
    var bool res = false

    if (_highStructBreakPrice > _structureHigh and  bar_index[1] >  _structureHighStartIndex) or (_structureDirection == 1 and _highStructBreakPrice > _structureHigh)
        res := true
    else
        res := false

    res

// Fear Value Gap
isFvgToShow =  input(true, title='Display FVG', group="Fear Value Gap")
bullishFvgColor = input(color.new(color.green, 50), 'Bullish FVG Color', group="Fear Value Gap")
bearishFvgColor = input(color.new(color.red, 50), 'Bearish FVG Color', group="Fear Value Gap")
mitigatedFvgColor = input(color.new(color.gray, 50), 'Mitigated FVG Color', group="Fear Value Gap")
fvgHistoryNbr = input.int(5, 'Number of FVG to show', minval=1, maxval=50)
isMitigatedFvgToReduce = input(false, title='Reduce mitigated FVG', group="Fear Value Gap")

// Structures
isStructBodyCandleBreak = input(true, title='Break with candle\'s body', group="Structures")
isCurrentStructToShow = input(true, title='Display current structure', group="Structures")
bullishBosColor = input(color.silver, 'Bullish BOS Color', group="Structures")
bearishBosColor = input(color.silver, 'Bearish BOS Color', group="Structures")
bosLineStyleOption = input.string("─", title="BOS Style", group="Structures", options=["─", "┈", "╌"])
bosLineStyle = getLineStyle(bosLineStyleOption)
bosLineWidth = input.int(1, title="BOS Width", group="Structures", minval=1, maxval=5)
bullishChochColor = input(color.yellow, 'Bullish CHoCH Color', group="Structures")
bearishChochColor = input(color.yellow, 'Bearish CHoCH Color', group="Structures")
chochLineStyleOption = input.string("─", title="CHoCH Style", group="Structures", options=["─", "┈", "╌"])
chochLineStyle = getLineStyle(chochLineStyleOption)
chochLineWidth = input.int(1, title="MSB Width", group="Structures", minval=1, maxval=5)
currentStructColor = input(color.blue, 'Current structure Color', group="Structures")
currentStructLineStyleOption = input.string("─", title="Current structure Style", group="Structures", options=["─", "┈", "╌"])
currentStructLineStyle = getLineStyle(currentStructLineStyleOption)
currentStructLineWidth = input.int(1, title="Current structure Width", group="Structures", minval=1, maxval=5)
structHistoryNbr = input.int(10, 'Number of break to show', minval=1, maxval=50)

// Fibonacci 1
isFibo1ToShow = input(true, title = "", group="Structure Fibonacci", inline = "Fibo1")
fibo1Value = input.float(0.786, title = "", group="Structure Fibonacci", inline = "Fibo1")
fibo1Color = input(#64b5f6, title = "", group="Structure Fibonacci", inline = "Fibo1")
fibo1StyleOption = input.string("─", title = "", group="Structure Fibonacci", options=["─", "┈", "╌"], inline = "Fibo1")
fibo1Style = getLineStyle(fibo1StyleOption)
fibo1LineWidth = input.int(1, title = "", group="Structure Fibonacci", minval=1, maxval=5, inline = "Fibo1")

// Fibonacci 2
isFibo2ToShow = input(true, title = "", group="Structure Fibonacci", inline = "Fibo2")
fibo2Value = input.float(0.705, title = "", group="Structure Fibonacci", inline = "Fibo2")
fibo2Color = input(#f23645, title = "", group="Structure Fibonacci", inline = "Fibo2")
fibo2StyleOption = input.string("─", title = "", group="Structure Fibonacci", options=["─", "┈", "╌"], inline = "Fibo2")
fibo2Style = getLineStyle(fibo2StyleOption)
fibo2LineWidth = input.int(1, title = "", group="Structure Fibonacci", minval=1, maxval=5, inline = "Fibo2")

// Fibonacci 3
isFibo3ToShow = input(true, title = "", group="Structure Fibonacci", inline = "Fibo3")
fibo3Value = input.float(0.618, title = "", group="Structure Fibonacci", inline = "Fibo3")
fibo3Color = input(#089981, title = "", group="Structure Fibonacci", inline = "Fibo3")
fibo3StyleOption = input.string("─", title = "", group="Structure Fibonacci", options=["─", "┈", "╌"], inline = "Fibo3")
fibo3Style = getLineStyle(fibo3StyleOption)
fibo3LineWidth = input.int(1, title = "", group="Structure Fibonacci", minval=1, maxval=5, inline = "Fibo3")

// Fibonacci 3
isFibo4ToShow = input(true, title = "", group="Structure Fibonacci", inline = "Fibo4")
fibo4Value = input.float(0.5, title = "", group="Structure Fibonacci", inline = "Fibo4")
fibo4Color = input(#4caf50, title = "", group="Structure Fibonacci", inline = "Fibo4")
fibo4StyleOption = input.string("─", title = "", group="Structure Fibonacci", options=["─", "┈", "╌"], inline = "Fibo4")
fibo4Style = getLineStyle(fibo4StyleOption)
fibo4LineWidth = input.int(1, title = "", group="Structure Fibonacci", minval=1, maxval=5, inline = "Fibo4")

// Fibonacci 5
isFibo5ToShow = input(true, title = "", group="Structure Fibonacci", inline = "Fibo5")
fibo5Value = input.float(0.382, title = "", group="Structure Fibonacci", inline = "Fibo5")
fibo5Color = input(#81c784, title = "", group="Structure Fibonacci", inline = "Fibo5")
fibo5StyleOption = input.string("─", title = "", group="Structure Fibonacci", options=["─", "┈", "╌"], inline = "Fibo5")
fibo5Style = getLineStyle(fibo5StyleOption)
fibo5LineWidth = input.int(1, title = "", group="Structure Fibonacci", minval=1, maxval=5, inline = "Fibo5")

// Draw FVG into graph
FVGDraw(_boxes, _fvgTypes, _isFvgMitigated) => 

    // Loop into all values of the array
    for [index, value] in _boxes
        
        // Processing bullish FVG
        if(array.get(_fvgTypes, index))

            // Check if FVG has been totally mitigated
            if(low <= box.get_bottom(value))
                array.remove(_boxes, index)
                array.remove(_fvgTypes, index)
                array.remove(_isFvgMitigated, index)
                box.delete(value)
            else 
                if(low < box.get_top((value)))
                    box.set_bgcolor(value, mitigatedFvgColor)    

                    // Mitigated FVG Alert
                    if(not(array.get(_isFvgMitigated, index)))
                        alert("FVG has been mitigated", alert.freq_once_per_bar)
                        array.set(_isFvgMitigated, index, true)

                    // Reduce FVG if needed
                    if(isMitigatedFvgToReduce)
                        box.set_top(value, low)

                box.set_right(value, bar_index)

        // Processing bearish FVG
        else

            // Check if FVG has been mitigated
            if(high >= box.get_top(value))
                array.remove(_boxes, index)
                array.remove(_fvgTypes, index)
                array.remove(_isFvgMitigated, index)
                box.delete(value)
            else
                if(high > box.get_bottom((value)))
                    box.set_bgcolor(value, mitigatedFvgColor)    

                    // Mitigated FVG Alert
                    if(not(array.get(_isFvgMitigated, index)))
                        alert("FVG has been mitigated", alert.freq_once_per_bar)
                        array.set(_isFvgMitigated, index, true)

                    // Reduce FVG if needed
                    if(isMitigatedFvgToReduce)
                        box.set_bottom(value, high)

                box.set_right(value, bar_index)

// Arrays variable
var array<line> structureLines = array.new_line(0)
var array<label> structureLabels = array.new_label(0)
var array<box>  fvgBoxes = array.new_box(0)
var array<bool> fvgTypes = array.new_bool(0)
var array<bool> isFvgMitigated = array.new_bool(0)

// Price variables
var float structureHigh = 0.0
var float structureLow = 0.0
var float fibo1Price = 0.0
var float fibo2Price = 0.0
var float fibo3Price = 0.0
var float fibo4Price = 0.0
var float fibo5Price = 0.0

// Index variable
var int structureHighStartIndex = 0
var int structureLowStartIndex = 0
var int structureDirection = 0
var int fibo1StartIndex = 0
var int fibo2StartIndex = 0
var int fibo3StartIndex = 0
var int fibo4StartIndex = 0
var int fibo5StartIndex = 0

// Line variable
var line structureHighLine = na
var line structureLowLine = na
var line fibo1Line = na
var line fibo2Line = na
var line fibo3Line = na
var line fibo4Line = na
var line fibo5Line = na

// Label variable
var label fibo1Label = na
var label fibo2Label = na
var label fibo3Label = na
var label fibo4Label = na
var label fibo5Label = na
//
//
// ==========================================================================================
//                              FAIR VALUE GAP FINDER PROCESSING                                                                         
// ==========================================================================================
//
//
// Define FVG type
isBullishFVG = high[3] < low[1]
isBearishFVG = low[3] > high[1]

// Bullish FVG process
if(isBullishFVG and isFvgToShow)

    // Add FVG into FVG's array
    box _box = box.new(left=bar_index - 2, top=low[1], right=bar_index[1], bottom=high[3], border_style=line.style_solid, border_width=1, bgcolor=bullishFvgColor, border_color=color.new(color.green, 100))
    array.push(fvgBoxes, _box)
    array.push(fvgTypes, true)
    array.push(isFvgMitigated, false)

    // Check if FVG to show is upper than user parameter
    if(array.size(fvgBoxes) > fvgHistoryNbr + 1)

        // Delete the FVG and its index from arrays
        box.delete(array.get(fvgBoxes, 0))
        array.remove(fvgBoxes, 0)
        array.remove(fvgTypes, 0)
        array.remove(isFvgMitigated, 0)

// Bearish FVG process
if(isBearishFVG and isFvgToShow)
    
    // Add FVG into FVG's array
    box _box = box.new(left=bar_index - 2, top=low[3], right=bar_index[1], bottom=high[1], border_style=line.style_solid, border_width=1, bgcolor=bearishFvgColor, border_color=color.new(color.red, 100))
    array.push(fvgBoxes, _box)
    array.push(fvgTypes, false)
    array.push(isFvgMitigated, false)

    // Check if FVG to show is upper than user parameter
    if(array.size(fvgBoxes) > fvgHistoryNbr + 1)
        
        // Delete the FVG and its index from arrays
        box.delete(array.get(fvgBoxes, 0))
        array.remove(fvgBoxes, 0)
        array.remove(fvgTypes, 0)
        array.remove(isFvgMitigated, 0)

// Draw FVG
FVGDraw(fvgBoxes, fvgTypes, isFvgMitigated)
//
//
// ==========================================================================================
//                                   STRUCTURES PROCESSING                                                         
// ==========================================================================================
//
//
// Initialize value for bar 0
if(bar_index == 0)
    structureHighStartIndex := bar_index
    structureLowStartIndex  := bar_index
    structureHigh := high
    structureLow  := low 

highest = bar_index > 10 ? ta.highest(10) : ta.highest(bar_index + 1)
highestBar = bar_index > 10 ? ta.highestbars(high, 10) : ta.highestbars(high, bar_index + 1) 
lowest = bar_index > 10 ? ta.lowest(10) : ta.lowest(bar_index + 1)
lowestBar = bar_index > 10 ? ta.lowestbars(low, 10) : ta.lowestbars(low, bar_index + 1)
structureMaxBar = bar_index + get_structure_highest_bar(10)
structureMinBar = bar_index + get_structure_lowest_bar(10)
lowStructBreakPrice = isStructBodyCandleBreak ? close : low
highStructBreakPrice = isStructBodyCandleBreak ? close : high
isStuctureLowBroken = (lowStructBreakPrice < structureLow and lowStructBreakPrice[1] >= structureLow and lowStructBreakPrice[2] >= structureLow and lowStructBreakPrice[3] >= structureLow and bar_index[1] >  structureLowStartIndex and bar_index[2] >  structureLowStartIndex and bar_index[3] >  structureLowStartIndex) or (structureDirection == 2 and lowStructBreakPrice < structureLow)
isStructureHighBroken = (highStructBreakPrice > structureHigh and highStructBreakPrice[1] <= structureHigh and highStructBreakPrice[2] <= structureHigh and highStructBreakPrice[3] <= structureHigh and bar_index[1] >  structureHighStartIndex and bar_index[2] >  structureHighStartIndex and bar_index[3] >  structureHighStartIndex) or (structureDirection == 1 and highStructBreakPrice > structureHigh)
 

//if((low < structureLow and low[1] >= structureLow and low[2] >= structureLow and low[3] >= structureLow and bar_index[1] >  structureLowStartIndex and bar_index[2] >  structureLowStartIndex and bar_index[3] >  structureLowStartIndex) or (structureDirection == 2 and low < structureLow))
if(isStuctureLowBroken)
    // Check if structures to show is upper than user parameter
    if(array.size(structureLines) >= structHistoryNbr)

        // Delete the line and its index from arrays
        d.delete_line(array.get(structureLines, 0), array.get(structureLabels, 0))
        array.remove(structureLabels, 0)
        array.remove(structureLines, 0)
        

    // Create BOS line
    if(structureDirection == 1)  
        array.push(structureLines, line.new(structureLowStartIndex, structureLow, bar_index, structureLow, xloc=xloc.bar_index, extend=extend.none, color=bearishBosColor, style=bosLineStyle, width=bosLineWidth))
        array.push(structureLabels, label.new((bar_index + structureLowStartIndex) / 2, structureLow, text="BOS", style=label.style_none, textcolor=bearishBosColor))

    // Create CHoCH line
    else
        array.push(structureLines, line.new(structureLowStartIndex, structureLow, bar_index, structureLow, xloc=xloc.bar_index, extend=extend.none, color=bearishChochColor, style=chochLineStyle, width=chochLineWidth))
        array.push(structureLabels, label.new((bar_index + structureLowStartIndex) / 2, structureLow, text="CHoCH", style=label.style_none, textcolor=bearishChochColor))
    
    // Update values for new structure 
    structureDirection := 1
    structureHighStartIndex := structureMaxBar
    structureLowStartIndex  := bar_index
    structureHigh :=  high[bar_index - structureHighStartIndex] //highest
    structureLow  := low

// Check for breakout
else if(isStructureHighBroken)
    
    // Check if structures to show is upper than user parameter
    if(array.size(structureLines) >= structHistoryNbr)

        // Delete the line and its index from arrays
        d.delete_line(array.get(structureLines, 0), array.get(structureLabels, 0))
        array.remove(structureLabels, 0)
        array.remove(structureLines, 0)

    // Create BOS line
    if(structureDirection == 2)  
        array.push(structureLines, line.new(structureHighStartIndex, structureHigh, bar_index, structureHigh, xloc=xloc.bar_index, extend=extend.none, color=bullishBosColor, style=bosLineStyle, width=bosLineWidth))
        array.push(structureLabels, label.new((bar_index + structureHighStartIndex) / 2, structureHigh, text="BOS", style=label.style_none, textcolor=bullishBosColor))

    // Create CHoCH line
    else
        array.push(structureLines, line.new(structureHighStartIndex, structureHigh, bar_index, structureHigh, xloc=xloc.bar_index, extend=extend.none, color=bullishChochColor, style=chochLineStyle, width=chochLineWidth))
        array.push(structureLabels, label.new((bar_index + structureHighStartIndex) / 2, structureHigh, text="CHoCH", style=label.style_none, textcolor=bullishChochColor))

    // Update values for new structure
    structureDirection := 2
    structureHighStartIndex := bar_index 
    structureLowStartIndex  := structureMinBar
    structureHigh := high 
    structureLow  := low[bar_index - structureLowStartIndex] //lowest
else
    if(high > structureHigh and (structureDirection == 0 or structureDirection == 2))
        if(not(isStructBodyCandleBreak) or not(isStructBodyCandleBreak and bar_index[1] > structureHighStartIndex and bar_index[2] >  structureHighStartIndex and bar_index[3] > structureHighStartIndex))
            structureHigh := high
            structureHighStartIndex := bar_index
    else if(low < structureLow and (structureDirection == 0 or structureDirection == 1))
        if(not(isStructBodyCandleBreak) or not(isStructBodyCandleBreak and bar_index[1] > structureLowStartIndex and bar_index[2] > structureLowStartIndex and bar_index[3] > structureLowStartIndex))
            structureLow := low
            structureLowStartIndex := bar_index

structureRange = math.abs(structureHigh - structureLow)

// Affichage de la structure actuelle
if(isCurrentStructToShow)
    d.delete_line(structureHighLine, na)
    d.delete_line(structureLowLine, na)
    structureHighLine := line.new(structureHighStartIndex, structureHigh, bar_index, structureHigh, xloc.bar_index, color=currentStructColor, style = currentStructLineStyle, width = currentStructLineWidth)
    structureLowLine := line.new(structureLowStartIndex, structureLow, bar_index, structureLow, xloc.bar_index, color=currentStructColor, style = currentStructLineStyle, width = currentStructLineWidth)

    // Affichage du Fibonnacci 1 de la structure actuelle
    if(isFibo1ToShow)
        d.delete_line(fibo1Line, fibo1Label)
        fibo1Price := structureDirection == 1 ? structureHigh - (structureRange - structureRange * fibo1Value) : structureLow + (structureRange - structureRange * fibo1Value)
        fibo1StartIndex := structureDirection == 1 ? structureHighStartIndex : structureLowStartIndex  
        fibo1Line := line.new(fibo1StartIndex, fibo1Price, bar_index, fibo1Price, xloc.bar_index, color = fibo1Color, style = fibo1Style, width = fibo1LineWidth)
        fibo1Label := label.new(bar_index + 20, fibo1Price, text = str.tostring(fibo1Value) + "(" + str.tostring(fibo1Price) + ")", style = label.style_none, textcolor = fibo1Color) 

    // Affichage du Fibonnacci 2 de la structure actuelle
    if(isFibo2ToShow)
        d.delete_line(fibo2Line, fibo2Label)
        fibo2Price := structureDirection == 1 ? structureHigh - (structureRange - structureRange * fibo2Value) : structureLow + (structureRange - structureRange * fibo2Value)
        fibo2StartIndex := structureDirection == 1 ? structureHighStartIndex : structureLowStartIndex  
        fibo2Line := line.new(fibo2StartIndex, fibo2Price, bar_index, fibo2Price, xloc.bar_index, color = fibo2Color, style = fibo2Style, width = fibo2LineWidth)
        fibo2Label := label.new(bar_index + 20, fibo2Price, text = str.tostring(fibo2Value) + "(" + str.tostring(fibo2Price) + ")", style = label.style_none, textcolor = fibo2Color) 

    // Affichage du Fibonnacci 3 de la structure actuelle
    if(isFibo3ToShow)
        d.delete_line(fibo3Line, fibo3Label)
        fibo3Price := structureDirection == 1 ? structureHigh - (structureRange - structureRange * fibo3Value) : structureLow + (structureRange - structureRange * fibo3Value)
        fibo3StartIndex := structureDirection == 1 ? structureHighStartIndex : structureLowStartIndex  
        fibo3Line := line.new(fibo3StartIndex, fibo3Price, bar_index, fibo3Price, xloc.bar_index, color = fibo3Color, style = fibo3Style, width = fibo3LineWidth)
        fibo3Label := label.new(bar_index + 20, fibo3Price, text = str.tostring(fibo3Value) + "(" + str.tostring(fibo3Price) + ")", style = label.style_none, textcolor = fibo3Color) 

    // Affichage du Fibonnacci 1 de la structure actuelle
    if(isFibo4ToShow)
        d.delete_line(fibo4Line, fibo4Label)
        fibo4Price := structureDirection == 1 ? structureHigh - (structureRange - structureRange * fibo4Value) : structureLow + (structureRange - structureRange * fibo4Value)
        fibo4StartIndex := structureDirection == 1 ? structureHighStartIndex : structureLowStartIndex  
        fibo4Line := line.new(fibo4StartIndex, fibo4Price, bar_index, fibo4Price, xloc.bar_index, color = fibo4Color, style = fibo4Style, width = fibo4LineWidth)
        fibo4Label := label.new(bar_index + 20, fibo4Price, text = str.tostring(fibo4Value) + "(" + str.tostring(fibo4Price) + ")", style = label.style_none, textcolor = fibo4Color) 

    // Affichage du Fibonnacci 1 de la structure actuelle
    if(isFibo5ToShow)
        d.delete_line(fibo5Line, fibo5Label)
        fibo5Price := structureDirection == 1 ? structureHigh - (structureRange - structureRange * fibo5Value) : structureLow + (structureRange - structureRange * fibo5Value)
        fibo5StartIndex := structureDirection == 1 ? structureHighStartIndex : structureLowStartIndex  
        fibo5Line := line.new(fibo5StartIndex, fibo5Price, bar_index, fibo5Price, xloc.bar_index, color = fibo5Color, style = fibo5Style, width = fibo5LineWidth)
        fibo5Label := label.new(bar_index + 20, fibo5Price, text = str.tostring(fibo5Value) + "(" + str.tostring(fibo5Price) + ")", style = label.style_none, textcolor = fibo5Color) 

plot(na)