Untitled

 avatar
s7s
java
5 months ago
8.6 kB
19
Indexable

// github @ 2LV, telegram @ nqmicro, discord @ nqmicro

//@version=5
indicator("Institutional Supply & Demand Zones", overlay=true, max_boxes_count = 500)

//inputs
candleDifferenceScale = input.float(defval = 1.8, minval = 1, title = 'Zone Difference Scale', tooltip = 'The scale of how much a candle needs to be larger than a previous to be considered a zone (minimum value 1.0, default 1.8)', group = 'Zone Settings')

zoneOffset = input.int(defval = 15, minval = 0, title="Zone Extension", group = 'Display Settings', tooltip = 'How much to extend zones to the right of latest bar in bars')
displayLowerTFZones = input.bool(false, title="Display Lower Timeframe Zones", group = 'Display Settings', tooltip = 'Whether to or not to display zones from a lower timeframe (ie. 2h zones on 4h timeframe, Recommended OFF)')

supplyEnable = input(true, title = "Enable Supply Zones", group = "Zone Personalization")
supplyColor = input.color(defval = color.rgb(242, 54, 69, 94), title = 'Supply Background Color', group = 'Zone Personalization')
supplyBorderColor = input.color(defval = color.rgb(209, 212, 220, 90), title = 'Supply Border Color', group = 'Zone Personalization')

demandEnable = input(true, title = "Enable Demand Zones", group = "Zone Personalization")
demandColor = input.color(defval = color.rgb(76, 175, 80, 94), title = 'Demand Background Color', group = 'Zone Personalization')
demandBorderColor = input.color(defval = color.rgb(209, 212, 220, 80), title = 'Demand Border Color', group = 'Zone Personalization')

textEnable = input(true, title = "Display Text", group = 'Text Settings')
// 60 m 
displayHL = input.bool(false, title="Display High/Low", group = 'Text Settings', tooltip = 'Whether to or not to display the tops and bottoms of a zone as text (ie. Top: 4000.00 Bottom: 3900.00)')

// ======   text  ===== 

textColor = 
input.color(defval = color.rgb(255, 255, 255), title = 'Text Color', group = 'Text Settings')
//
textSize = 
input.string("Small", title="Text Size", options=["Auto", "Tiny", "Small", "Normal", "Large", "Huge"], group = 'Text Settings')
//
halign = 
input.string("Right", title="Horizontal Alignment", options=["Left", "Center", "Right"], group = 'Text Settings')
//
supplyValign = 
input.string("Bottom", title="Vertical Alignment (Supply)", options=["Top", "Center", "Bottom"], group = 'Text Settings')
//
demandValign = 
input.string("Top", title="Vertical Alignment (Demand)", options=["Top", "Center", "Bottom"], group = 'Text Settings')

// === DISPLAY TIME === 
// 
display15m = 
input.bool(true, title="Show 15m Zones", group = 'Timeframe Options')
//
display1h = 
input.bool(true, title="Show 1h Zones", group = 'Timeframe Options')
// 
display4h = 
input.bool(true, title="Show 4h Zones", group = 'Timeframe Options')
//
displayD = 
input.bool(false, title="Show 1D Zones", group = 'Timeframe Options')
//
// variables

currentTimeframe = timeframe.period

if currentTimeframe == 'D'
    currentTimeframe := '1440'
if currentTimeframe == 'W'
    currentTimeframe := '10080'
if displayLowerTFZones
    currentTimeframe := '0'

momentCTD = math.round(time(timeframe.period) + (zoneOffset * 60000 * str.tonumber(currentTimeframe)))

textSize := switch textSize
    "Auto" => size.auto
    "Tiny" => size.tiny
    "Small" => size.small
    "Normal" => size.normal
    "Large"   => size.large
    "Huge" => size.huge

halign := switch halign
    'Left'   => text.align_left
    'Center' => text.align_center
    'Right'  => text.align_right

supplyValign := switch supplyValign
    'Bottom'=> text.align_bottom
    'Center'=> text.align_center
    'Top'   => text.align_top

demandValign := switch demandValign
    'Bottom'=> text.align_bottom
    'Center'=> text.align_center
    'Top'   => text.align_top

var box[] supply_HT = array.new_box()
var box[] demand_HT = array.new_box()

//  ===   plotting zones  ===

