本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=5
indicator("Swing Volume Profiles [LuxAlgo]", "LuxAlgo - Swing Volume Profiles", true, max_bars_back = 5000, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 500)
//------------------------------------------------------------------------------
//Settings
//-----------------------------------------------------------------------------{
mode = input.string('Present', title = 'Mode', options =['Present', 'Historical'], inline = 'MOD')
back = input.int (300, ' # Bars', minval = 100, maxval = 5000, step = 10, inline = 'MOD')
grpVP = 'Swing Volume Profiles'
ppTT = 'The Swing High Low indicator is used to determine and anticipate potential changes in market price and reversals\n' +
'\'Swing Volume Profiles [LuxAlgo]\' aims at highliting the trading activity at specified price levels between two Swing Levels'
ppLen = input.int(47, "Swing Detection Length", minval = 1, group = grpVP, tooltip = ppTT)
vpTT = 'Common Interest Profile (Total Volume) - displays total trading activity over a specified time period at specific price levels'
vpShw = input.bool(true, 'Swing Volume Profiles', inline = 'BB3', group = grpVP, tooltip = vpTT)
vpTVC = input.color(color.new(#fbc02d, 65), '', inline = 'BB3', group = grpVP)
vpVVC = input.color(color.new(#434651, 65), '', inline = 'BB3', group = grpVP)
vpB = input.bool(false, 'Profile Range Background Fill', inline ='BG', group = grpVP)
vpBC = input.color(color.new(#2962ff, 95), '', inline ='BG', group = grpVP)
grpPC = 'Point of Control (POC)'
pcTT = 'Point of Control (POC) - The price level for the time period with the highest traded volume'
pcShw = input.bool(true, 'Point of Control (PoC)', inline = 'PoC', group = grpPC, tooltip = pcTT)
pcC = input.color(color.new(#ff0000, 0), '', inline = 'PoC', group = grpPC)
dpTT = 'Developing Point of Control, displays how POC is changing during the active market session'
dpcS = input.bool(true, 'Developing PoC ', inline = 'dPoC', group = grpPC, tooltip = dpTT)
dpcC = input.color(color.new(#ff0000, 0), '', inline = 'dPoC', group = grpPC)
pcE = input.string('None', 'Extend PoC', options=['Until Last Bar', 'Until Bar Cross', 'Until Bar Touch', 'None'], group = grpPC)
grpVA = 'Value Area (VA)'
vaTT = 'Value Area (VA) – The range of price levels in which a specified percentage of all volume was traded during the time period'
isVA = input.float(68, "Value Area Volume %", minval = 0, maxval = 100, group = grpVA, tooltip = vaTT) / 100
vhTT = 'Value Area High (VAH) - The highest price level within the value area'
vhShw = input.bool(true, 'Value Area High (VAH)', inline = 'VAH', group = grpVA, tooltip = vhTT)
vaHC = input.color(color.new(#2962ff, 0), '', inline = 'VAH', group = grpVA)
vlTT = 'Value Area Low (VAL) - The lowest price level within the value area'
vlShw = input.bool(true, 'Value Area Low (VAL) ', inline = 'VAL', group = grpVA, tooltip = vlTT)
vaLC = input.color(color.new(#2962ff, 0), '', inline = 'VAL', group = grpVA)
vaB = input.bool(false, 'Value Area (VA) Background Fill', inline = 'vBG', group = grpVA)
vaBC = input.color(color.new(#2962ff, 89), '', inline = 'vBG', group = grpVA)
grpLQ = 'Liquidity Levels / Voids'
liqUF = input(true, 'Unfilled Liquidity, Thresh', inline = 'UFL', group = grpLQ)
liqT = input(21, '', inline = 'UFL', group = grpLQ) / 100
liqC = input.color(color.new(#00bcd4, 90), '', inline = 'UFL', group = grpLQ)
grpLB = 'Profile Stats'
ppLev = input.string('Swing High/Low', 'Position', options = ['Swing High/Low', 'Profile High/Low', 'Value Area High/Low'], inline='ppLS' , group = grpLB)
ppLS = input.string('Small', "Size", options=['Tiny', 'Small', 'Normal'], inline='ppLS', group = grpLB)
ppS = switch ppLS
'Tiny' => size.tiny
'Small' => size.small
'Normal' => size.normal
ppP = input(false, "Price", inline = 'Levels', group = grpLB)
ppC = input(false, "Price Change", inline = 'Levels', group = grpLB)
ppV = input(false, "Cumulative Volume", inline = 'Levels', group = grpLB)
grpOT = 'Volume Profile Others'
vpLev = input.int(27, 'Number of Rows' , minval = 10, maxval = 100 , step = 1, group = grpOT)
vpPlc = input.string('Left', 'Placment', options = ['Right', 'Left'], group = grpOT)
vpWth = input.int(50, 'Profile Width %', minval = 0, maxval = 100, group = grpOT) / 100
//-----------------------------------------------------------------------------}
//User Defined Types
//-----------------------------------------------------------------------------{
// @type bar properties with their values
//
// @field h (float) high price of the bar
// @field l (float) low price of the bar
// @field v (float) volume of the bar
// @field i (int) index of the bar
type bar
float h = high
float l = low
float v = volume
int i = bar_index
// @type store pivot high/low and index data
//
// @field x (int) last pivot bar index
// @field x1 (int) previous pivot bar index
// @field h (float) last pivot high
// @field l (float) last pivot low
// @field s (string) last pivot as 'L' or 'H'
type pivotPoint
int x
int x1
float h
float l
string s
// @type maintain liquidity data
//
// @field b (array<bool>) array maintains price levels where liquidity exists
// @field bx (array<box>) array maintains visual object of price levels where liquidity exists
type liquidity
bool [] b
box [] bx
// @type maintain volume profile data
//
// @field vs (array<float>) array maintains tolal traded volume
// @field vp (array<box>) array maintains visual object of each price level
type volumeProfile
float [] vs
box [] vp
//-----------------------------------------------------------------------------}
//Variables
//-----------------------------------------------------------------------------{
var aPOC = array.new_box()
var dPOC = array.new_line()
var dPCa = array.new_line()
var laP = 0, var lbP = 0, var dpcL = 0, var float ersten = na
bar b = bar.new()
var pivotPoint pp = pivotPoint.new()
var liquidity[] aLIQ = array.new<liquidity> (1, liquidity.new(array.new <bool> (vpLev, false), array.new <box> (na)))
var liquidity[] dLIQ = array.new<liquidity> (1, liquidity.new(array.new <bool> (na) , array.new <box> (na)))
volumeProfile aVP = volumeProfile.new(array.new <float> (vpLev + 1, 0.), array.new <box> (na))
volumeProfile aVPa = volumeProfile.new(array.new <float> (vpLev + 1, 0.), array.new <box> (na))
var volumeProfile dVP = volumeProfile.new(array.new <float> (na) , array.new <box> (na))
//-----------------------------------------------------------------------------}
//Functions/methods
//-----------------------------------------------------------------------------{
// @function calcuates highest, lowest price value and cumulative volume of the given range
//
// @param _l (int) length of the range
// @param _c (bool) check
// @param _o (int) offset
//
// @returns (float, float, float) highest, lowest and cumulative volume
f_calcHL(_l, _c, _o) =>
if _c
l = low [_o]
h = high[_o]
v = 0.
for x = 0 to _l - 1
l := math.min(low [_o + x], l)
h := math.max(high[_o + x], h)
v += volume[_o + x]
l := math.min(low [_o + _l], l)
h := math.max(high[_o + _l], h)
[h, l, v]
// @function check bar breaches
//
// @param _a (array<box>) array containg the boxes to be checked
// @param _e (strings) extend statment : 'Until Last Bar', 'Until Bar Cross', 'Until Bar Touch' and 'None'
//
// @returns none, updated visual objects (boxes)
f_checkBreaches(_a, _e) =>
int qBX = array.size(_a)
for no = 0 to (qBX > 0 ? qBX - 1 : na)
if no < array.size(_a)
cBX = array.get(_a, no)
mBX = math.avg(box.get_bottom(cBX), box.get_top(cBX))
ced = math.sign(close[1] - mBX) != math.sign(close - mBX)
ted = math.sign(close[1] - mBX) != math.sign(low - mBX) or math.sign(close[1] - mBX) != math.sign(high - mBX)
if ced and _e == 'Until Bar Cross'
array.remove(_a, no)
int(na)
else if ted and _e == 'Until Bar Touch'
array.remove(_a, no)
int(na)
else
box.set_right(cBX, bar_index)
int(na)
// @function creates new line object, updates existing line objects
//
// @param details in Pine Script™ language reference manual
//
// @returns id of the line
f_drawLineX(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width) =>
var id = line.new(_x1, _y1, _x2, _y2, _xloc, _extend, _color, _style, _width)
line.set_xy1(id, _x1, _y1)
line.set_xy2(id, _x2, _y2)
line.set_color(id, _color)
id
// @function creates new label object, updates existing label objects
//
// @param details in Pine Script™ language reference manual
//
// @returns none
f_drawLabelX(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip) =>
var id = label.new(_x, _y, _text, _xloc, _yloc, _color, _style, _textcolor, _size, _textalign, _tooltip)
label.set_xy(id, _x, _y)
label.set_text(id, _text)
label.set_tooltip(id, _tooltip)
//-----------------------------------------------------------------------------}
//Calculations
//-----------------------------------------------------------------------------{
per = mode == 'Present' ? last_bar_index - b.i <= back : true
nzV = nz(b.v)
pp_h = ta.pivothigh(ppLen, ppLen)
pp_l = ta.pivotlow (ppLen, ppLen)
if not na(pp_h)
pp.h := pp_h
pp.s := 'H'
if not na(pp_l)
pp.l := pp_l
pp.s := 'L'
go = not na(pp_h) or not na(pp_l)
if go
pp.x1 := pp.x
pp.x := b.i
vpLen = pp.x - pp.x1
[pHst, pLst, tV] = f_calcHL(vpLen, go, ppLen)
pStp = (pHst - pLst) / vpLev
[pHta, pLta, _] = f_calcHL(ppLen, go, 0)
pSpa = (pHta - pLta) / vpLev
if go and nzV and pStp > 0 and b.i > vpLen and vpLen > 0 and per
if dPCa.size() > 0
for i = 0 to dPCa.size() - 1
dPCa.shift().delete()
for bIt = 1 to vpLen
l = 0
bI = bIt + ppLen
for pLev = pLst to pHst by pStp
if b.h[bI] >= pLev and b.l[bI] < pLev + pStp
aVP.vs.set(l, aVP.vs.get(l) + nzV[bI] * ((b.h[bI] - b.l[bI]) == 0 ? 1 : pStp / (b.h[bI] - b.l[bI])))
l += 1
pcL = aVP.vs.indexof(aVP.vs.max())
ttV = aVP.vs.sum() * isVA
va = aVP.vs.get(pcL)
laP := pcL
lbP := pcL
while va < ttV
if lbP == 0 and laP == vpLev - 1
break
vaP = 0.
if laP < vpLev - 1
vaP := aVP.vs.get(laP + 1)
vbP = 0.
if lbP > 0
vbP := aVP.vs.get(lbP - 1)
if vbP == 0 and vaP == 0
break
if vaP >= vbP
va += vaP
laP += 1
else
va += vbP
lbP -= 1
aLIQ.unshift(liquidity.new(array.new <bool> (vpLev, false), array.new <box> (na)))
cLIQ = aLIQ.get(0)
for l = vpLev - 1 to 0
if vpShw
sbI = vpPlc == 'Right' ? b.i - int(aVP.vs.get(l) / aVP.vs.max() * vpLen * vpWth) : b.i - vpLen
ebI = vpPlc == 'Right' ? b.i : sbI + int( aVP.vs.get(l) / aVP.vs.max() * vpLen * vpWth)
aVP.vp.push(box.new(sbI - ppLen, pLst + (l + 0.1) * pStp, ebI - ppLen, pLst + (l + 0.9) * pStp, l >= lbP and l <= laP ? vpTVC : vpVVC, bgcolor = l >= lbP and l <= laP ? vpTVC : vpVVC))
if liqUF
if aVP.vs.get(l) / aVP.vs.max() < liqT
cLIQ.b.set(l, true)
cLIQ.bx.unshift(box.new(b.i[ppLen], pLst + (l + 0.00) * pStp, b.i[ppLen], pLst + (l + 1.00) * pStp, border_color = color(na), bgcolor = liqC ))
else
cLIQ.bx.unshift(box.new(na, na, na, na))
cLIQ.b.set(l, false)
for bIt = 0 to vpLen
bI = bIt + ppLen
int qBX = cLIQ.bx.size()
for no = 0 to (qBX > 0 ? qBX - 1 : na)
if no < cLIQ.bx.size()
if cLIQ.b.get(no)
cBX = cLIQ.bx.get(no)
mBX = math.avg(cBX.get_bottom(), cBX.get_top())
if math.sign(close[bI + 1] - mBX) != math.sign(low[bI] - mBX) or math.sign(close[bI + 1] - mBX) != math.sign(high[bI] - mBX) or math.sign(close[bI + 1] - mBX) != math.sign(close[bI] - mBX)
cBX.set_left(b.i[bI])
cLIQ.b.set(no, false)
for bI = ppLen to 0
int qBX = cLIQ.bx.size()
for no = (qBX > 0 ? qBX - 1 : na) to 0
if no < cLIQ.bx.size()
cBX = cLIQ.bx.get(no)
mBX = math.avg(box.get_bottom(cBX), box.get_top(cBX))
if math.sign(close[bI + 1] - mBX) != math.sign(low[bI] - mBX) or math.sign(close[bI + 1] - mBX) != math.sign(high[bI] - mBX)
cBX.delete()
cLIQ.bx.remove(no)
else
cBX.set_right(b.i[bI])
if dpcS
l = 0
for pLev = pLta to pHta by pSpa
if b.h[bI] >= pLev and b.l[bI] < pLev + pSpa
aVPa.vs.set(l, aVPa.vs.get(l) + nzV[bI] * ((b.h[bI] - b.l[bI]) == 0 ? 1 : pSpa / (b.h[bI] - b.l[bI])))
l += 1
if bI == ppLen
ersten := math.avg(b.h[ppLen], b.l[ppLen])//pLta + (aVPa.vs.indexof(aVPa.vs.max()) + .50) * pSpa
else
dPCa.push(line.new(b.i[bI] - 1, ersten, b.i[bI], pLta + (aVPa.vs.indexof(aVPa.vs.max()) + .50) * pSpa, color = dpcC, width = 2))
ersten := pLta + (aVPa.vs.indexof(aVPa.vs.max()) + .50) * pSpa
if vpB
aVP.vp.push(box.new(b.i[ppLen] - vpLen, pHst, b.i[ppLen], pLst, vpBC, border_style = line.style_dotted, bgcolor = vpBC))
if pcShw
aPOC.push(box.new(b.i[ppLen] - vpLen, pLst + (pcL + .40) * pStp, b.i[ppLen], pLst + (pcL + .60) * pStp, pcC, bgcolor = pcC ))
vah = line.new(b.i[ppLen] - vpLen, pLst + (laP + 1.00) * pStp, b.i[ppLen], pLst + (laP + 1.00) * pStp, xloc.bar_index, extend.none, vhShw ? vaHC : #00000000, line.style_solid, 2)
val = line.new(b.i[ppLen] - vpLen, pLst + (lbP + 0.00) * pStp, b.i[ppLen], pLst + (lbP + 0.00) * pStp, xloc.bar_index, extend.none, vlShw ? vaLC : #00000000, line.style_solid, 2)
if vaB
linefill.new(vah, val, vaBC)
statTip = '\n -Traded Volume : ' + str.tostring(tV, format.volume) + ' (' + str.tostring(vpLen - 1) + ' bars)' +
'\n *Average Volume/Bar : ' + str.tostring(tV / (vpLen - 1), format.volume) +
'\n\nProfile High : ' + str.tostring(pHst, format.mintick) + ' ↑ %' + str.tostring((pHst - pLst) / pLst * 100, '#.##') +
'\nProfile Low : ' + str.tostring(pLst, format.mintick) + ' ↓ %' + str.tostring((pHst - pLst) / pHst * 100, '#.##') +
'\n -Point Of Control : ' + str.tostring(pLst + (pcL + .50) * pStp, format.mintick) +
'\n\nValue Area High : ' + str.tostring(pLst + (laP + 1.00) * pStp, format.mintick) +
'\nValue Area Low : ' + str.tostring(pLst + (lbP + 0.00) * pStp, format.mintick) +
'\n -Value Area Width : %' + str.tostring(((pLst + (laP + 1.00) * pStp) - (pLst + (lbP + 0.00) * pStp)) / (pHst - pLst) * 100, '#.##') +
'\n\nNumber of Bars (Profile) : ' + str.tostring(vpLen)
if ppLev != 'Swing High/Low'
uPl = ppLev == 'Value Area High/Low' ? pLst + (laP + 1.00) * pStp : pHst
lPl = ppLev == 'Value Area High/Low' ? pLst + (lbP + 0.00) * pStp : pLst
uTx = (ppP ? str.tostring(uPl, format.mintick) : '') + (not na(pp_h) ? (ppC ? (ppP ? ' ↑ %' : '↑ %') + str.tostring((pp.h - pp.l) * 100 / pp.l, '#.##') : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tV, format.volume) : '') : '')
lTx = (ppP ? str.tostring(lPl, format.mintick) : '') + (not na(pp_l) ? (ppC ? (ppP ? ' ↓ %' : '↓ %') + str.tostring((pp.h - pp.l) * 100 / pp.h, '#.##') : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tV, format.volume) : '') : '')
label.new(b.i[ppLen] - vpLen / 2, uPl, uTx, xloc.bar_index, yloc.price, #00000000, label.style_label_down, chart.fg_color, ppS, text.align_center, ' Profile High : ' + str.tostring(pHst, format.mintick) + '\n %' + str.tostring((pHst - pLst) / pLst * 100, '#.##') + ' higher than the Profile Low' + statTip)
label.new(b.i[ppLen] - vpLen / 2, lPl, lTx, xloc.bar_index, yloc.price, #00000000, label.style_label_up , chart.fg_color, ppS, text.align_center, ' Profile Low : ' + str.tostring(pLst, format.mintick) + '\n %' + str.tostring((pHst - pLst) / pHst * 100, '#.##') + ' lower than the Profile High' + statTip)
else
if not na(pp_h)
label.new(b.i[ppLen], pp.h, (ppP ? str.tostring(pp.h, format.mintick) : '') + (ppC ? (ppP ? ' ↑ %' : '↑ %') + str.tostring((pp.h - pp.l) * 100 / pp.l, '#.##') : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tV, format.volume) : ''), xloc.bar_index, yloc.price, (not ppP and not ppC and not ppV ? chart.fg_color : #00000000), label.style_label_down, chart.fg_color, (not ppP and not ppC and not ppV ? size.tiny : ppS), text.align_center, 'Swing High : ' + str.tostring(pp.h, format.mintick) + '\n -Price Change : %' + str.tostring((pp.h - pp.l) * 100 / pp.l, '#.##') + statTip)
if not na(pp_l)
label.new(b.i[ppLen], pp.l ,(ppP ? str.tostring(pp.l, format.mintick) : '') + (ppC ? (ppP ? ' ↓ %' : '↓ %') + str.tostring((pp.h - pp.l) * 100 / pp.h, '#.##') : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tV, format.volume) : ''), xloc.bar_index, yloc.price, (not ppP and not ppC and not ppV ? chart.fg_color : #00000000), label.style_label_up , chart.fg_color, (not ppP and not ppC and not ppV ? size.tiny : ppS), text.align_center, 'Swing Low : ' + str.tostring(pp.l, format.mintick) + '\n -Price Change : %' + str.tostring((pp.h - pp.l) * 100 / pp.h, '#.##') + statTip)
if pcShw and pcE != 'None'
f_checkBreaches(aPOC, pcE)
for i = 0 to aLIQ.size() - 1
x = aLIQ.get(i)
int qBX = x.bx.size()
for no = (qBX > 0 ? qBX - 1 : na) to 0
if no < x.bx.size()
cBX = x.bx.get(no)
mBX = math.avg(box.get_bottom(cBX), box.get_top(cBX))
if math.sign(close[1] - mBX) != math.sign(low - mBX) or math.sign(close[1] - mBX) != math.sign(high - mBX)
cBX.delete()
x.bx.remove(no)
else
cBX.set_right(b.i)
vpLen := barstate.islast ? last_bar_index - pp.x + ppLen : 1
pHst := ta.highest(b.h, vpLen > 0 ? vpLen + 1 : 1)
pLst := ta.lowest (b.l, vpLen > 0 ? vpLen + 1 : 1)
pStp := (pHst - pLst) / vpLev
[_, _, tVd] = f_calcHL(vpLen, true, 0)
if barstate.islast and nzV and vpLen > 0 and pStp > 0
if dVP.vp.size() > 0
for i = 0 to dVP.vp.size() - 1
dVP.vp.shift().delete()
if dPOC.size() > 0
for i = 0 to dPOC.size() - 1
dPOC.shift().delete()
tLIQ = dLIQ.shift()
if tLIQ.bx.size() > 0
for i = 0 to tLIQ.bx.size() - 1
tLIQ.bx.shift().delete()
tLIQ.b.shift()
for bI = vpLen to 1 //1 to vpLen
l = 0
for pLev = pLst to pHst by pStp
if b.h[bI] >= pLev and b.l[bI] < pLev + pStp
aVP.vs.set(l, aVP.vs.get(l) + nzV[bI] * ((b.h[bI] - b.l[bI]) == 0 ? 1 : pStp / (b.h[bI] - b.l[bI])))
l += 1
if dpcS
if bI == last_bar_index - pp.x
if dPCa.size() > 0
dPOC.push(line.new(b.i[bI], dPCa.get(dPCa.size() - 1).get_y2(), b.i[bI] + 1, pLst + (aVP.vs.indexof(aVP.vs.max()) + .50) * pStp, color = dpcC, width = 2))
else if bI < last_bar_index - pp.x
if dPOC.size() > 0
dPOC.push(line.new(b.i[bI], dPOC.get(dPOC.size() - 1).get_y2(), b.i[bI] + 1, pLst + (aVP.vs.indexof(aVP.vs.max()) + .50) * pStp, color = dpcC, width = 2))
dpcL := aVP.vs.indexof(aVP.vs.max())
ttV = aVP.vs.sum() * isVA
va = aVP.vs.get(dpcL)
laP := dpcL
lbP := dpcL
while va < ttV
if lbP == 0 and laP == vpLev - 1
break
vaP = 0.
if laP < vpLev - 1
vaP := aVP.vs.get(laP + 1)
vbP = 0.
if lbP > 0
vbP := aVP.vs.get(lbP - 1)
if vbP == 0 and vaP == 0
break
if vaP >= vbP
va += vaP
laP += 1
else
va += vbP
lbP -= 1
dLIQ.unshift(liquidity.new(array.new <bool> (na), array.new <box> (na)))
cLIQ = dLIQ.get(0)
for l = 0 to vpLev - 1
if vpShw
sbI = vpPlc == 'Right' ? b.i - int(aVP.vs.get(l) / aVP.vs.max() * vpLen * vpWth) : b.i - vpLen
ebI = vpPlc == 'Right' ? b.i : sbI + int( aVP.vs.get(l) / aVP.vs.max() * vpLen * vpWth)
dVP.vp.push(box.new(sbI, pLst + (l + 0.1) * pStp, ebI, pLst + (l + 0.9) * pStp, l >= lbP and l <= laP ? vpTVC : vpVVC, bgcolor = l >= lbP and l <= laP ? vpTVC : vpVVC))
if liqUF
if aVP.vs.get(l) / aVP.vs.max() < liqT
cLIQ.b.unshift(true)
cLIQ.bx.unshift(box.new(b.i, pLst + (l + 0.00) * pStp, b.i, pLst + (l + 1.00) * pStp, border_color = color(na), bgcolor = liqC))
else
cLIQ.bx.unshift(box.new(na, na, na, na))
cLIQ.b.unshift(false)
for bI = 0 to vpLen
int qBX = cLIQ.bx.size()
for no = 0 to (qBX > 0 ? qBX - 1 : na)
if no < cLIQ.bx.size()
if cLIQ.b.get(no)
cBX = cLIQ.bx.get(no)
mBX = math.avg(cBX.get_bottom(), cBX.get_top())
if math.sign(close[bI + 1] - mBX) != math.sign(low[bI] - mBX) or math.sign(close[bI + 1] - mBX) != math.sign(high[bI] - mBX) or math.sign(close[bI + 1] - mBX) != math.sign(close[bI] - mBX)
cBX.set_left(b.i[bI])
cLIQ.b.set(no, false)
if vpB
dVP.vp.push(box.new(b.i - vpLen, pHst, b.i, pLst, vpBC, bgcolor = vpBC))
if pcShw and not dpcS
dVP.vp.push(box.new(b.i - vpLen, pLst + (dpcL + .40) * pStp, b.i, pLst + (dpcL + .60) * pStp, pcC, bgcolor = pcC))
vah = f_drawLineX(b.i - vpLen, pLst + (laP + 1.00) * pStp, b.i, pLst + (laP + 1.00) * pStp, xloc.bar_index, extend.none, vhShw ? vaHC : #00000000, line.style_solid, 2)
val = f_drawLineX(b.i - vpLen, pLst + (lbP + 0.00) * pStp, b.i, pLst + (lbP + 0.00) * pStp, xloc.bar_index, extend.none, vlShw ? vaLC : #00000000, line.style_solid, 2)
if vaB
linefill.new(vah, val, vaBC)
if ppLev != 'Swing High/Low'
statTip = '\n -Traded Volume : ' + str.tostring(tVd, format.volume) + ' (' + str.tostring(vpLen - 1) + ' bars)' +
'\n *Average Volume/Bar : ' + str.tostring(tVd / (vpLen - 1), format.volume) +
'\n\nProfile High : ' + str.tostring(pHst, format.mintick) + ' ↑ %' + str.tostring((pHst - pLst) / pLst * 100, '#.##') +
'\nProfile Low : ' + str.tostring(pLst, format.mintick) + ' ↓ %' + str.tostring((pHst - pLst) / pHst * 100, '#.##') +
'\n -Point Of Control : ' + str.tostring(pLst + (dpcL + 0.50) * pStp, format.mintick) +
'\n\nValue Area High : ' + str.tostring(pLst + (laP + 1.00) * pStp, format.mintick) +
'\nValue Area Low : ' + str.tostring(pLst + (lbP + 0.00) * pStp, format.mintick) +
'\n -Value Area Width : %' + str.tostring(((pLst + (laP + 1.00) * pStp) - (pLst + (lbP + 0.00) * pStp)) / (pHst - pLst) * 100, '#.##') +
'\n\nNumber of Bars (Profile) : ' + str.tostring(vpLen) +
(ppC ? '\n\n*price change caculated based on last swing high/low and last price' : '')
uPl = ppLev == 'Value Area High/Low' ? pLst + (laP + 1.00) * pStp : pHst
lPl = ppLev == 'Value Area High/Low' ? pLst + (lbP + 0.00) * pStp : pLst
uTx = (ppP ? str.tostring(uPl, format.mintick) : '') + (pp.s == 'L' ? (ppC ? (ppP ? ' ↑ %' : '↑ %') + str.tostring((close - pp.l) * 100 / pp.l, '#.##') + '*' : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tVd, format.volume) : '') : '')
lTx = (ppP ? str.tostring(lPl, format.mintick) : '') + (pp.s == 'H' ? (ppC ? (ppP ? ' ↓ %' : '↓ %') + str.tostring((pp.h - close) * 100 / pp.h, '#.##') + '*' : '') + (ppV ? (ppP or ppC ? '\n' : '') + str.tostring(tVd, format.volume) : '') : '')
f_drawLabelX(b.i - vpLen / 2, uPl, uTx, xloc.bar_index, yloc.price, #00000000, label.style_label_down, chart.fg_color, ppS, text.align_center, 'Profile High : ' + str.tostring(pHst, format.mintick) + '\n %' + str.tostring((pHst - pLst) / pLst * 100, '#.##') + ' higher than the Profile Low' + statTip)
f_drawLabelX(b.i - vpLen / 2, lPl, lTx, xloc.bar_index, yloc.price, #00000000, label.style_label_up , chart.fg_color, ppS, text.align_center, 'Profile Low : ' + str.tostring(pLst, format.mintick) + '\n %' + str.tostring((pHst - pLst) / pHst * 100, '#.##') + ' lower than the Profile High' + statTip)
//-----------------------------------------------------------------------------}
//Alerts
//-----------------------------------------------------------------------------{
priceTxt = str.tostring(close, format.mintick)
tickerTxt = syminfo.ticker
if ta.cross(close, pLst + (dpcL + 0.50) * pStp) and pcShw
alert(tickerTxt + ' : Swings Volume Profile : Price touches/crosses Point Of Control Line, price ' + priceTxt)
if ta.cross(close, pLst + (laP + 1.00) * pStp) and vhShw
alert(tickerTxt + ' : Swings Volume Profile : Price touches/crosses Value Area High Line, price ' + priceTxt)
if ta.cross(close, pLst + (lbP + 0.00) * pStp) and vlShw
alert(tickerTxt + ' : Swings Volume Profile : Price touches/crosses Value Area Low Line, price ' + priceTxt)
//-----------------------------------------------------------------------------}