Confluence Zones & Midpoints
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fvideira

// Study of Confluence Zone & Midpoints levels from Eliza123123's quantative trading series: https://youtu.be/C9hUlmPLVEk

//@version=5
indicator("Confluence Zones & Midpoints", overlay=true)


// Inputs


Confluence = input.bool(true, "On/Off", "", inline = "Line Colours", group = "Confluence Zones")
ConfluenceCol = input.color(color.new(color.aqua, 20), "", inline = "Line Colours", group = "Confluence Zones")

Midpoint = input.bool(true, "On/Off", "", inline = "Colour", group = "Midpoint")
MidpointCol = input.color(color.new(color.fuchsia, 80), "", inline = "Colour", group = "Midpoint")

extendRight = input.bool(false, "Extend Lines")
var extending = extend.none
if extendRight
    extending := extend.right
if not extendRight
    extending := extend.none

Table = input.bool(true, "On/Off", inline = "Col", group = "Table")
TableColUp = input.color(color.new(color.blue, 50), "Table Top", inline = "Col1", group = "Table")
TableColDown = input.color(color.new(color.fuchsia, 50), "Table Bottom", inline = "Col2", group = "Table")
TxtCol = input.color(color.new(color.white, 25), "Text", inline = "Col3", group = "Table")

    
// Scale Factors & Constants

scale = 0.0

if close >= 10000
    scale := 1000

if close >= 1000 and close <=9999.999999
    scale := 100

if close >= 100 and close <=999.999999
    scale := 10

if close >= 10 and close <=99.999999
    scale := 1
    
if close >= 1 and close <=9.999999
    scale := 0.1
    
if close >= 0.1 and close <=0.999999
    scale := 0.01

if close >= 0.01 and close <=0.099999
    scale := 0.001
    
if close >= 0.001 and close <=0.009999
    scale := 0.0001
    
e = 2.71828, pi = 3.14159
    
// Variables

z_1_low = 3 * scale, z_1_high = pi * scale

z_2_low = (4*e) * scale, z_2_high = 11 * scale

z_3_low = 19 * scale, z_3_high = (7*e) * scale

z_4_low = (15*e) * scale, z_4_high = (13*pi) * scale

z_5_low = 47 * scale, z_5_high = (15*pi) * scale

z_6_low = (19*pi) * scale, z_6_high = (22*e) * scale

z_7_low = (25*pi) * scale, z_7_high = (29*e) * scale

z_8_low = (30*e) * scale, z_8_high = (26*pi) * scale

// If clauses (for inputs to work as on/off)

if Confluence
    ConfluenceCol
else
    ConfluenceCol := na
    
if Midpoint
    MidpointCol
else
    MidpointCol := na

    
// Plots

z1 = line.new(bar_index[4999], z_1_low, bar_index, z_1_low, color = ConfluenceCol, width = 1, extend = extending)
z2 = line.new(bar_index[4999], z_1_high, bar_index, z_1_high, color = ConfluenceCol, width = 1, extend = extending)
z3 = line.new(bar_index[4999], z_2_low, bar_index, z_2_low, color = ConfluenceCol, width = 1, extend = extending)
z4 = line.new(bar_index[4999], z_2_high, bar_index, z_2_high, color = ConfluenceCol, width = 1, extend = extending)
z5 = line.new(bar_index[4999], z_3_low, bar_index, z_3_low, color = ConfluenceCol, width = 1, extend = extending)
z6 = line.new(bar_index[4999], z_3_high, bar_index, z_3_high, color = ConfluenceCol, width = 1, extend = extending)
z7 = line.new(bar_index[4999], z_4_low, bar_index, z_4_low, color = ConfluenceCol, width = 1, extend = extending)
z8 = line.new(bar_index[4999], z_4_high, bar_index, z_4_high, color = ConfluenceCol, width = 1, extend = extending)
z9 = line.new(bar_index[4999], z_5_low, bar_index, z_5_low, color = ConfluenceCol, width = 1, extend = extending)
z10 = line.new(bar_index[4999], z_5_high, bar_index, z_5_high, color = ConfluenceCol, width = 1, extend = extending)
z11 = line.new(bar_index[4999], z_6_low, bar_index, z_6_low, color = ConfluenceCol, width = 1, extend = extending)
z12 = line.new(bar_index[4999], z_6_high, bar_index, z_6_high, color = ConfluenceCol, width = 1, extend = extending)
z13 = line.new(bar_index[4999], z_7_low, bar_index, z_7_low, color = ConfluenceCol, width = 1, extend = extending)
z14 = line.new(bar_index[4999], z_7_high, bar_index, z_7_high, color = ConfluenceCol, width = 1, extend = extending)
z15 = line.new(bar_index[4999], z_8_low, bar_index, z_8_low, color = ConfluenceCol, width = 1, extend = extending)
z16 = line.new(bar_index[4999], z_8_high, bar_index, z_8_high, color = ConfluenceCol, width = 1, extend = extending)