createSupplyDemandZones(timeframe) =>

    [open_HT, high_HT, low_HT, close_HT]= request.security(syminfo.tickerid, timeframe, [open[1], high[1], low[1], close[1]], lookahead = barmerge.lookahead_on)

    var timeframeFormatted = switch timeframe
        '1'   => '1m'
        '3'   => '3m'
        '5'   => '5m'
        '16'  => '15m'
        '30'  => '30m'
        '45'  => '45m'
        '60'  => '1h'
        '120' => '2h'
        '180' => '3h'
        '240' => '4h'
        'D'   => '1D'
        'W'   => '1W'

    redCandle_HT = close_HT < open_HT
    greenCandle_HT = close_HT > open_HT
    neutralCandle_HT = close_HT == open_HT
    candleChange_HT = math.abs(close_HT - open_HT)

    var float bottomBox_HT = na
    var float topBox_HT = na
    momentCTD_HT = time(timeframe)[2]

    if (((redCandle_HT and greenCandle_HT[1]) or (redCandle_HT and neutralCandle_HT[1])) and (candleChange_HT / candleChange_HT[1]) >= candleDifferenceScale and barstate.isconfirmed[1] and supplyEnable and close_HT[1] >= close_HT and open_HT[1] <= open_HT)
        if displayHL
            timeframeFormatted := timeframeFormatted + '\nTop: ' + str.tostring(topBox_HT) + '\nBottom: ' + str.tostring(open_HT[1])
        if high_HT >= high_HT[1]
            topBox_HT := high_HT
        else 
            topBox_HT := high_HT[1]

        box supply = box.new(left=momentCTD_HT, top=topBox_HT, right=momentCTD, bgcolor=supplyColor, bottom=open_HT[1], xloc=xloc.bar_time)
        box.set_border_color(supply, supplyBorderColor)
        if textEnable
            box.set_text(supply, timeframeFormatted)
            box.set_text_size(supply, textSize)
            box.set_text_color(supply, textColor)
            box.set_text_halign(supply, halign)
            box.set_text_valign(supply, supplyValign)
        array.push(supply_HT, supply)

    if (((greenCandle_HT and redCandle_HT[1]) or (greenCandle_HT and neutralCandle_HT[1])) and (candleChange_HT / candleChange_HT[1]) >= candleDifferenceScale and barstate.isconfirmed[1] and demandEnable and close_HT[1] <= close_HT and open_HT[1] >= open_HT) 
        if displayHL
            timeframeFormatted := timeframeFormatted + '\nTop: ' + str.tostring(open_HT[1]) + '\nBottom: ' + str.tostring(bottomBox_HT)
        if low_HT <= low_HT[1]
            bottomBox_HT := low_HT
        else 
            bottomBox_HT := low_HT[1]

        box demand = box.new(left=momentCTD_HT, top=open_HT[1], right=momentCTD, bottom=bottomBox_HT, bgcolor=demandColor, xloc=xloc.bar_time)
        box.set_border_color(demand, demandBorderColor)
        if textEnable
            box.set_text(demand, timeframeFormatted)
            box.set_text_size(demand, textSize)
            box.set_text_color(demand, textColor)
            box.set_text_halign(demand, halign)
            box.set_text_valign(demand, demandValign)
        array.push(demand_HT, demand)

// initiation

// remove comments to add these zones to the chart (warning: this will break replay mode)
// if str.tonumber(currentTimeframe) <= 5
//    createSupplyDemandZones('5')
//if str.tonumber(currentTimeframe) <= 15
//    createSupplyDemandZones('15')
//if str.tonumber(currentTimeframe) <= 10
//    createSupplyDemandZones('10')
//if str.tonumber(currentTimeframe) <= 15
//    createSupplyDemandZones('15')
if display30m and str.tonumber(currentTimeframe) <= 30
    createSupplyDemandZones('30')
if display45m and str.tonumber(currentTimeframe) <= 45
    createSupplyDemandZones('45')
if display1h and str.tonumber(currentTimeframe) <= 60
    createSupplyDemandZones('60') 
if display2h and str.tonumber(currentTimeframe) <= 120
    createSupplyDemandZones('120')
if display3h and str.tonumber(currentTimeframe) <= 180
    createSupplyDemandZones('180')
if display4h and str.tonumber(currentTimeframe) <= 240
    createSupplyDemandZones('240')
if displayD and str.tonumber(currentTimeframe) <= 1440
    createSupplyDemandZones('D')
if displayW and str.tonumber(currentTimeframe) <= 10080
    createSupplyDemandZones('W')

// remove broken zones

i = 0
while i < array.size(supply_HT) and array.size(supply_HT) > 0
    box currentBox = array.get(supply_HT, i)
    float breakLevel = box.get_top(currentBox)
    if high > breakLevel 
        array.remove(supply_HT, i)
        box.delete(currentBox)
        int(na)
    else
        box.set_right(currentBox, momentCTD)
        i += 1
        int(na)

i2 = 0
while i2 < array.size(demand_HT) and array.size(demand_HT) > 0
    box currentBox = array.get(demand_HT, i2)
    float breakLevel = box.get_bottom(currentBox)
    if low < breakLevel 
        array.remove(demand_HT, i2)
        box.delete(currentBox)
        int(na)
    else
        box.set_right(currentBox, momentCTD)
        i2 += 1
        int(na)