csw-smart-money-concepts-beta.pine
Copy
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © goodgains
//@version=5
indicator("CSW Smart-Money-Concepts [BETA]", overlay = true, max_labels_count = 500, max_boxes_count = 500, max_lines_count = 500, max_bars_back = 1000)
// @keywords: smart-money-concepts, supply-demand-zones, order-block-boxes, swing-labels, higher-high-lower-low, break-of-structure, fair-value-gaps, prior-day-levels, prior-week-levels, prior-month-levels, pivot-swing-detection, atr-zone-width, overlapping-filter, zone-to-bos, fvg-merge-fill, mtf-structure-lines, equilibrium-mid, zone-extension, imbalance-gaps, instruction-label
//--INSTRUCTIONS--//
instructions_tooltip = "• Supply/Demand = zones where buyers or sellers will look to enter the market.
\n• Price-Action Labels = swing highs and swing lows labeled to show if market is bullish or bearish. Hover to see details.
\n• Break-of-Structure (BOS) = previous supply/demand zones that were broken. Often times will be retested.
\n• Fair-Value Gaps (FVGs) = created by one-way inefficiencies. If they hold on retests they are great entries.
\n• MTF Structure = draws lines at a prior level. Can be prior day, prior week, or prior month.
"
instructions = input.bool(title='Show Instructions', defval=false, inline='1', tooltip = instructions_tooltip)
if barstate.islast and instructions
var label instruction_label = na
if not na(instruction_label[1])
label.delete(instruction_label[1])
instruction_label := label.new(bar_index + 5, close, instructions_tooltip, xloc = xloc.bar_index , yloc = yloc.price, color = color.black , style = label.style_label_left, textcolor = color.white, size = size.large, textalign = text.align_left)
//--INSTRUCTIONS--//
//--GLOBAL INPUTS--//
show_supplydemand = input.bool(true, title = 'Supply/Demand Zones (Orderblocks)', group = 'CSW SMC Options', inline = '1', tooltip = 'Supply/Demand are price action zones that are drawn based on prior
swing highs and swing lows. Supply Zones act as resisPatternsnce. Demand Zones act as support.')
show_priceaction = input.bool(true, title = 'Price Action Labels', group = 'CSW SMC Options', inline = '2', tooltip = 'Price Action Labels mark at each swing high or swing low. \n\nHH = Higher High \nLH = Lower High \nLL=
Lower Low \nLH = Lower High')
show_bos = input.bool(true, title = 'Break-of-Structure (BOS)', group = 'CSW SMC Options', inline = '3', tooltip = 'BOS or Break-of-Structure, are previous supply and demand zones that were broken. To break a Supply Zone we
close above it. To break a Demand Zone we must close below.')
show_fvg = input.bool(true, title = 'Fair-Value Gaps (FVG)', group = 'CSW SMC Options', inline = '4', tooltip = 'FVGs or Fair-Value Gaps mark inefficiencies, or imbalances, in price-aciton.
A FVG is drawn when there is a one-directional price-action move that is not backfilled on the next candle. A new FVG marks a behavioral change in the market. If the FVG holds and then
price-action creates a confirming pattern, price can continue to move away from the FVG.')
show_mtfstructure = input.bool(true, title = 'Multi-Timeframe Structure (MTF)', group = 'CSW SMC Options', inline = '5', tooltip = 'Prior Time Structure shows the previous
(Set by user. Day, Week, Month, or All the Above) price action structures. These levels are not rocket science, but are used by traders everywhere as key inflection points in
the market. \n\nPD = Prior Day \nPW = Prior Week \nPM = Prior Month \n\nC = Close \nH = High \nL = Low \nM = Mid or Equilibrium')
mtf_structures = input.string('Day', title = '', options = ['Day', 'Week', 'Month', 'Day & Week', 'Day & Month', 'Week & Month', 'All'],group = 'CSW SMC Options', inline = '5')
//--GLOBAL INPUTS--//
//--SUPPLY DEMAND INPUTS--//
sd_length = input.int(20, title = 'Supply/Demand Length', group = 'Supply/Demand Settings', minval = 3, maxval = 50)
sd_width = input.float(7.00, title = 'Supply/Demand Width', group = 'Supply/Demand Settings', minval = 1, maxval = 15, step = 0.5)
sd_history = 50
supply_color = input.color(color.new(#b63632,70), title = 'Supply', group = 'Supply/Demand Settings', inline = '3')
demand_color = input.color(color.new(#27a69b,70), title = 'Demand', group = 'Supply/Demand Settings', inline = '3')
sd_labelcolor = input.color(color.new(color.white,20), title = 'Label', group = 'Supply/Demand Settings', inline = '3')
//--SUPPLY DEMAND INPUTS--//
//--PRICE ACTION INPUTS--//
pa_color = input.color(color.new(color.white, 60), title = 'Label', group = 'Price Action Label Settings', inline = '1')
//--PRICE ACTION INPUTS--//
//--BOS INPUTS--//
bos_color = input.color(color.new(color.white, 75), title = 'Line & Label', group = 'Break-of-Structure (BOS) Settings', inline = '1')
//--BOS INPUTS--//
//--FVG INPUTS--//
fvg_minimize_onfill = input.bool(true, title = 'Adjust FVG Box As It Fills', group = 'Fair-Value Gaps', inline = '1')
fvg_delete_filled = input.bool(false, title = 'Delete Filled FVGs', group = 'Fair-Value Gaps', inline = '2')
fvg_sensitivity = input.int(250, title = 'FVG Sensitivity', group = 'Fair-Value Gaps', inline = '3', minval = 100, maxval = 500, step = 25)
bull_fvg_css = input.color(color.new(#000000, 70), 'Bull FVG BG', group = 'Fair-Value Gaps', inline = '4')
bear_fvg_css = input.color(color.new(#000000, 70), 'Bear FVG BG', group = 'Fair-Value Gaps', inline = '4')
bull_fvgb_css = input.color(color.new(#27a69b, 20), 'Bull FVG Outline', group = 'Fair-Value Gaps', inline = '5')
bear_fvgb_css = input.color(color.new(#b63632, 20), 'Bear FVG Outline', group = 'Fair-Value Gaps', inline = '5')
//--FVG INPUTS--//
//--MTF STRUCTURE INPUTS--//
// options = ['Day', 'Week', 'Month', 'Day & Week', 'Day & Month', 'Week & Month', 'All']
mtf_showday = mtf_structures == 'Day' or mtf_structures == 'Day & Week' or mtf_structures == 'Day & Month' or mtf_structures == 'All'
mtf_showweek = mtf_structures == 'Week' or mtf_structures == 'Day & Week' or mtf_structures == 'Week & Month' or mtf_structures == 'All'
mtf_showmonth = mtf_structures == 'Month' or mtf_structures == 'Day & Month' or mtf_structures == 'Week & Month' or mtf_structures == 'All'
mtf_priorhighs = input.bool(true, title = 'Prior Highs', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '1')
mtf_priorlows = input.bool(true, title = 'Prior Lows', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '1')
mtf_priorclose = input.bool(true, title = 'Prior Close', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '2')
mtf_priormids = input.bool(true, title = 'Prior Mid', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '2')
mtf_day_css = input.color(color.new(color.white,70), title = 'Day Color', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '3')
mtf_week_css = input.color(color.new(color.white,70), title = 'Week Color', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '4')
mtf_month_css = input.color(color.new(color.white,70), title = 'Month Color', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '5')
mtf_label_css = input.color(color.new(color.white, 60), title = 'Label Color', group = 'Multi-Timeframe Structure (MTF) Settings', inline = '6')
//-----INPUTS-----//
//-----FUNCTIONS-----//
//--FUNCTION TO ADD NEW AND REMOVE LAST IN ARRAY--//
f_array_add_pop(array, new_value_to_add) =>
array.unshift(array, new_value_to_add)
array.pop(array)
//--FUNCTION TO ADD NEW AND REMOVE LAST IN ARRAY--//
//--FUNCTION SWING H & L LABELS--//
f_sh_sl_labels(array, swing_type) =>
var string label_text = na
if swing_type == 1
if array.get(array, 0) >= array.get(array, 1)
label_text := 'HH'
else
label_text := 'LH'
label.new(bar_index - sd_length, array.get(array,0), text = label_text, style=label.style_label_down, textcolor = pa_color, color = color.new(pa_color, 100), size = size.tiny, tooltip = label_text)
else if swing_type == -1
if array.get(array, 0) >= array.get(array, 1)
label_text := 'HL'
else
label_text := 'LL'
label.new(bar_index - sd_length, array.get(array,0), text = label_text, style=label.style_label_up, textcolor = pa_color, color = color.new(pa_color, 100), size = size.tiny, tooltip = label_text)
//--FUNCTION SWING H & L LABELS--//
//--FUNCTION MAKE SURE SUPPLY ISNT OVERLAPPING--//
f_check_overlapping(new_poi, box_array, atr) =>
atr_threshold = atr * 2
okay_to_draw = true
for i = 0 to array.size(box_array) - 1
top = box.get_top(array.get(box_array, i))
bottom = box.get_bottom(array.get(box_array, i))
poi = (top + bottom) / 2
upper_boundary = poi + atr_threshold
lower_boundary = poi - atr_threshold
if new_poi >= lower_boundary and new_poi <= upper_boundary
okay_to_draw := false
break
else
okay_to_draw := true
okay_to_draw
//--FUNCTION MAKE SURE SUPPLY ISNT OVERLAPPING--//
//--FUNCTION TO DRAW SUPPLY OR DEMAND ZONE--//
f_supply_demand(value_array, bn_array, box_array, box_type, atr) =>
atr_buffer = atr * (sd_width / 10)
box_left = array.get(bn_array, 0)
box_right = bar_index
var float box_top = 0.00
var float box_bottom = 0.00
var float poi = 0.00
if box_type == 1
box_top := array.get(value_array, 0)
box_bottom := box_top - atr_buffer
poi := (box_top + box_bottom) / 2
else if box_type == -1
box_bottom := array.get(value_array, 0)
box_top := box_bottom + atr_buffer
poi := (box_top + box_bottom) / 2
okay_to_draw = f_check_overlapping(poi, box_array, atr)
//delete oldest box, and then create a new box and add it to the array
if box_type == 1 and okay_to_draw
box.delete( array.get(box_array, array.size(box_array) - 1) )
f_array_add_pop(box_array, box.new( left = box_left, top = box_top, right = box_right, bottom = box_bottom, border_color = show_supplydemand ? color.new(supply_color,30) : color.new(#000000,100),
bgcolor = show_supplydemand ? supply_color : color.new(#000000,100), extend = extend.right, text = show_supplydemand ? 'SUPPLY' : '', text_halign = text.align_center, text_valign = text.align_center, text_color = sd_labelcolor, text_size = size.small, xloc = xloc.bar_index))
else if box_type == -1 and okay_to_draw
box.delete( array.get(box_array, array.size(box_array) - 1) )
f_array_add_pop(box_array, box.new( left = box_left, top = box_top, right = box_right, bottom = box_bottom, border_color = show_supplydemand ? color.new(demand_color,30) : color.new(#000000,100),
bgcolor = show_supplydemand ? demand_color : color.new(#000000,100), extend = extend.right, text = show_supplydemand ? 'DEMAND' : '', text_halign = text.align_center, text_valign = text.align_center, text_color = sd_labelcolor, text_size = size.small, xloc = xloc.bar_index))
//--FUNCTION TO DRAW SUPPLY OR DEMAND ZONE--//
//--FUNCTION TO CHANGE SUPPLY/DEMAND TO A BOS IF BROKEN--//
f_sd_to_bos(box_array, bos_array, zone_type) =>
for i = 0 to array.size(box_array) - 1
level_to_break = zone_type == 1 ? box.get_top(array.get(box_array,i)) : box.get_bottom(array.get(box_array,i))
if (zone_type == 1 and close >= level_to_break) or (zone_type == -1 and close <= level_to_break)
if show_bos
copied_box = box.copy(array.get(box_array,i))
f_array_add_pop(bos_array, copied_box)
bos_level = zone_type == 1 ? box.get_top(array.get(box_array,i)) : box.get_bottom(array.get(box_array,i))
box.set_top(array.get(bos_array,0), bos_level)
box.set_bottom(array.get(bos_array,0), bos_level)
box.set_extend( array.get(bos_array,0), extend.none)
box.set_right( array.get(bos_array,0), bar_index)
box.set_text( array.get(bos_array,0), 'BOS' )
box.set_text_color( array.get(bos_array,0), color.new(bos_color, 40))
box.set_border_color( array.get(bos_array,0), bos_color)
box.set_text_size( array.get(bos_array,0), size.small)
box.set_text_halign( array.get(bos_array,0), text.align_center)
box.set_text_valign( array.get(bos_array,0), text.align_center)
box.delete(array.get(box_array, i))
//--FUNCTION TO CHANGE SUPPLY/DEMAND TO A BOS IF BROKEN--//
//--FUNCTION MANAGE CURRENT BOXES BY CHANGING ENDPOINT--//
f_extend_box_endpoint(box_array) =>
for i = 0 to array.size(box_array) - 1
box.set_right(array.get(box_array, i), bar_index + 100)
//--FUNCTION MANAGE CURRENT BOXES BY CHANGING ENDPOINT--//
//--FUNCTION FOR GETTING MTF VALUES AND PLOTTING THEM--//
f_mtf_values(time_period, bar_start, line_color, label_color, label_text , tooltip_text) =>
highs = request.security(syminfo.tickerid,time_period, high[1], lookahead=barmerge.lookahead_on)
lows = request.security(syminfo.tickerid,time_period, low[1], lookahead=barmerge.lookahead_on)
closes = request.security(syminfo.tickerid,time_period, close[1], lookahead=barmerge.lookahead_on)
var prior_high_line = array.new_line(0, na)
var prior_high_label = array.new_label(0, na)
if mtf_priorhighs
array.insert(prior_high_line, 0, line.new(bar_start, highs, bar_index, y2 = highs, xloc = xloc.bar_index, extend = extend.right, color =
line_color, style = line.style_dashed, width = 1))
array.insert(prior_high_label, 0, label.new(x = bar_index + 70, y = highs, text = label_text + "H", style = label.style_none,
size = size.tiny, textcolor = label_color, tooltip = tooltip_text + "High " + str.tostring(highs)))
var prior_low_line = array.new_line(0, na)
var prior_low_label = array.new_label(0, na)
if mtf_priorlows
array.insert(prior_low_line, 0, line.new(bar_start, lows, bar_index, y2 = lows, xloc = xloc.bar_index, extend = extend.right, color =
line_color, style = line.style_dashed, width = 1))
array.insert(prior_low_label, 0, label.new(x = bar_index + 70, y = lows, text = label_text + "L", style = label.style_none,
size = size.tiny, textcolor = label_color, tooltip = tooltip_text + "Low " +str.tostring(lows)))
var prior_close_line = array.new_line(0, na)
var prior_close_label = array.new_label(0, na)
if mtf_priorclose
array.insert(prior_close_line, 0, line.new(bar_start, closes, bar_index, y2 = closes, xloc = xloc.bar_index, extend = extend.right, color =
line_color, style = line.style_dashed, width = 1))
array.insert(prior_close_label, 0, label.new(x = bar_index + 70, y = closes, text = label_text + "C", style = label.style_none,
size = size.tiny, textcolor = label_color, tooltip = tooltip_text + "Close " +str.tostring(closes)))
var prior_mid_line = array.new_line(0, na)
var prior_mid_label = array.new_label(0, na)
if mtf_priormids
array.insert(prior_mid_line, 0, line.new(bar_start, (highs + lows) / 2, bar_index, y2 = (highs + lows) / 2, xloc = xloc.bar_index, extend = extend.right, color =
line_color, style = line.style_dashed, width = 1))
array.insert(prior_mid_label, 0, label.new(x = bar_index + 70, y = (highs + lows) / 2, text = label_text + "M", style = label.style_none,
size = size.tiny, textcolor = label_color, tooltip = tooltip_text + "Mid " +str.tostring((highs + lows) / 2)))
//--FUNCTION FOR GETTING MTF VALUES AND PLOTTING THEM--//
//--FUNCTION TO DRAW NEW FVGS--//
f_new_fvg(box_array, box_type) =>
box_left = bar_index - 1
box_right = bar_index + 3
box_top = box_type == 1 ? low : math.max( (high[1] + low[1])/2, low[2] )
box_bottom = box_type == 1 ? math.min( (high[1] + low[1])/2, high[2] ) : high
if box_type == 1
box.delete( array.get(box_array, array.size(box_array) - 1) )
f_array_add_pop(box_array, box.new( left = box_left, top = box_top, right = box_right, bottom = box_bottom, border_color = bull_fvgb_css,
bgcolor = bull_fvg_css, extend = extend.none, text = 'FVG', text_halign = text.align_center, text_valign = text.align_bottom,
text_color = color.new(bull_fvgb_css,20), text_size = size.small, xloc = xloc.bar_index, border_style = line.style_solid, border_width = 1))
if box_type == -1
f_array_add_pop(box_array, box.new( left = box_left, top = box_top, right = box_right, bottom = box_bottom, border_color = bear_fvgb_css,
bgcolor = bear_fvg_css, extend = extend.none, text = 'FVG', text_halign = text.align_center, text_valign = text.align_top,
text_color = color.new(bear_fvgb_css,20), text_size = size.small, xloc = xloc.bar_index, border_style = line.style_solid, border_width = 1))
//--FUNCTION TO DRAW NEW FVGS--//
//--FUNCTION TO COMBINE FVGS--//
f_merge_fvg(box_array, box_type) =>
if box_type == 1
box.set_top(array.get(box_array,0), low)
if box_type == -1
box.set_bottom(array.get(box_array,0), high)
//--FUNCTION TO COMBINE FVGS--//
//--FUNCTION TO MANAGE FVGS--//
f_manage_fvg(box_array, finished_box_array, box_type) =>
// loop to move broken fvgs to finished and extend unbroken ones
for i = 0 to array.size(box_array) - 1
box_top = box.get_top(array.get(box_array,i))
box_bottom = box.get_bottom(array.get(box_array,i))
if box_type == 1
if low < box_bottom
if not fvg_delete_filled
copied_box = box.copy(array.get(box_array,i))
f_array_add_pop(finished_box_array, copied_box)
box.set_extend(array.get(finished_box_array,0), extend.none)
box.set_right(array.get(finished_box_array,0),bar_index)
box.set_text(array.get(finished_box_array,0), 'FVG')
box.set_text_color(array.get(finished_box_array,0), color.new(bull_fvgb_css, 40))
box.set_border_color(array.get(finished_box_array,0), color.new(bull_fvgb_css, 40))
box.set_border_width(array.get(finished_box_array,0),0)
box.set_text_size(array.get(finished_box_array,0), size.small)
box.delete( array.get(box_array, i) )
else if fvg_minimize_onfill and low < box_top
box.set_top( array.get(box_array,i), low)
else
box.set_right(array.get(box_array,i),bar_index)
if box_type == -1
if high > box_top
if not fvg_delete_filled
copied_box = box.copy(array.get(box_array,i))
f_array_add_pop(finished_box_array, copied_box)
box.set_extend(array.get(finished_box_array,0), extend.none)
box.set_right(array.get(finished_box_array,0),bar_index)
box.set_text(array.get(finished_box_array,0), 'FVG')
box.set_text_color(array.get(finished_box_array,0), color.new(bear_fvgb_css, 40))
box.set_border_color(array.get(finished_box_array,0), color.new(bear_fvgb_css, 40))
box.set_border_width(array.get(finished_box_array,0),0)
box.set_text_size(array.get(finished_box_array,0), size.small)
box.delete( array.get(box_array, i) )
else if fvg_minimize_onfill and high > box_bottom
box.set_bottom( array.get(box_array,i), high)
else
box.set_right(array.get(box_array,i),bar_index)
//--FUNCTION TO MANAGE FVGS--//
//-----FUNCTIONS-----//
//-----DEFINE VARIABLES-----//
//--ARRAYS FOR SWING H/L & BN--//
var swing_high_values = array.new_float(5,0.00)
var swing_low_values = array.new_float(5,0.00)
var swing_high_bns = array.new_int(5,0)
var swing_low_bns = array.new_int(5,0)
//--ARRAYS FOR SWING H/L & BN--//
//--ARRAYS FOR SWING H/L & BN--//
var current_supply_box = array.new_box(sd_history, na)
var current_demand_box = array.new_box(sd_history, na)
//--ARRAYS FOR SWING H/L & BN--//
//--ARRAYS FOR BOS--//
var supply_bos = array.new_box(5, na)
var demand_bos = array.new_box(5, na)
//--ARRAYS FOR BOS--//
//-----DEFINE VARIABLES-----//
//-----START CALCULATING-----//
// call functions to calculate swing highs/lows
swing_high = ta.pivothigh(high, sd_length, sd_length)
swing_low = ta.pivotlow(low, sd_length, sd_length)
atr = ta.atr(50)
// if new swing high
if not na(swing_high)
// manage swing high values
f_array_add_pop(swing_high_values, swing_high)
f_array_add_pop(swing_high_bns, bar_index[sd_length])
if show_priceaction
f_sh_sl_labels(swing_high_values, 1)
f_supply_demand(swing_high_values, swing_high_bns, current_supply_box, 1, atr)
// if new swing low
else if not na(swing_low)
// manage swing low values
f_array_add_pop(swing_low_values, swing_low)
f_array_add_pop(swing_low_bns, bar_index[sd_length])
if show_priceaction
f_sh_sl_labels(swing_low_values, -1)
f_supply_demand(swing_low_values, swing_low_bns, current_demand_box, -1, atr)
// move s/d zones to bos
f_sd_to_bos(current_supply_box, supply_bos, 1)
f_sd_to_bos(current_demand_box, demand_bos, -1)
// time changes for mtf
var int day_bn_start = 0
day_bn_start := ta.change(time('D')) ? bar_index : day_bn_start[1]
var int week_bn_start = 0
week_bn_start := ta.change(time('W')) ? bar_index : week_bn_start[1]
var int month_bn_start = 0
month_bn_start := ta.change(time('M')) ? bar_index : month_bn_start[1]
if barstate.islast
//extrend s/d zone boxes
f_extend_box_endpoint(current_supply_box)
f_extend_box_endpoint(current_demand_box)
if barstate.islastconfirmedhistory
if mtf_showday and show_mtfstructure
f_mtf_values('D', day_bn_start, mtf_day_css, mtf_label_css, 'PD', 'Prior Days ')
if mtf_showweek and show_mtfstructure
f_mtf_values('W', week_bn_start, mtf_week_css, mtf_label_css, 'PW', 'Prior Weeks ')
if mtf_showmonth and show_mtfstructure
f_mtf_values('M', month_bn_start, mtf_month_css, mtf_label_css, 'PM', 'Prior Months ')
// fvg logic
abody = math.round_to_mintick(ta.sma(math.abs(close-open), 20))
abody_pct_value = math.round(math.abs(close-open) / abody * 100,0)
abody_bull = abody_pct_value > fvg_sensitivity and close > open ? 1 : 0
abody_bear = abody_pct_value > fvg_sensitivity and close < open ? 1 : 0
var bool fvg_bull = false
var bool fvg_bear = false
fvg_bull := abody_bull[1] and low > (high[1] + low[1]) / 2 and low > high[2]
fvg_bear := abody_bear[1] and high < (high[1] + low[1]) / 2 and high < low[2]
// barcolor(fvg_bull ? color.green : fvg_bear ? color.red : na, offset = -1)
//--ARRAYS FOR FVGS--//
var fvg_bull_box = array.new_box(20, na)
var fvg_bear_box = array.new_box(20, na)
var fvg_finishedbull_box = array.new_box(100, na)
var fvg_finishedbear_box = array.new_box(100, na)
//--ARRAYS FOR FVGS--//
if show_fvg
if fvg_bull
if not fvg_bull[1]
f_new_fvg(fvg_bull_box, 1)
else
f_merge_fvg(fvg_bull_box, 1)
if fvg_bear
if not fvg_bear[1]
f_new_fvg(fvg_bear_box, -1)
else
f_merge_fvg(fvg_bear_box, -1)
f_manage_fvg(fvg_bull_box, fvg_finishedbull_box, 1)
f_manage_fvg(fvg_bear_box, fvg_finishedbear_box, -1)
// fvg logic
Show all 452 lines