midpoint1 = (z_1_high + z_2_low) / 2,   mp1 = line.new(bar_index[4999], midpoint1, bar_index, midpoint1, color = MidpointCol, width = 1, extend = extending)
midpoint2 = (z_2_high + z_3_low) / 2,   mp2 = line.new(bar_index[4999], midpoint2, bar_index, midpoint2, color = MidpointCol, width = 1, extend = extending)
midpoint3 = (z_3_high + z_4_low) / 2,   mp3 = line.new(bar_index[4999], midpoint3, bar_index, midpoint3, color = MidpointCol, width = 1, extend = extending)
midpoint4 = (z_4_high + z_5_low) / 2,   mp4 = line.new(bar_index[4999], midpoint4, bar_index, midpoint4, color = MidpointCol, width = 1, extend = extending)
midpoint5 = (z_5_high + z_6_low) / 2,   mp5 = line.new(bar_index[4999], midpoint5, bar_index, midpoint5, color = MidpointCol, width = 1, extend = extending)
midpoint6 = (z_6_high + z_7_low) / 2,   mp6 = line.new(bar_index[4999], midpoint6, bar_index, midpoint6, color = MidpointCol, width = 1, extend = extending)
midpoint7 = (z_7_high + z_8_low) / 2,   mp7 = line.new(bar_index[4999], midpoint7, bar_index, midpoint7, color = MidpointCol, width = 1, extend = extending)


// Distances from levels

dist1 = math.abs(close - z_1_low), dist2 = math.abs(close - z_1_high)
dist3 = math.abs(close - z_2_low), dist4 = math.abs(close - z_2_high)
dist5 = math.abs(close - z_3_low), dist6 = math.abs(close - z_3_high)
dist7 = math.abs(close - z_4_low), dist8 = math.abs(close - z_4_high)
dist9 = math.abs(close - z_5_low), dist10 = math.abs(close - z_5_high)
dist11 = math.abs(close - z_6_low), dist12 = math.abs(close - z_6_high)
dist13 = math.abs(close - z_7_low), dist14 = math.abs(close - z_7_high)
dist15 = math.abs(close - z_8_low), dist16 = math.abs(close - z_8_high)

closest_zone = math.min(dist1, dist2, dist3, dist4, dist5, dist6, dist7, dist8, dist9, dist10, dist11, dist12, dist13, dist14, dist15, dist16)

closest_zone_percent = (closest_zone / close) * 100

mdist1 = math.abs(close - midpoint1)
mdist2 = math.abs(close - midpoint2)
mdist3 = math.abs(close - midpoint3)
mdist4 = math.abs(close - midpoint4)
mdist5 = math.abs(close - midpoint5)
mdist6 = math.abs(close - midpoint6)
mdist7 = math.abs(close - midpoint7)

closest_midpoint = math.min(mdist1, mdist2, mdist3, mdist4, mdist5, mdist6, mdist7)

closest_mid_percent = (closest_midpoint / close) * 100

abovezone1 = string(""), belowzone1 = string("")
abovezone2 = string(""), belowzone2 = string("")
abovezone3 = string(""), belowzone3 = string("")
abovezone4 = string(""), belowzone4 = string("")
abovezone5 = string(""), belowzone5 = string("")
abovezone6 = string(""), belowzone6 = string("")
abovezone7 = string(""), belowzone7 = string("")
abovezone8 = string(""), belowzone8 = string("")

abovemidpoint1 = string(""), belowmidpoint1 = string("")
abovemidpoint2 = string(""), belowmidpoint2 = string("")
abovemidpoint3 = string(""), belowmidpoint3 = string("")
abovemidpoint4 = string(""), belowmidpoint4 = string("")
abovemidpoint5 = string(""), belowmidpoint5 = string("")
abovemidpoint6 = string(""), belowmidpoint6 = string("")
abovemidpoint7 = string(""), belowmidpoint7 = string("")


