SD

You might also like

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 4

//@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)

//------------

You might also like