Mark FVG
Mark FVG
// Mark FVGs is marking FVG (stands for Fair Value Gap, other name is Imbalance or
IMB) on your chart so that you can instantly detect them
// It supports:
// - marking bullish and bearish partly filled or unfilled FVGs of the current
timeframe
// - marking bullish and bearish already filled FVGs of the current timeframe
// - marking bullish and bearish FVGs of the any 4 timeframes on your current
timeframe
// technically it re-builds them on the last bar or as soon as new realtime bar is
updated. it looks with 1k bars back to find the nearest specific number of FGVs
// Adjustments:
// - changing the maximum number of FVGs to display.
// - changing the color of FVG area
// - displaying already filled FVG of the current time frame
// - changing the mode of displaying area it can either extended or fixed width
// - displaying labels of other time frame FVGs
version = 'v4.5'
int mbb = 1000
indicator("Mark FVGs", overlay = true, max_lines_count = 500, max_bars_back = mbb,
max_labels_count = 500)
max_bars_back(time, mbb)
max_bars_back(low, mbb)
max_bars_back(close, mbb)
max_bars_back(open, mbb)
max_bars_back(high, mbb)
// Settings
//{
FvgCat = 'Release ' + version
beName = 'Be'
buName = 'Bu'
UWName = 'UBars'
ff_FilledFVGsBack = 'Max Fills'
ff_FVGsBack = 'Last Unfilled'
colorTip = ':\n ' + beName + ' - bearish FVG color\n ' + buName + ' - bullish FVG
color'
extendName = 'Extend'
eo_Unextended = 'Unextended'
eo_BySceen = 'By Screen'
eo_ByLastBar = 'By Last Bar'
eo_None = 'None'
eo_ByFilledBar = 'Filling Candle'
custColorName = 'Cust Colors'
onTip = 'Shows/Hides chosen TF'
custColorTip = custColorName + colorTip
extendTip = extendName + ':\n ' + eo_Unextended + ' - shows fixed FVG area\n ' +
eo_BySceen + ' - extends FVG area all the way to the right\n ' + eo_ByLastBar + ' -
extends FVG area to the last bar\n\nEnables/Disables custom colors\n\n' +
custColorTip
customColorName = custColorName + ': ' + beName + '/' + buName
filledName = 'Filled'
fTip = 'From:\n ' + ff_FVGsBack + ' - shows filled FVGs by the first unfilled FVG\n
' + ff_FilledFVGsBack + ' - sets max filled FVGs to show\n\nTo:\n ' +
eo_ByFilledBar + '- filled area is clipped by filling bar\n ' + eo_Unextended + ' -
show fixed FVG area\n\n'
maxImbs = input.int(3, 'Max FVGs', group = FvgCat, minval = 1, maxval = 100, inline
= 'gen')
fvg_fmax = input.int(3, 'Max Fills', minval = 1, maxval = 250, group = FvgCat,
inline = 'gen', tooltip = 'Max - Maximum bearish and bullish FVGs to show\n\nMax
Fills - Sets maximum filled FVGs\n\n')
fvg_uw = input.int(0, UWName, group = FvgCat, minval = -100, maxval = 100, inline =
'2')
fvg_middleBar = input.bool(true, 'Mid Bar Start', group = FvgCat, inline = '2')
fvg_borders = input.bool(false, 'Borders', tooltip = UWName + ' - additonal bars
for the unextended area\n\nMid Bar Start - Starts drawing FVG zone from the middle
candle otherwise it starts drawing it from previous candle\n\nBorders - Displays
FVG area borders', group = FvgCat, inline = '2')
type TFConfig
bool on
string extend
bool nameon = false
string name
color bu
color be
color fbu
color fbe
bool filledon
bool fillToUnfilled
bool extendFilled
matrix<float> data
bool filled = false
int off = -1
if na(tfc)
tfc := TFConfig.new(input.bool(true, 'On', group = CurrentCat, inline =
CurrentCat))
alerts.on := input.bool(false, 'Alert First Test', group = CurrentCat, inline =
CurrentCat)
tfc.extend := chooseExtend(input.string(eo_BySceen, extendName, options =
[eo_Unextended, eo_BySceen, eo_ByLastBar], group = CurrentCat, inline = '1',
tooltip = onTip + '\n\n'))
fvg_custcolor = input.bool(false, customColorName, group = CurrentCat, inline =
'1')
tfc.be := chooseColor2(fvg_custcolor, fvg_be_shared, input.color(defBeColor, '',
group = CurrentCat, inline = '1'))
tfc.bu := chooseColor2(fvg_custcolor, fvg_bu_shared, input.color(defBuColor, '/',
group = CurrentCat, inline = '1', tooltip = extendTip))
labelName = 'Name'
timeframeTip = onTip + '\n\nTimeframe to display'
labelsTip = labelName + ' - displays the time frame name\n\nAdds extra text data to
the label'
if na(tfc2)
tfc2 := TFConfig.new(tf2_on,
chooseExtend(input.string(eo_BySceen, extendName, options = [eo_Unextended,
eo_BySceen, eo_ByLastBar], group = cat2, inline = '1')),
input.bool(true, labelName, group = cat2, inline = cat2),
input.string(' FVG', '', group = cat2, inline = cat2, tooltip = timeframeTip + '\n\
n' + labelsTip)
)
itoid(indata, i) =>
k = i % mbb
if indata.filled
k <= indata.off ? indata.off - k : mbb - 1 - (k - 1 - indata.off)
else
indata.off - k
getlen(indata) =>
indata.filled ? mbb : indata.off + 1
//}
getLow() =>
mn = math.min(open, close, low)
pmx = math.max(open[1], close[1])
mn > pmx ? pmx : low
getHigh() =>
mx = math.max(open, close, high)
pmn = math.min(open[1], close[1])
mx < pmn ? pmn : high
maxFilled = 200
ID_L = 0
ID_RL = 1
ID_H = 2
ID_RH = 3
ID_BI = 4
ID_LI = 5,
ID_FVG = 6
ID_CNT = ID_FVG + 1
createTextLabel(tf) =>
r = tf
if str.contains(tf, 'M') or str.contains(tf, 'D') or str.contains(tf, 'Y') or
str.contains(tf, 'W') or str.contains(tf, 's')
r := tf
else
s = timeframe.in_seconds(tf)
s /= 60
if s / 60 >= 1
r := str.tostring(s / 60) + 'H'
else if fvg_minuteM
r := tf + 'm'
else
r := tf
r
findImb(d, tf, IDL, IDH, sign, col, uw, filled_col, lon = false, string lname = na)
=>
var array<box> imbs = array.new<box>()
var array<box> filledImbs = array.new<box>()
var array<label> names = array.new<label>()
while array.size(imbs) > 0
box.delete(array.pop(imbs))
while array.size(filledImbs) > 0
box.delete(array.pop(filledImbs))
while array.size(names) > 0
label.delete(array.pop(names))
maxBlocks = maxImbs
int len = getlen(d)
if len > 4
ml = getv(d, 0, IDL)
mh = getv(d, 0, IDH)
bi = int(getv(d, 0, ID_LI))
int lastImb = na
for i = 1 to len - 2
l = getv(d, i, IDL)
nl = getv(d, i + 1, IDL)
h = getv(d, i, IDH)
nh = getv(d, i + 1, IDH)
if nh < ml
right = (d.extend == eo_ByLastBar ? bi : int(getv(d, i - 1, ID_LI))) + uw
left = fvg_middleBar ? int(getv(d, i, ID_BI)) : int(getv(d, i + 1, ID_BI))
if bar_index - right > mbb
right := bar_index - mbb
if bar_index - left > mbb
left := bar_index - mbb
if right - left < 1
right := left + 1
imb = box.new(left, sign * ml, right, sign * nh, border_color = fvg_borders ? col :
na, bgcolor = col, extend = d.extend == eo_BySceen ? extend.right : extend.none)
array.push(imbs, imb)
maxBlocks -= 1
lastImb := i
if ml > nh and nh < l//for the gap
ml := nh
if l < ml
ml := l
if maxBlocks <= 0
break
if d.filledon //draw filled imbs
i = 1
fvgs = 0
if na(lastImb) or not d.fillToUnfilled
lastImb := len - 1
while fvgs < fvg_fmax and i <= lastImb
nl = getv(d, i - 1, IDL)//from the right
ph = getv(d, i + 1, IDH)//from the left
if ph < nl and i > 1
ml := nl
//left = bi - i - 1
left = fvg_middleBar ? int(getv(d, i, ID_BI)) : int(getv(d, i + 1, ID_BI))
if bar_index - left > mbb
left := bar_index - mbb
fills = 0
box imb = na
j = i - 2
while j >= 0
if getv(d, j, IDL) < ml
//right = bi - j
right = d.extendFilled ? int(getv(d, j, ID_BI)) : int(getv(d, i - 1, ID_LI)) + uw
if bar_index - right > mbb
right := bar_index - mbb
if right - left < 1
right := left + 1
if d.extendFilled
imb := na
bottom = sign * math.max(getv(d, j, IDL), ph)
if na(imb)
imb := box.new(left, sign * ml, right, bottom, border_color = fvg_borders ?
filled_col : na, bgcolor = filled_col, extend = extend.none)
array.push(filledImbs, imb)
if array.size(filledImbs) + array.size(imbs) > maxFilled
box.delete(array.shift(filledImbs))
box.set_bottom(imb, bottom)
ml := getv(d, j, IDL)
fills += 1
if ml <= ph
break
j -= 1
if fills > 0
fvgs += 1
i += 1
if d.nameon
i = 0
txt = createTextLabel(tf) + lname
while i < array.size(imbs)
box b = array.get(imbs, i)
array.push(names, createLabel(box.get_right(b), (box.get_top(b) +
box.get_bottom(b)) / 2, txt, color.new(col, color.t(col) / 2), d.extend))
i += 1
getAlertText(bull) =>
txt = bull ? 'bull' : 'bear'
txt := txt + ' FVG test'
FindCurTFImb(TFConfig d) =>
l = getLow()
h = getHigh()
if d.on
if na(d.data)
d.data := matrix.new<float>(mbb, ID_CNT)
var lbi = -1
if lbi != bar_index
lbi := bar_index
d.off += 1
if d.off == mbb
d.off := 0
d.filled := true
matrix.set(d.data, d.off, ID_BI, bar_index)
if barstate.islast
findImb(d, timeframe.period, ID_L, ID_H, 1, d.bu, fvg_uw, d.fbu)
findImb(d, timeframe.period, ID_RL, ID_RH, -1, d.be, fvg_uw, d.fbe)
if alerts.on and d.off > 1
donel = low[1] <= low
doneh = high[1] >= high
lastl = low[1]
lasth = high[1]
for i = 2 to d.off - 1
l := getv(d, i, ID_L)
h := getv(d, i, ID_H)
isfvg = getv(d, i, ID_FVG) == 0
if not donel
donel := lastl <= low
if isfvg and l < lastl
//label.new(int(getv(d, i, ID_BI)), lastl, text = str.tostring(getv(d, i, ID_FVG)))
left = getv(d, i + 1, ID_H)
right = math.min(lastl, getv(d, i - 1, ID_L))
if low < right and right - left > 0
donel := true
setv(d, i, ID_FVG, 1)
bi = itoid(d, i)
if alerts.last_low != bi
alerts.last_low := bi
alert(getAlertText(true), alert.freq_once_per_bar)
//alert(getAlertText(true), alert.freq_once_per_bar)
if not doneh
doneh := lasth >= high
if isfvg and h > lasth
left = getv(d, i + 1, ID_L)
right = math.max(lasth, getv(d, i - 1, ID_H))
if high > right and left - right > 0
doneh := true
setv(d, i, ID_FVG, 1)
// var label info = na
// label.delete(info)
// info := label.new(int(getv(d, i, ID_BI)), right, text = 'test high')
bi = itoid(d, i)
if alerts.last_high != bi
alerts.last_high := bi
alert(getAlertText(false), alert.freq_once_per_bar)
if donel and doneh
break
lastl := math.min(lastl, l)
lasth := math.max(lasth, h)
type ltfData
float ltf_low
float ltf_high
if barstate.islast
findImb(d, tf, ID_L, ID_H, 1, d.bu, fvg_uw, d.fbu, d.nameon, d.name)
findImb(d, tf, ID_RL, ID_RH, -1, d.be, fvg_uw, d.fbe, d.nameon, d.name)
if barstate.islast
findImb(d, tf, ID_L, ID_H, 1, d.bu, fvg_uw, d.fbu, d.nameon, d.name)
findImb(d, tf, ID_RL, ID_RH, -1, d.be, fvg_uw, d.fbe, d.nameon, d.name)
FindCurTFImb(tfc)
FindLtfImb(tf0_tf, tf0_on, tfc0)
FindLtfImb(tf1_tf, tf1_on, tfc1)
FindLtfImb(tf2_tf, tf2_on, tfc2)
FindLtfImb(tf3_tf, tf3_on, tfc3)
FindHtfImb(tf0_tf, tf0_on, tfc0)
FindHtfImb(tf1_tf, tf1_on, tfc1)
FindHtfImb(tf2_tf, tf2_on, tfc2)
FindHtfImb(tf3_tf, tf3_on, tfc3)