// Above or below for zones

if close < ((z_1_low + z_1_high) / 2) and close > 0.001 * scale
    abovezone1 := "above"
    belowzone1 := na
if close > ((z_1_low + z_1_high) / 2) and close < midpoint1
    abovezone1 := na
    belowzone1 := "below"
if close < 0.001 * scale
    abovezone1 := na
    belowzone1 := na
if close > midpoint2
    abovezone1 := na
    belowzone1 := na

if close < ((z_2_low + z_2_high) / 2) and close > midpoint1
    abovezone2 := "above"
    belowzone2 := na
if close > ((z_2_low + z_2_high) / 2) and close < midpoint2
    abovezone2 := na
    belowzone2 := "below"
if close < midpoint1
    abovezone2 := na
    belowzone2 := na
if close > midpoint2
    abovezone2 := na
    belowzone2 := na

if close < ((z_3_low + z_3_high) / 2) and close > midpoint2
    abovezone3 := "above"
    belowzone3 := na
if close > ((z_3_low + z_3_high) / 2) and close < midpoint3
    abovezone3 := na
    belowzone3 := "below"
if close < midpoint2
    abovezone3 := na
    belowzone3 := na
if close > midpoint3
    abovezone3 := na
    belowzone3 := na

if close < ((z_4_low + z_4_high) / 2) and close > midpoint3
    abovezone4 := "above"
    belowzone4 := na
if close > ((z_4_low + z_4_high) / 2) and close < midpoint4
    abovezone4 := na
    belowzone4 := "below"
if close < midpoint3
    abovezone4 := na
    belowzone4 := na
if close > midpoint4
    abovezone4 := na
    belowzone4 := na

if close < ((z_5_low + z_5_high) / 2) and close > midpoint4
    abovezone5 := "above"
    belowzone5 := na
if close > ((z_5_low + z_5_high) / 2) and close < midpoint5
    abovezone5 := na
    belowzone5 := "below"
if close < midpoint4
    abovezone5 := na
    belowzone5 := na
if close > midpoint5
    abovezone5 := na
    belowzone5 := na

if close < ((z_6_low + z_6_high) / 2) and close > midpoint5
    abovezone6 := "above"
    belowzone6 := na
if close > ((z_6_low + z_6_high) / 2) and close < midpoint6
    abovezone6 := na
    belowzone6 := "below"
if close < midpoint5
    abovezone6 := na
    belowzone6 := na
if close > midpoint6
    abovezone6 := na
    belowzone6 := na

if close < ((z_7_low + z_7_high) / 2) and close > midpoint6
    abovezone7 := "above"
    belowzone7 := na
if close > ((z_7_low + z_7_high) / 2) and close < midpoint7
    abovezone7 := na
    belowzone7 := "below"
if close < midpoint6
    abovezone7 := na
    belowzone7 := na
if close > midpoint7
    abovezone7 := na
    belowzone7 := na

if close < ((z_8_low + z_8_high) / 2) and close > midpoint7
    abovezone8 := "above"
    belowzone8 := na
if close > ((z_8_low + z_8_high) / 2) and close < 100 * scale
    abovezone8 := na
    belowzone8 := "below"
if close < midpoint7
    abovezone8 := na
    belowzone8 := na
if close > 100 * scale
    abovezone8 := na
    belowzone8 := na
    
    
// Above or below for midpoints

if close < midpoint1 and close > 0.001 * scale
    abovemidpoint1 := "above"
    belowmidpoint1 := na
if close > midpoint1 and close < ((midpoint1 + midpoint2) / 2)
    abovemidpoint1 := na
    belowmidpoint1 := "below"
if close < 0.001 * scale
    abovemidpoint1 := na
    belowmidpoint1 := na
if close > ((midpoint1 + midpoint2) / 2)
    abovemidpoint1 := na
    belowmidpoint1 := na
    
if close < midpoint2 and close > ((midpoint1 + midpoint2) / 2)
    abovemidpoint2 := "above"
    belowmidpoint2 := na
if close > midpoint2 and close < ((midpoint2 + midpoint3) / 2)
    abovemidpoint2 := na
    belowmidpoint2 := "below"
