Untitled
unknown
plain_text
9 months ago
9.2 kB
8
Indexable
//@version=5
indicator("S&D ZONES"
, overlay = true
, max_labels_count = 500
, max_lines_count = 500
, max_boxes_count = 500
, max_bars_back = 500)
max_bars_back(time, 500)
//-----------------------------------------------------------------------------{
//Constants
//-----------------------------------------------------------------------------{
int DEMAND_ZONE = 1
int SUPPLY_ZONE = 2
int TBD_ZONE = 0
//-----------------------------------------------------------------------------{
//Settings
//-----------------------------------------------------------------------------{
// -- Indecision ----
indecision_factor = input.int(2, 'Min. Factor', minval = 1, group = "Indecision")
volume_periods = input.int(26, 'Previous Periods', minval = 1, group = "Indecision")
volume_chg = input.int(10, 'Volume Change (%)', minval = 1, group = "Indecision")
confirm_bars = input.int(2, 'Confirmation Bars', minval = 1, group = 'Indecision')
invalidation = input.string('Wick', 'Invalidation Method', options = ['Close', 'Wick'], group = "Indecision")
// -- Zones ----
showlast = input.int(10, 'Show Last', minval = 1, group = 'Zones')
demand_zone_css = input.color(color.new(#66bb6a, 70), 'Demand', inline = "Zones", group = 'Zones')
supply_zone_css = input.color(color.new(#f77c80, 70), 'Supply', inline = "Zones", group = 'Zones')
indecision_zone_css = input.color(color.new(#777575, 70), 'Indecision', inline = "Zones",group = 'Zones')
text_size = input.string('Small', 'Text Size', options = ['Tiny', 'Small', 'Normal'], group = "Zones")
//Global variables
//-----------------------------------------------------------------------------{
var zone_boxes = array.new_box(0)
var zone_labels = array.new_label(0)
type Zone
float top
float bottom
float volume
int left
int type = 0
color css
int reached = 0
int bars_outside = 0
var zones = array.new<Zone>(0)
var last_zone_reached = Zone.new()
bool demand_zone_confirmed = false
bool supply_zone_confirmed = false
bool price_enter_supply_zone = false
bool price_enter_demand_zone = false
var label_size = text_size == 'Tiny' ? size.tiny: text_size == 'Small' ? size.small : size.normal
//------------------------------------------------------------------
// FUNCTIONS
//-----------------------------------------------------------------
get_volume(include_current_bar, bars) =>
past_vol = array.new_float(0)
for i = include_current_bar ? 0: 1 to bars
array.push(past_vol, volume[i])
array.avg(past_vol)
is_indecision_bar() =>
//Is an indecision candle?
float high_change = 0.
float low_change = 0.
float body_change = math.abs((close - open) / open)
if close > open
high_change := math.abs((high - close) / close)
low_change := math.abs((low - open) / open)
else
high_change := math.abs((high - open) / open)
low_change := math.abs((low - close) / close)
float factor = math.floor(math.max(high_change, low_change) / body_change)
factor := na(factor) or factor > 999999 ? 999999 : factor
bool add_as_new_zone = false
if factor >= indecision_factor
add_as_new_zone := true
for zone in zones
//if the candle its include in some previous candle don't add
if (high < zone.top and high > zone.bottom) and (low < zone.top and low > zone.bottom)
add_as_new_zone := false
break
else if zone.type == DEMAND_ZONE and (low < zone.top and low > zone.bottom) and (high >= zone.top)
add_as_new_zone := false
break
else if zone.type == SUPPLY_ZONE and (high < zone.top and high > zone.bottom) and (low <= zone.bottom)
add_as_new_zone := false
break
add_as_new_zone
valid_zone(zone, bclose, bhigh, blow) =>
if zone.type == DEMAND_ZONE
demand_bar_price = invalidation == 'Close' ? bclose : blow
demand_bar_price >= zone.bottom //and bopen > zone.bottom
else if zone.type == SUPPLY_ZONE
supply_bar_price = invalidation == 'Close' ? bclose : bhigh
supply_bar_price <= zone.top //and bopen < zone.top
else
true
bar_reached_zone(zone, wick) =>
(wick >= zone.bottom and wick <= zone.top) or (close >= zone.bottom and close <= zone.top) or (open >= zone.bottom and open <= zone.top)
is_lateral_movement(zone, candles) =>
int inside = 0
for i = 1 to candles
if (close[i] < zone.top and close[i] > zone.bottom) and (open[i] < zone.top and open[i] > zone.bottom)
inside += 1
inside >= candles
confirm_zone(zone) =>
valid_zone = true
new_volume = get_volume(true, confirm_bars)
zone.volume := math.round((new_volume - zone.volume) / zone.volume * 100, 0)
if math.max(open, close) > zone.top
zone.type := DEMAND_ZONE
zone.css := demand_zone_css
else if math.min(open, close) < zone.bottom
zone.type := SUPPLY_ZONE
zone.css := supply_zone_css
if math.abs(zone.volume) >= volume_chg
and zone.type != TBD_ZONE
and not is_lateral_movement(zone, confirm_bars)
for i = 0 to confirm_bars - 1
if not valid_zone(zone, close[i], high[i], low[i])
valid_zone := false
break
else
valid_zone := false
valid_zone
display_zones(boxes, labels, dzones, show_last, zsize) =>
for i = 0 to math.min(show_last - 1, zsize - 1)
zindex = zsize - (1 + i)
get_box = array.get(boxes, i)
get_label = array.get(labels, i)
zone = array.get(dzones, zindex)
box.set_lefttop(get_box, zone.left, zone.top)
box.set_rightbottom(get_box, zone.left, zone.bottom)
box.set_border_color(get_box, zone.css)
box.set_bgcolor(get_box, zone.css)
label.set_textcolor(get_label, color.new(zone.css, 0))
label.set_xy(get_label, bar_index + 5, zone.bottom)
if zone.type == TBD_ZONE
label.set_text(get_label, "")
else
label.set_text(get_label, "Volume change: " + str.tostring(zone.volume) + "%\nReached: " + str.tostring(zone.reached))
//------------------------------------------------------------------
// CALCULATE ZONES
//------------------------------------------------------------------
if barstate.isfirst
for i = 0 to showlast - 1
array.push(zone_boxes, box.new(na,na,na,na, xloc = xloc.bar_time , extend = extend.right))
array.push(zone_labels, label.new(na,na,na, size = label_size, style = label.style_none))
if barstate.isconfirmed
if is_indecision_bar()
period_volume = get_volume(include_current_bar = false, bars = volume_periods)
array.push(zones, Zone.new(top = high, bottom = low, volume = period_volume, left = time, css= indecision_zone_css))
for zone in zones
index = array.indexof(zones, zone)
if zone.type == TBD_ZONE and zone.left == time[confirm_bars]
// Confirm zone o delete it
if confirm_zone(zone)
demand_zone_confirmed := zone.type == DEMAND_ZONE
supply_zone_confirmed := zone.type == SUPPLY_ZONE
for i = 1 to confirm_bars
pindex = index + 1
if pindex < array.size(zones)
array.remove(zones, pindex)
else
array.remove(zones, index)
break
for zone in zones
index = array.indexof(zones, zone)
if not valid_zone(zone, close, high, low)
if last_zone_reached.left == zone.left
last_zone_reached := Zone.new()
array.remove(zones, index)
else
// Check if price reached any zone
if zone.type == DEMAND_ZONE and bar_reached_zone(zone, low)
zone.reached += 1
price_enter_demand_zone := true
if zone.type == SUPPLY_ZONE and bar_reached_zone(zone, high)
zone.reached += 1
price_enter_supply_zone := true
if price_enter_demand_zone or price_enter_supply_zone
zone.bars_outside := 0
last_zone_reached := zone
if last_zone_reached.type == DEMAND_ZONE and close > last_zone_reached.top //and open > last_zone_reached.top
last_zone_reached.bars_outside += 1
else if last_zone_reached.type == SUPPLY_ZONE and close < last_zone_reached.bottom //and open < last_zone_reached.bottom
last_zone_reached.bars_outside += 1
if barstate.islast
int zones_size = array.size(zones)
if zones_size > 0
display_zones(zone_boxes, zone_labels, zones, showlast, zones_size)
//------------
Editor is loading...
Leave a Comment