// © VIKAS KUMAR
//@version=6
indicator('Smart Money Concepts V0.1', 'Smart Money Concepts by Vikas Kumar V.01', overlay = true, max_labels_count = 500, max_lines_count = 500, max_boxes_count = 500)
//---------------------------------------------------------------------------------------------------------------------
// CONSTANTS & STRINGS & INPUTS
//---------------------------------------------------------------------------------------------------------------------
BULLISH_LEG = 1
BEARISH_LEG = 0
BULLISH = +1
BEARISH = -1
GREEN = #089981
RED = #F23645
BLUE = #2157f3
GRAY = #878b94
MONO_BULLISH = #b2b5be
MONO_BEARISH = #5d606b
HISTORICAL = 'Historical'
PRESENT = 'Present'
COLORED = 'Colored'
MONOCHROME = 'Monochrome'
ALL = 'All'
BOS = 'BOS'
CHOCH = 'CHoCH'
TINY = size.tiny
SMALL = size.small
NORMAL = size.normal
ATR = 'Atr'
RANGE = 'Cumulative Mean Range'
CLOSE = 'Close'
HIGHLOW = 'High/Low'
SOLID = '⎯⎯⎯'
DASHED = '----'
DOTTED = '····'
SMART_GROUP = 'Smart Money Concepts'
INTERNAL_GROUP = 'Real Time Internal Structure'
SWING_GROUP = 'Real Time Swing Structure'
BLOCKS_GROUP = 'Order Blocks'
EQUAL_GROUP = 'EQH/EQL'
GAPS_GROUP = 'Fair Value Gaps'
LEVELS_GROUP = 'Highs & Lows MTF'
ZONES_GROUP = 'Premium & Discount Zones'
modeTooltip = 'Allows to display historical Structure or only the recent ones'
styleTooltip = 'Indicator color theme'
showTrendTooltip = 'Display additional candles with a color reflecting the current trend detected by structure'
showInternalsTooltip = 'Display internal market structure'
internalFilterConfluenceTooltip = 'Filter non significant internal structure breakouts'
showStructureTooltip = 'Display swing market Structure'
showSwingsTooltip = 'Display swing point as labels on the chart'
showHighLowSwingsTooltip = 'Highlight most recent strong and weak high/low points on the chart'
showInternalOrderBlocksTooltip = 'Display internal order blocks on the chart\n\nNumber of internal order blocks to display on the chart'
showSwingOrderBlocksTooltip = 'Display swing order blocks on the chart\n\nNumber of internal swing blocks to display on the chart'
orderBlockFilterTooltip = 'Method used to filter out volatile order blocks\n\nIt is recommended to use the cumulative mean range method when a low amount of data is available'
orderBlockMitigationTooltip = 'Select what values to use for order block mitigation'
showEqualHighsLowsTooltip = 'Display equal highs and equal lows on the chart'
equalHighsLowsLengthTooltip = 'Number of bars used to confirm equal highs and equal lows'
equalHighsLowsThresholdTooltip = 'Sensitivity threshold in a range (0, 1) used for the detection of equal highs & lows\n\nLower values will return fewer but more pertinent results'
showFairValueGapsTooltip = 'Display fair values gaps on the chart'
fairValueGapsThresholdTooltip = 'Filter out non significant fair value gaps'
fairValueGapsTimeframeTooltip = 'Fair value gaps timeframe'
fairValueGapsExtendTooltip = 'Determine how many bars to extend the Fair Value Gap boxes on chart'
showPremiumDiscountZonesTooltip = 'Display premium, discount, and equilibrium zones on chart'
modeInput = input.string(HISTORICAL, 'Mode', group = SMART_GROUP, tooltip = modeTooltip, options = [HISTORICAL, PRESENT])
styleInput = input.string(COLORED, 'Style', group = SMART_GROUP, tooltip = styleTooltip, options = [COLORED, MONOCHROME])
showTrendInput = input.bool(false, 'Color Candles', group = SMART_GROUP, tooltip = showTrendTooltip)
showInternalsInput = input.bool(true, 'Show Internal Structure', group = INTERNAL_GROUP, tooltip = showInternalsTooltip)
showInternalBullInput = input.string(ALL, 'Bullish Structure', group = INTERNAL_GROUP, inline = 'ibull', options = [ALL, BOS, CHOCH])
internalBullColorInput = input.color(GREEN, '', group = INTERNAL_GROUP, inline = 'ibull')
showInternalBearInput = input.string(ALL, 'Bearish Structure', group = INTERNAL_GROUP, inline = 'ibear', options = [ALL, BOS, CHOCH])
internalBearColorInput = input.color(RED, '', group = INTERNAL_GROUP, inline = 'ibear')
internalFilterConfluenceInput = input.bool(false, 'Confluence Filter', group = INTERNAL_GROUP, tooltip = internalFilterConfluenceTooltip)
internalStructureSize = input.string(TINY, 'Internal Label Size', group = INTERNAL_GROUP, options = [TINY, SMALL, NORMAL])
showStructureInput = input.bool(true, 'Show Swing Structure', group = SWING_GROUP, tooltip = showStructureTooltip)
showSwingBullInput = input.string(ALL, 'Bullish Structure', group = SWING_GROUP, inline = 'bull', options = [ALL, BOS, CHOCH])
swingBullColorInput = input.color(GREEN, '', group = SWING_GROUP, inline = 'bull')
showSwingBearInput = input.string(ALL, 'Bearish Structure', group = SWING_GROUP, inline = 'bear', options = [ALL, BOS, CHOCH])
swingBearColorInput = input.color(RED, '', group = SWING_GROUP, inline = 'bear')
swingStructureSize = input.string(SMALL, 'Swing Label Size', group = SWING_GROUP, options = [TINY, SMALL, NORMAL])
showSwingsInput = input.bool(false, 'Show Swings Points', group = SWING_GROUP, tooltip = showSwingsTooltip, inline = 'swings')
swingsLengthInput = input.int(50, '', group = SWING_GROUP, minval = 10, inline = 'swings')
showHighLowSwingsInput = input.bool(true, 'Show Strong/Weak High/Low', group = SWING_GROUP, tooltip = showHighLowSwingsTooltip)
showInternalOrderBlocksInput = input.bool(true, 'Internal Order Blocks', group = BLOCKS_GROUP, tooltip = showInternalOrderBlocksTooltip, inline = 'iob')
internalOrderBlocksSizeInput = input.int(5, '', group = BLOCKS_GROUP, minval = 1, maxval = 20, inline = 'iob')
showSwingOrderBlocksInput = input.bool(false, 'Swing Order Blocks', group = BLOCKS_GROUP, tooltip = showSwingOrderBlocksTooltip, inline = 'ob')
swingOrderBlocksSizeInput = input.int(5, '', group = BLOCKS_GROUP, minval = 1, maxval = 20, inline = 'ob')
orderBlockFilterInput = input.string(ATR, 'Order Block Filter', group = BLOCKS_GROUP, tooltip = orderBlockFilterTooltip, options = [ATR, RANGE])
orderBlockMitigationInput = input.string(HIGHLOW, 'Order Block Mitigation', group = BLOCKS_GROUP, tooltip = orderBlockMitigationTooltip, options = [CLOSE, HIGHLOW])
internalBullishOrderBlockColor = input.color(color.new(#3179f5, 80), 'Internal Bullish OB', group = BLOCKS_GROUP)
internalBearishOrderBlockColor = input.color(color.new(#f77c80, 80), 'Internal Bearish OB', group = BLOCKS_GROUP)
swingBullishOrderBlockColor = input.color(color.new(#1848cc, 80), 'Bullish OB', group = BLOCKS_GROUP)
swingBearishOrderBlockColor = input.color(color.new(#b22833, 80), 'Bearish OB', group = BLOCKS_GROUP)
showEqualHighsLowsInput = input.bool(true, 'Equal High/Low', group = EQUAL_GROUP, tooltip = showEqualHighsLowsTooltip)
equalHighsLowsLengthInput = input.int(3, 'Bars Confirmation', group = EQUAL_GROUP, tooltip = equalHighsLowsLengthTooltip, minval = 1)
equalHighsLowsThresholdInput = input.float(0.1, 'Threshold', group = EQUAL_GROUP, tooltip = equalHighsLowsThresholdTooltip, minval = 0, maxval = 0.5, step = 0.1)
equalHighsLowsSizeInput = input.string(TINY, 'Label Size', group = EQUAL_GROUP, options = [TINY, SMALL, NORMAL])
showFairValueGapsInput = input.bool(false, 'Fair Value Gaps', group = GAPS_GROUP, tooltip = showFairValueGapsTooltip)
fairValueGapsThresholdInput = input.bool(true, 'Auto Threshold', group = GAPS_GROUP, tooltip = fairValueGapsThresholdTooltip)
fairValueGapsTimeframeInput = input.timeframe('', 'Timeframe', group = GAPS_GROUP, tooltip = fairValueGapsTimeframeTooltip)
fairValueGapsBullColorInput = input.color(color.new(#00ff68, 70), 'Bullish FVG', group = GAPS_GROUP)
fairValueGapsBearColorInput = input.color(color.new(#ff0008, 70), 'Bearish FVG', group = GAPS_GROUP)
fairValueGapsExtendInput = input.int(1, 'Extend FVG', group = GAPS_GROUP, tooltip = fairValueGapsExtendTooltip, minval = 0)
showDailyLevelsInput = input.bool(false, 'Daily', group = LEVELS_GROUP, inline = 'daily')
dailyLevelsStyleInput = input.string(SOLID, '', group = LEVELS_GROUP, inline = 'daily', options = [SOLID, DASHED, DOTTED])
dailyLevelsColorInput = input.color(BLUE, '', group = LEVELS_GROUP, inline = 'daily')
showWeeklyLevelsInput = input.bool(false, 'Weekly', group = LEVELS_GROUP, inline = 'weekly')
weeklyLevelsStyleInput = input.string(SOLID, '', group = LEVELS_GROUP, inline = 'weekly', options = [SOLID, DASHED, DOTTED])
weeklyLevelsColorInput = input.color(BLUE, '', group = LEVELS_GROUP, inline = 'weekly')
showMonthlyLevelsInput = input.bool(false, 'Monthly', group = LEVELS_GROUP, inline = 'monthly')
monthlyLevelsStyleInput = input.string(SOLID, '', group = LEVELS_GROUP, inline = 'monthly', options = [SOLID, DASHED, DOTTED])
monthlyLevelsColorInput = input.color(BLUE, '', group = LEVELS_GROUP, inline = 'monthly')
showPremiumDiscountZonesInput = input.bool(false, 'Premium/Discount Zones', group = ZONES_GROUP, tooltip = showPremiumDiscountZonesTooltip)
premiumZoneColorInput = input.color(RED, 'Premium Zone', group = ZONES_GROUP)
equilibriumZoneColorInput = input.color(GRAY, 'Equilibrium Zone', group = ZONES_GROUP)
discountZoneColorInput = input.color(GREEN, 'Discount Zone', group = ZONES_GROUP)
//---------------------------------------------------------------------------------------------------------------------
// DATA STRUCTURES & VARIABLES
//---------------------------------------------------------------------------------------------------------------------
type alerts
bool internalBullishBOS = false
bool internalBearishBOS = false
bool internalBullishCHoCH = false
bool internalBearishCHoCH = false
bool swingBullishBOS = false
bool swingBearishBOS = false
bool swingBullishCHoCH = false
bool swingBearishCHoCH = false
bool internalBullishOrderBlock = false
bool internalBearishOrderBlock = false
bool swingBullishOrderBlock = false
bool swingBearishOrderBlock = false
bool equalHighs = false
bool equalLows = false
bool bullishFairValueGap = false
bool bearishFairValueGap = false
type trailingExtremes
float top
float bottom
int barTime
int barIndex
int lastTopTime
int lastBottomTime
type fairValueGap
float top
float bottom
int bias
box topBox
box bottomBox
type trend
int bias
type equalDisplay
line l_ine = na
label l_abel = na
type pivot
float currentLevel
float lastLevel
bool crossed
int barTime = time
int barIndex = bar_index
type orderBlock
float barHigh
float barLow
int barTime
int bias
var pivot swingHigh = pivot.new(na, na, false)
var pivot swingLow = pivot.new(na, na, false)
var pivot internalHigh = pivot.new(na, na, false)
var pivot internalLow = pivot.new(na, na, false)
var pivot equalHigh = pivot.new(na, na, false)
var pivot equalLow = pivot.new(na, na, false)
var trend swingTrend = trend.new(0)
var trend internalTrend = trend.new(0)
var equalDisplay equalHighDisplay = equalDisplay.new()
var equalDisplay equalLowDisplay = equalDisplay.new()
var array<fairValueGap> fairValueGaps = array.new<fairValueGap>()
var array<float> parsedHighs = array.new<float>()
var array<float> parsedLows = array.new<float>()
var array<float> highs = array.new<float>()
var array<float> lows = array.new<float>()
var array<int> times = array.new<int>()
var trailingExtremes trailing = trailingExtremes.new()
var array<orderBlock> swingOrderBlocks = array.new<orderBlock>()
var array<orderBlock> internalOrderBlocks = array.new<orderBlock>()
var array<box> swingOrderBlocksBoxes = array.new<box>()
var array<box> internalOrderBlocksBoxes = array.new<box>()
var swingBullishColor = styleInput == MONOCHROME ? MONO_BULLISH : swingBullColorInput
var swingBearishColor = styleInput == MONOCHROME ? MONO_BEARISH : swingBearColorInput
var fairValueGapBullishColor = styleInput == MONOCHROME ? color.new(MONO_BULLISH, 70) : fairValueGapsBullColorInput
var fairValueGapBearishColor = styleInput == MONOCHROME ? color.new(MONO_BEARISH, 70) : fairValueGapsBearColorInput
var premiumZoneColor = styleInput == MONOCHROME ? MONO_BEARISH : premiumZoneColorInput
var discountZoneColor = styleInput == MONOCHROME ? MONO_BULLISH : discountZoneColorInput
varip int currentBarIndex = bar_index
varip int lastBarIndex = bar_index
alerts currentAlerts = alerts.new()
var initialTime = time
//---------------------------------------------------------------------------------------------------------------------
// INITIALIZE ORDER BLOCK BOXES
//---------------------------------------------------------------------------------------------------------------------
if barstate.isfirst
if showSwingOrderBlocksInput
for index = 1 to swingOrderBlocksSizeInput
swingOrderBlocksBoxes.push(
box.new(na, na, na, na, xloc = xloc.bar_time, extend = extend.right))
if showInternalOrderBlocksInput
for index = 1 to internalOrderBlocksSizeInput
internalOrderBlocksBoxes.push(
box.new(na, na, na, na, xloc = xloc.bar_time, extend = extend.right))
//---------------------------------------------------------------------------------------------------------------------
// VOLATILITY
//---------------------------------------------------------------------------------------------------------------------
bearishOrderBlockMitigationSource = orderBlockMitigationInput == CLOSE ? close : high
bullishOrderBlockMitigationSource = orderBlockMitigationInput == CLOSE ? close : low
atrMeasure = ta.atr(200)
volatilityMeasure = orderBlockFilterInput == ATR ? atrMeasure : ta.cum(ta.tr) / bar_index
highVolatilityBar = (high - low) >= (2 * volatilityMeasure)
parsedHigh = highVolatilityBar ? low : high
parsedLow = highVolatilityBar ? high : low
parsedHighs.push(parsedHigh)
parsedLows.push(parsedLow)
highs.push(high)
lows.push(low)
times.push(time)
//---------------------------------------------------------------------------------------------------------------------
// FUNCTIONS
//---------------------------------------------------------------------------------------------------------------------
leg(int size) =>
var int legValue = 0
newLegHigh = high[size] > ta.highest(size)
newLegLow = low[size] < ta.lowest(size)
if newLegHigh
legValue := BEARISH_LEG
else if newLegLow
legValue := BULLISH_LEG
legValue
startOfNewLeg(int legValue) =>
ta.change(legValue) != 0
startOfBearishLeg(int legValue) =>
ta.change(legValue) == -1
startOfBullishLeg(int legValue) =>
ta.change(legValue) == +1
drawLabel(int labelTime, float labelPrice, string tag, color labelColor, string labelStyle) =>
var label l_abel = na
if modeInput == PRESENT
l_abel.delete()
l_abel := label.new(
chart.point.new(labelTime, na, labelPrice),
tag,
xloc = xloc.bar_time,
color = color(na),
textcolor = labelColor,
style = labelStyle,
size = size.small)
drawEqualHighLow(pivot p_ivot, float level, int size, bool equalHigh) =>
equalDisplay e_qualDisplay = equalHigh ? equalHighDisplay : equalLowDisplay
string tag = 'EQL'
color equalColor = swingBullishColor
string labelStyle = label.style_label_up
if equalHigh
tag := 'EQH'
equalColor := swingBearishColor
labelStyle := label.style_label_down
if modeInput == PRESENT
line.delete(e_qualDisplay.l_ine)
label.delete(e_qualDisplay.l_abel)
e_qualDisplay.l_ine := line.new(
chart.point.new(p_ivot.barTime, na, p_ivot.currentLevel),
chart.point.new(time[size], na, level),
xloc = xloc.bar_time,
color = equalColor,
style = line.style_dotted)
labelPosition = math.round(0.5 * (p_ivot.barIndex + bar_index - size))
e_qualDisplay.l_abel := label.new(
chart.point.new(na, labelPosition, level),
tag,
xloc.bar_index,
color = color(na),
textcolor = equalColor,
style = labelStyle,
size = equalHighsLowsSizeInput)
getCurrentStructure(int size, bool equalHighLow = false, bool internal = false) =>
currentLeg = leg(size)
newPivot = startOfNewLeg(currentLeg)
pivotLow = startOfBullishLeg(currentLeg)
pivotHigh = startOfBearishLeg(currentLeg)
if newPivot
if pivotLow
pivot p_ivot = equalHighLow ? equalLow : internal ? internalLow : swingLow
if equalHighLow and math.abs(p_ivot.currentLevel - low[size]) < equalHighsLowsThresholdInput * atrMeasure
drawEqualHighLow(p_ivot, low[size], size, false)
currentAlerts.equalLows := true
p_ivot.lastLevel := p_ivot.currentLevel
p_ivot.currentLevel := low[size]
p_ivot.crossed := false
p_ivot.barTime := time[size]
p_ivot.barIndex := bar_index[size]
if not equalHighLow and not internal
trailing.bottom := p_ivot.currentLevel
trailing.barTime := p_ivot.barTime
trailing.barIndex := p_ivot.barIndex
trailing.lastBottomTime := p_ivot.barTime
if showSwingsInput and not internal and not equalHighLow
drawLabel(
time[size],
p_ivot.currentLevel,
p_ivot.currentLevel < p_ivot.lastLevel ? 'LL' : 'HL',
swingBullishColor,
label.style_label_up)
else
pivot p_ivot = equalHighLow ? equalHigh : internal ? internalHigh : swingHigh
if equalHighLow and math.abs(p_ivot.currentLevel - high[size]) < equalHighsLowsThresholdInput * atrMeasure
drawEqualHighLow(p_ivot, high[size], size, true)
currentAlerts.equalHighs := true
p_ivot.lastLevel := p_ivot.currentLevel
p_ivot.currentLevel := high[size]
p_ivot.crossed := false
p_ivot.barTime := time[size]
p_ivot.barIndex := bar_index[size]
if not equalHighLow and not internal
trailing.top := p_ivot.currentLevel
trailing.barTime := p_ivot.barTime
trailing.barIndex := p_ivot.barIndex
trailing.lastTopTime := p_ivot.barTime
if showSwingsInput and not internal and not equalHighLow
drawLabel(
time[size],
p_ivot.currentLevel,
p_ivot.currentLevel > p_ivot.lastLevel ? 'HH' : 'LH',
swingBearishColor,
label.style_label_down)
drawStructure(
pivot p_ivot,
string tag,
color structureColor,
string lineStyle,
string labelStyle,
string labelSize) =>
var line l_ine = line.new(na, na, na, na, xloc = xloc.bar_time)
var label l_abel = label.new(na, na)
if modeInput == PRESENT
l_ine.delete()
l_abel.delete()
l_ine := line.new(
chart.point.new(p_ivot.barTime, na, p_ivot.currentLevel),
chart.point.new(time, na, p_ivot.currentLevel),
xloc.bar_time,
color = structureColor,
style = lineStyle)
l_abel := label.new(
chart.point.new(
na,
math.round(0.5 * (p_ivot.barIndex + bar_index)),
p_ivot.currentLevel),
tag,
xloc.bar_index,
color = color(na),
textcolor = structureColor,
style = labelStyle,
size = labelSize)
deleteOrderBlocks(bool internal = false) =>
array<orderBlock> orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks
for [index, eachOrderBlock] in orderBlocks
bool crossedOrderBlock = false
if bearishOrderBlockMitigationSource > eachOrderBlock.barHigh and eachOrderBlock.bias == BEARISH
crossedOrderBlock := true
if internal
currentAlerts.internalBearishOrderBlock := true
else
currentAlerts.swingBearishOrderBlock := true
else if bullishOrderBlockMitigationSource < eachOrderBlock.barLow and eachOrderBlock.bias == BULLISH
crossedOrderBlock := true
if internal
currentAlerts.internalBullishOrderBlock := true
else
currentAlerts.swingBullishOrderBlock := true
if crossedOrderBlock
orderBlocks.remove(index)
storeOrdeBlock(pivot p_ivot, bool internal = false, int bias) =>
if (not internal and showSwingOrderBlocksInput) or
(internal and showInternalOrderBlocksInput)
array<float> a_rray = na
int parsedIndex = na
if bias == BEARISH
a_rray := parsedHighs.slice(p_ivot.barIndex, bar_index)
parsedIndex := p_ivot.barIndex + a_rray.indexof(a_rray.max())
else
a_rray := parsedLows.slice(p_ivot.barIndex, bar_index)
parsedIndex := p_ivot.barIndex + a_rray.indexof(a_rray.min())
orderBlock o_rderBlock = orderBlock.new(
parsedHighs.get(parsedIndex),
parsedLows.get(parsedIndex),
times.get(parsedIndex),
bias)
array<orderBlock> orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks
if orderBlocks.size() >= 100
orderBlocks.pop()
orderBlocks.unshift(o_rderBlock)
drawOrderBlocks(bool internal = false) =>
array<orderBlock> orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks
orderBlocksSize = orderBlocks.size()
if orderBlocksSize > 0
maxOrderBlocks = internal ? internalOrderBlocksSizeInput : swingOrderBlocksSizeInput
array<orderBlock> parsedOrdeBlocks =
orderBlocks.slice(0, math.min(maxOrderBlocks, orderBlocksSize))
array<box> b_oxes =
internal ? internalOrderBlocksBoxes : swingOrderBlocksBoxes
for [index, eachOrderBlock] in parsedOrdeBlocks
orderBlockColor =
styleInput == MONOCHROME ?
(eachOrderBlock.bias == BEARISH ?
color.new(MONO_BEARISH, 80) :
color.new(MONO_BULLISH, 80)) :
internal ?
(eachOrderBlock.bias == BEARISH ?
internalBearishOrderBlockColor :
internalBullishOrderBlockColor) :
(eachOrderBlock.bias == BEARISH ?
swingBearishOrderBlockColor :
swingBullishOrderBlockColor)
box b_ox = b_oxes.get(index)
b_ox.set_top_left_point(
chart.point.new(
eachOrderBlock.barTime,
na,
eachOrderBlock.barHigh))
b_ox.set_bottom_right_point(
chart.point.new(
last_bar_time,
na,
eachOrderBlock.barLow))
b_ox.set_border_color(internal ? na : orderBlockColor)
b_ox.set_bgcolor(orderBlockColor)
displayStructure(bool internal = false) =>
var bool bullishBar = true
var bool bearishBar = true
if internalFilterConfluenceInput
bullishBar := high - math.max(close, open) > math.min(close, open - low)
bearishBar := high - math.max(close, open) < math.min(close, open - low)
pivot p_ivot = internal ? internalHigh : swingHigh
trend t_rend = internal ? internalTrend : swingTrend
lineStyle = internal ? line.style_dashed : line.style_solid
labelSize = internal ? internalStructureSize : swingStructureSize
extraCondition =
internal ?
internalHigh.currentLevel != swingHigh.currentLevel and bullishBar :
true
bullishColor =
styleInput == MONOCHROME ?
MONO_BULLISH :
internal ?
internalBullColorInput :
swingBullColorInput
if ta.crossover(close, p_ivot.currentLevel) and not p_ivot.crossed and extraCondition
string tag = t_rend.bias == BEARISH ? CHOCH : BOS
if internal
currentAlerts.internalBullishCHoCH := tag == CHOCH
currentAlerts.internalBullishBOS := tag == BOS
else
currentAlerts.swingBullishCHoCH := tag == CHOCH
currentAlerts.swingBullishBOS := tag == BOS
p_ivot.crossed := true
t_rend.bias := BULLISH
displayCondition =
internal ?
showInternalsInput and
(showInternalBullInput == ALL or
(showInternalBullInput == BOS and tag != CHOCH) or
(showInternalBullInput == CHOCH and tag == CHOCH)) :
showStructureInput and
(showSwingBullInput == ALL or
(showSwingBullInput == BOS and tag != CHOCH) or
(showSwingBullInput == CHOCH and tag == CHOCH))
if displayCondition
drawStructure(
p_ivot,
tag,
bullishColor,
lineStyle,
label.style_label_down,
labelSize)
if (internal and showInternalOrderBlocksInput) or
(not internal and showSwingOrderBlocksInput)
storeOrdeBlock(p_ivot, internal, BULLISH)
p_ivot := internal ? internalLow : swingLow
extraCondition :=
internal ?
internalLow.currentLevel != swingLow.currentLevel and bearishBar :
true
bearishColor =
styleInput == MONOCHROME ?
MONO_BEARISH :
internal ?
internalBearColorInput :
swingBearColorInput
if ta.crossunder(close, p_ivot.currentLevel) and not p_ivot.crossed and extraCondition
string tag = t_rend.bias == BULLISH ? CHOCH : BOS
if internal
currentAlerts.internalBearishCHoCH := tag == CHOCH
currentAlerts.internalBearishBOS := tag == BOS
else
currentAlerts.swingBearishCHoCH := tag == CHOCH
currentAlerts.swingBearishBOS := tag == BOS
p_ivot.crossed := true
t_rend.bias := BEARISH
displayCondition =
internal ?
showInternalsInput and
(showInternalBearInput == ALL or
(showInternalBearInput == BOS and tag != CHOCH) or
(showInternalBearInput == CHOCH and tag == CHOCH)) :
showStructureInput and
(showSwingBearInput == ALL or
(showSwingBearInput == BOS and tag != CHOCH) or
(showSwingBearInput == CHOCH and tag == CHOCH))
if displayCondition
drawStructure(
p_ivot,
tag,
bearishColor,
lineStyle,
label.style_label_up,
labelSize)
if (internal and showInternalOrderBlocksInput) or
(not internal and showSwingOrderBlocksInput)
storeOrdeBlock(p_ivot, internal, BEARISH)
fairValueGapBox(
int leftTime,
int rightTime,
float topPrice,
float bottomPrice,
color boxColor) =>
box.new(
chart.point.new(leftTime, na, topPrice),
chart.point.new(
rightTime + fairValueGapsExtendInput * (time - time[1]),
na,
bottomPrice),
xloc = xloc.bar_time,
border_color = boxColor,
bgcolor = boxColor)
deleteFairValueGaps() =>
for [index, eachFairValueGap] in fairValueGaps
if (low < eachFairValueGap.bottom and eachFairValueGap.bias == BULLISH) or
(high > eachFairValueGap.top and eachFairValueGap.bias == BEARISH)
eachFairValueGap.topBox.delete()
eachFairValueGap.bottomBox.delete()
fairValueGaps.remove(index)
drawFairValueGaps() =>
[lastClose, lastOpen, lastTime, currentHigh, currentLow, currentTime, last2High, last2Low] =
request.security(
syminfo.tickerid,
fairValueGapsTimeframeInput,
[close[1], open[1], time[1], high[0], low[0], time[0], high[2], low[2]],
lookahead = barmerge.lookahead_on)
barDeltaPercent = (lastClose - lastOpen) / (lastOpen * 100)
newTimeframe = timeframe.change(fairValueGapsTimeframeInput)
threshold =
fairValueGapsThresholdInput ?
ta.cum(math.abs(newTimeframe ? barDeltaPercent : 0)) / bar_index * 2 :
0
bullishFairValueGap =
currentLow > last2High and
lastClose > last2High and
barDeltaPercent > threshold and
newTimeframe
bearishFairValueGap =
currentHigh < last2Low and
lastClose < last2Low and
-barDeltaPercent > threshold and
newTimeframe
if bullishFairValueGap
currentAlerts.bullishFairValueGap := true
fairValueGaps.unshift(
fairValueGap.new(
currentLow,
last2High,
BULLISH,
fairValueGapBox(
lastTime,
currentTime,
currentLow,
math.avg(currentLow, last2High),
fairValueGapBullishColor),
fairValueGapBox(
lastTime,
currentTime,
math.avg(currentLow, last2High),
last2High,
fairValueGapBullishColor)))
if bearishFairValueGap
currentAlerts.bearishFairValueGap := true
fairValueGaps.unshift(
fairValueGap.new(
currentHigh,
last2Low,
BEARISH,
fairValueGapBox(
lastTime,
currentTime,
currentHigh,
math.avg(currentHigh, last2Low),
fairValueGapBearishColor),
fairValueGapBox(
lastTime,
currentTime,
math.avg(currentHigh, last2Low),
last2Low,
fairValueGapBearishColor)))
getStyle(string style) =>
switch style
SOLID => line.style_solid
DASHED => line.style_dashed
DOTTED => line.style_dotted
drawLevels(
string timeframeValue,
bool sameTimeframe,
string style,
color levelColor) =>
[topLevel, bottomLevel, leftTime, rightTime] =
request.security(
syminfo.tickerid,
timeframeValue,
[high[1], low[1], time[1], time],
lookahead = barmerge.lookahead_on)
float parsedTop = sameTimeframe ? high : topLevel
float parsedBottom = sameTimeframe ? low : bottomLevel
int parsedLeftTime = sameTimeframe ? time : leftTime
int parsedRightTime = sameTimeframe ? time : rightTime
int parsedTopTime = time
int parsedBottomTime = time
if not sameTimeframe
int leftIndex = times.binary_search_rightmost(parsedLeftTime)
int rightIndex = times.binary_search_rightmost(parsedRightTime)
array<int> timeArray = times.slice(leftIndex, rightIndex)
array<float> topArray = highs.slice(leftIndex, rightIndex)
array<float> bottomArray = lows.slice(leftIndex, rightIndex)
parsedTopTime :=
timeArray.size() > 0 ?
timeArray.get(topArray.indexof(topArray.max())) :
initialTime
parsedBottomTime :=
timeArray.size() > 0 ?
timeArray.get(bottomArray.indexof(bottomArray.min())) :
initialTime
var line topLine =
line.new(
na,
na,
na,
na,
xloc = xloc.bar_time,
color = levelColor,
style = getStyle(style))
var line bottomLine =
line.new(
na,
na,
na,
na,
xloc = xloc.bar_time,
color = levelColor,
style = getStyle(style))
var label topLabel =
label.new(
na,
na,
xloc = xloc.bar_time,
text = str.format('P{0}H', timeframeValue),
color = color(na),
textcolor = levelColor,
size = size.small,
style = label.style_label_left)
var label bottomLabel =
label.new(
na,
na,
xloc = xloc.bar_time,
text = str.format('P{0}L', timeframeValue),
color = color(na),
textcolor = levelColor,
size = size.small,
style = label.style_label_left)
topLine.set_first_point(
chart.point.new(parsedTopTime, na, parsedTop))
topLine.set_second_point(
chart.point.new(
last_bar_time + 20 * (time - time[1]),
na,
parsedTop))
topLabel.set_point(
chart.point.new(
last_bar_time + 20 * (time - time[1]),
na,
parsedTop))
bottomLine.set_first_point(
chart.point.new(parsedBottomTime, na, parsedBottom))
bottomLine.set_second_point(
chart.point.new(
last_bar_time + 20 * (time - time[1]),
na,
parsedBottom))
bottomLabel.set_point(
chart.point.new(
last_bar_time + 20 * (time - time[1]),
na,
parsedBottom))
higherTimeframe(string timeframeValue) =>
timeframe.in_seconds() > timeframe.in_seconds(timeframeValue)
updateTrailingExtremes() =>
trailing.top := math.max(high, trailing.top)
trailing.lastTopTime := trailing.top == high ? time : trailing.lastTopTime
trailing.bottom := math.min(low, trailing.bottom)
trailing.lastBottomTime := trailing.bottom == low ? time : trailing.lastBottomTime
drawHighLowSwings() =>
var line topLine =
line.new(
na,
na,
na,
na,
color = swingBearishColor,
xloc = xloc.bar_time)
var line bottomLine =
line.new(
na,
na,
na,
na,
color = swingBullishColor,
xloc = xloc.bar_time)
var label topLabel =
label.new(
na,
na,
color = color(na),
textcolor = swingBearishColor,
xloc = xloc.bar_time,
style = label.style_label_down,
size = size.tiny)
var label bottomLabel =
label.new(
na,
na,
color = color(na),
textcolor = swingBullishColor,
xloc = xloc.bar_time,
style = label.style_label_up,
size = size.tiny)
rightTimeBar = last_bar_time + 20 * (time - time[1])
topLine.set_first_point(
chart.point.new(
trailing.lastTopTime,
na,
trailing.top))
topLine.set_second_point(
chart.point.new(
rightTimeBar,
na,
trailing.top))
topLabel.set_point(
chart.point.new(
rightTimeBar,
na,
trailing.top))
topLabel.set_text(
swingTrend.bias == BEARISH ? 'Strong High' : 'Weak High')
bottomLine.set_first_point(
chart.point.new(
trailing.lastBottomTime,
na,
trailing.bottom))
bottomLine.set_second_point(
chart.point.new(
rightTimeBar,
na,
trailing.bottom))
bottomLabel.set_point(
chart.point.new(
rightTimeBar,
na,
trailing.bottom))
bottomLabel.set_text(
swingTrend.bias == BULLISH ? 'Strong Low' : 'Weak Low')
drawZone(
float labelLevel,
int labelIndex,
float top,
float bottom,
string tag,
color zoneColor,
string style) =>
var label l_abel =
label.new(
na,
na,
text = tag,
color = color(na),
textcolor = zoneColor,
style = style,
size = size.small)
var box b_ox =
box.new(
na,
na,
na,
na,
bgcolor = color.new(zoneColor, 80),
border_color = color(na),
xloc = xloc.bar_time)
b_ox.set_top_left_point(
chart.point.new(
trailing.barTime,
na,
top))
b_ox.set_bottom_right_point(
chart.point.new(
last_bar_time,
na,
bottom))
l_abel.set_point(
chart.point.new(
na,
labelIndex,
labelLevel))
drawPremiumDiscountZones() =>
drawZone(
trailing.top,
math.round(0.5 * (trailing.barIndex + last_bar_index)),
trailing.top,
0.95 * trailing.top + 0.05 * trailing.bottom,
'Premium',
premiumZoneColor,
label.style_label_down)
equilibriumLevel = math.avg(trailing.top, trailing.bottom)
drawZone(
equilibriumLevel,
last_bar_index,
0.525 * trailing.top + 0.475 * trailing.bottom,
0.525 * trailing.bottom + 0.475 * trailing.top,
'Equilibrium',
equilibriumZoneColorInput,
label.style_label_left)
drawZone(
trailing.bottom,
math.round(0.5 * (trailing.barIndex + last_bar_index)),
0.95 * trailing.bottom + 0.05 * trailing.top,
trailing.bottom,
'Discount',
discountZoneColor,
label.style_label_up)
//---------------------------------------------------------------------------------------------------------------------
// EXECUTION
//---------------------------------------------------------------------------------------------------------------------
parsedOpen = showTrendInput ? open : na
candleColor =
internalTrend.bias == BULLISH ?
swingBullishColor :
swingBearishColor
plotcandle(
parsedOpen,
high,
low,
close,
color = candleColor,
wickcolor = candleColor,
bordercolor = candleColor)
if showHighLowSwingsInput or showPremiumDiscountZonesInput
updateTrailingExtremes()
if showHighLowSwingsInput
drawHighLowSwings()
if showPremiumDiscountZonesInput
drawPremiumDiscountZones()
if showFairValueGapsInput
deleteFairValueGaps()
getCurrentStructure(swingsLengthInput, false)
getCurrentStructure(5, false, true)
if showEqualHighsLowsInput
getCurrentStructure(equalHighsLowsLengthInput, true)
if showInternalsInput or showInternalOrderBlocksInput or showTrendInput
displayStructure(true)
if showStructureInput or showSwingOrderBlocksInput or showHighLowSwingsInput
displayStructure()
if showInternalOrderBlocksInput
deleteOrderBlocks(true)
if showSwingOrderBlocksInput
deleteOrderBlocks()
if showFairValueGapsInput
drawFairValueGaps()
if barstate.islastconfirmedhistory or barstate.islast
if showInternalOrderBlocksInput
drawOrderBlocks(true)
if showSwingOrderBlocksInput
drawOrderBlocks()
lastBarIndex := currentBarIndex
currentBarIndex := bar_index
newBar = currentBarIndex != lastBarIndex
if barstate.islastconfirmedhistory or (barstate.isrealtime and newBar)
if showDailyLevelsInput and not higherTimeframe('D')
drawLevels('D', timeframe.isdaily, dailyLevelsStyleInput, dailyLevelsColorInput)
if showWeeklyLevelsInput and not higherTimeframe('W')
drawLevels('W', timeframe.isweekly, weeklyLevelsStyleInput, weeklyLevelsColorInput)
if showMonthlyLevelsInput and not higherTimeframe('M')
drawLevels('M', timeframe.ismonthly, monthlyLevelsStyleInput, monthlyLevelsColorInput)
//---------------------------------------------------------------------------------------------------------------------
// ALERTS
//---------------------------------------------------------------------------------------------------------------------
alertcondition(
currentAlerts.internalBullishBOS,
'Internal Bullish BOS',
'Internal Bullish BOS formed')
alertcondition(
currentAlerts.internalBullishCHoCH,
'Internal Bullish CHoCH',
'Internal Bullish CHoCH formed')
alertcondition(
currentAlerts.internalBearishBOS,
'Internal Bearish BOS',
'Internal Bearish BOS formed')
alertcondition(
currentAlerts.internalBearishCHoCH,
'Internal Bearish CHoCH',
'Internal Bearish CHoCH formed')
alertcondition(
currentAlerts.swingBullishBOS,
'Bullish BOS',
'Internal Bullish BOS formed')
alertcondition(
currentAlerts.swingBullishCHoCH,
'Bullish CHoCH',
'Internal Bullish CHoCH formed')
alertcondition(
currentAlerts.swingBearishBOS,
'Bearish BOS',
'Bearish BOS formed')
alertcondition(
currentAlerts.swingBearishCHoCH,
'Bearish CHoCH',
'Bearish CHoCH formed')
alertcondition(
currentAlerts.internalBullishOrderBlock,
'Bullish Internal OB Breakout',
'Price broke bullish internal OB')
alertcondition(
currentAlerts.internalBearishOrderBlock,
'Bearish Internal OB Breakout',
'Price broke bearish internal OB')
alertcondition(
currentAlerts.swingBullishOrderBlock,
'Bullish Swing OB Breakout',
'Price broke bullish swing OB')
alertcondition(
currentAlerts.swingBearishOrderBlock,
'Bearish Swing OB Breakout',
'Price broke bearish swing OB')
alertcondition(
currentAlerts.equalHighs,
'Equal Highs',
'Equal highs detected')
alertcondition(
currentAlerts.equalLows,
'Equal Lows',
'Equal lows detected')
alertcondition(
currentAlerts.bullishFairValueGap,
'Bullish FVG',
'Bullish FVG formed')
alertcondition(
currentAlerts.bearishFairValueGap,
'Bearish FVG',
'Bearish FVG formed')