if close < ((midpoint1 + midpoint2) / 2)
    abovemidpoint2 := na
    belowmidpoint2 := na
if close > ((midpoint2 + midpoint3) / 2)
    abovemidpoint2 := na
    belowmidpoint2 := na
    
if close < midpoint3 and close > ((midpoint2 + midpoint3) / 2)
    abovemidpoint3 := "above"
    belowmidpoint3 := na
if close > midpoint3 and close < ((midpoint3 + midpoint4) / 2)
    abovemidpoint3 := na
    belowmidpoint3 := "below"
if close < ((midpoint2 + midpoint3) / 2)
    abovemidpoint3 := na
    belowmidpoint3 := na
if close > ((midpoint3 + midpoint4) / 2)
    abovemidpoint3 := na
    belowmidpoint3 := na

if close < midpoint4 and close > ((midpoint3 + midpoint4) / 2)
    abovemidpoint4 := "above"
    belowmidpoint4 := na
if close > midpoint4 and close < ((midpoint4 + midpoint5) / 2)
    abovemidpoint4 := na
    belowmidpoint4 := "below"
if close < ((midpoint3 + midpoint4) / 2)
    abovemidpoint4 := na
    belowmidpoint4 := na
if close > ((midpoint4 + midpoint5) / 2)
    abovemidpoint4 := na
    belowmidpoint4 := na
    
if close < midpoint5 and close > ((midpoint4 + midpoint5) / 2)
    abovemidpoint5 := "above"
    belowmidpoint5 := na
if close > midpoint5 and close < ((midpoint5 + midpoint6) / 2)
    abovemidpoint5 := na
    belowmidpoint5 := "below"
if close < ((midpoint4 + midpoint5) / 2)
    abovemidpoint5 := na
    belowmidpoint5 := na
if close > ((midpoint5 + midpoint6) / 2)
    abovemidpoint5 := na
    belowmidpoint5 := na

if close < midpoint6 and close > ((midpoint5 + midpoint6) / 2)
    abovemidpoint6 := "above"
    belowmidpoint6 := na
if close > midpoint6 and close < ((midpoint6 + midpoint7) / 2)
    abovemidpoint6 := na
    belowmidpoint6 := "below"
if close < ((midpoint5 + midpoint6) / 2)
    abovemidpoint6 := na
    belowmidpoint6 := na
if close > ((midpoint6 + midpoint7) / 2)
    abovemidpoint6 := na
    belowmidpoint6 := na

if close < midpoint7 and close > ((midpoint6 + midpoint7) / 2)
    abovemidpoint7 := "above"
    belowmidpoint7 := na
if close > midpoint7 and close < 100 * scale
    abovemidpoint7 := na
    belowmidpoint7 := "below"
if close < ((midpoint6 + midpoint7) / 2)
    abovemidpoint7 := na
    belowmidpoint7 := na
if close > 100 * scale
    abovemidpoint7 := na
    belowmidpoint7 := na

abovezone = abovezone1 + abovezone2 + abovezone3 + abovezone4 + abovezone5 + abovezone6 + abovezone7 + abovezone8
belowzone = belowzone1 + belowzone2 + belowzone3 + belowzone4 + belowzone5 + belowzone6 + belowzone7 + belowzone8

abovemidpoint = abovemidpoint1 + abovemidpoint2 + abovemidpoint3 + abovemidpoint4 + abovemidpoint5 + abovemidpoint6 + abovemidpoint7
belowmidpoint = belowmidpoint1 + belowmidpoint2 + belowmidpoint3 + belowmidpoint4 + belowmidpoint5 + belowmidpoint6 + belowmidpoint7

abovebelowzone = abovezone + belowzone
abovebelowmidpoint = abovemidpoint + belowmidpoint

// Table

var dataTable = table.new(position = position.top_right, columns = 1, rows = 2, bgcolor = color.new(color.blue, 40))
if Table
    if barstate.islast
        table.cell(table_id = dataTable, column = 0, row = 0, text = "Nearest Zone: " + str.tostring(closest_zone_percent) + "% " + str.tostring(abovebelowzone), bgcolor = TableColUp, text_color = TxtCol)
        table.cell(table_id = dataTable, column = 0, row = 1, text = "Nearest Midpoint: " + str.tostring(closest_mid_percent) + "% " + str.tostring(abovebelowmidpoint), bgcolor = TableColDown, text_color = TxtCol)
else 
    na
