the one in the picture is what it should look like but there wasnt source code for it so this is leviathancapital , he makes good free ones
Code: Select all
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Leviathan
// Some elements of generating Profiles are inspired by @LonesomeTheBlue's volume profile script
//@version=5
indicator("Open Interest Profile - By Leviathan", overlay=true, max_boxes_count=500, max_bars_back=1000)
//==========================
//Inputs
//==========================
sessionType = input.string('Weekly', 'Session / Lookback', options=['Tokyo','London','New York','Daily','Weekly', 'Monthly'])
dispMode = input.string('Mode 3', 'OI Profile Mode', ['Mode 1', 'Mode 2', 'Mode 3'], group='Display')
showVAb = input.bool(false, 'Show OI Value Area', group='Display')
showSbox = input.bool(false, 'Show Session Box', group='Display')
showProf = input.bool(true, 'Show Profile', group='Display')
showCur = input.bool(true, 'Show Current Session', group='Display')
showLabels = input.bool(false, 'Show Session Lables', group='Display')
resolution = input.int(50, 'Resolution', minval=5, tooltip='The higher the value, the more refined of a profile, but less profiles shown on chart', group='Profile Settings')
volType = input.string('Open Interest', 'Profile Data Type', options=['Open Interest'], group='Profile Settings')
VAwid = input.int(60, 'OI Value Area %', minval=1, maxval=100, group='Profile Settings')
smoothVol = input.bool(false, 'Smooth OI Data', tooltip='Useful for assets that have very large spikes in volume over large bars, helps create better profiles', group='Profile Settings')
dataTf = ''
bullCol = input.color(color.rgb(76, 175, 79, 50), 'OI Increase', group='Appearance')
bearCol = input.color(color.rgb(255, 82, 82, 50), 'OI Decrease', group='Appearance')
VAbCol = input.color(color.rgb(107, 159, 255, 90), 'Value Area Box', group='Appearance' )
boxWid = input.int(1, 'Session Box Thickness', group='Appearance')
//==========================
//Constants / Variable Declaration
//==========================
var int zoneStart = 0
var int tokyoStart = 0
var int londonStart = 0
var int nyStart = 0
int lookback = bar_index - zoneStart
var activeZone = false
// Defining arrays that store the information
var vpGreen = array.new_float(resolution, 0) // Sum of volume on long bars
var vpRed = array.new_float(resolution, 0) // Same thing but with red bars
var zoneBounds = array.new_float(resolution, 0) // array that stores the highest value that can be in a zone
//Values to store current intra bar data
var float[] ltfOpen = array.new_float(0)
var float[] ltfClose = array.new_float(0)
var float[] ltfHigh = array.new_float(0)
var float[] ltfLow = array.new_float(0)
var float[] ltfVolume = array.new_float(0)
//Getting OI Data
string userSymbol = syminfo.prefix + ":" + syminfo.ticker
string openInterestTicker = str.format("{0}_OI", userSymbol)
string timeframe = syminfo.type == "futures" and timeframe.isintraday ? "1D" : timeframe.period
deltaOi = request.security(openInterestTicker, timeframe, close-close[1], ignore_invalid_symbol = true)
//Selecting what vol type to use
vol() =>
out = smoothVol ? ta.ema(volume, 5) : volume
if volType == 'Open Interest'
out := deltaOi
out
//Getting intrabar intial data
[dO, dC, dH, dL, dV] = request.security_lower_tf(syminfo.tickerid, dataTf, [open, close, high, low, vol()])
//==========================
//Functions
//==========================
resetProfile(enable) =>
if enable
array.fill(vpGreen, 0)
array.fill(vpRed, 0)
array.clear(ltfOpen)
array.clear(ltfHigh)
array.clear(ltfLow)
array.clear(ltfClose)
array.clear(ltfVolume)
profHigh = ta.highest(high, lookback+1)[1]
profLow = ta.lowest(low, lookback+1)[1]
tr = ta.atr(1)
atr = ta.atr(14)
get_vol(y11, y12, y21, y22, height, vol) =>
nz(math.max(math.min(math.max(y11, y12), math.max(y21, y22)) - math.max(math.min(y11, y12), math.min(y21, y22)), 0) * vol / height)
profileAdd(o, h, l, c, v, g, w) =>
//Array to store how much to distribute in each zone, on scale of 1 for full gap size to 0
zoneDist = array.new_float(resolution, 0)
distSum = 0.0
// Going over each zone
for i = 0 to array.size(vpGreen) - 1
// Checking to see if cur bar is in zone
zoneTop = array.get(zoneBounds, i)
zoneBot = zoneTop - g
body_top = math.max(c, o)
body_bot = math.min(c, o)
itsgreen = c >= o
topwick = h - body_top
bottomwick = body_bot - l
body = body_top - body_bot
bodyvol = body * v / (2 * topwick + 2 * bottomwick + body)
topwickvol = 2 * topwick * v / (2 * topwick + 2 * bottomwick + body)
bottomwickvol = 2 * bottomwick * v / (2 * topwick + 2 * bottomwick + body)
if volType == 'Volume'
array.set(vpGreen, i, array.get(vpGreen, i) + (itsgreen ? get_vol(zoneBot, zoneTop, body_bot, body_top, body, bodyvol) : 0) + get_vol(zoneBot, zoneTop, body_top, h, topwick, topwickvol) / 2 + get_vol(zoneBot, zoneTop, body_bot, l, bottomwick, bottomwickvol) / 2)
array.set(vpRed, i, array.get(vpRed, i) + (itsgreen ? 0 : get_vol(zoneBot, zoneTop, body_bot, body_top, body, bodyvol)) + get_vol(zoneBot, zoneTop, body_top, h, topwick, topwickvol) / 2 + get_vol(zoneBot, zoneTop, body_bot, l, bottomwick, bottomwickvol) / 2)
else if volType == 'Open Interest'
if v > 0
array.set(vpGreen, i, array.get(vpGreen, i) + get_vol(zoneBot, zoneTop, body_bot, body_top, body, v))// + get_vol(zoneBot, zoneTop, body_top, h, topwick, topwickvol) / 2 + get_vol(zoneBot, zoneTop, body_bot, l, bottomwick, bottomwickvol) / 2)
if v < 0
array.set(vpRed, i, array.get(vpRed, i) + get_vol(zoneBot, zoneTop, body_bot, body_top, body, -v))// + get_vol(zoneBot, zoneTop, body_top, h, topwick, topwickvol) / 2 + get_vol(zoneBot, zoneTop, body_bot, l, bottomwick, bottomwickvol) / 2)
calcSession(update) =>
array.fill(vpGreen, 0)
array.fill(vpRed, 0)
if bar_index > lookback and update
gap = (profHigh - profLow) / resolution
// Defining profile bounds
for i = 0 to resolution - 1
array.set(zoneBounds, i, profHigh - gap * i)
// Putting each bar inside zone into the volume profile array
if array.size(ltfOpen) > 0
for j = 0 to array.size(ltfOpen) - 1
profileAdd(array.get(ltfOpen, j), array.get(ltfHigh, j), array.get(ltfLow, j), array.get(ltfClose, j), array.get(ltfVolume, j), gap, 1)
pocLevel() =>
float maxVol = 0
int levelInd = 0
for i = 0 to array.size(vpRed) - 1
if array.get(vpRed, i) + array.get(vpGreen, i) > maxVol
maxVol := array.get(vpRed, i) + array.get(vpGreen, i)
levelInd := i
float outLevel = na
if levelInd != array.size(vpRed) - 1
outLevel := array.get(zoneBounds, levelInd) - (array.get(zoneBounds, levelInd) - array.get(zoneBounds, levelInd+1)) / 2
outLevel
valueLevels(poc) =>
float gap = (profHigh - profLow) / resolution
float volSum = array.sum(vpRed) + array.sum(vpGreen)
float volCnt = 0
float vah = profHigh
float val = profLow
//Finding poc index
int pocInd = 0
for i = 0 to array.size(zoneBounds)-2
if array.get(zoneBounds, i) >= poc and array.get(zoneBounds, i + 1) < poc
pocInd := i
volCnt += (array.get(vpRed, pocInd) + array.get(vpGreen, pocInd))
for i = 1 to array.size(vpRed)
if pocInd + i >= 0 and pocInd + i < array.size(vpRed)
volCnt += (array.get(vpRed, pocInd + i) + array.get(vpGreen, pocInd + i))
if volCnt >= volSum * (VAwid/100)
break
else
val := array.get(zoneBounds, pocInd + i) - gap
if pocInd - i >= 0 and pocInd - i < array.size(vpRed)
volCnt += (array.get(vpRed, pocInd - i) + array.get(vpGreen, pocInd - i))
if volCnt >= volSum * (VAwid/100)
break
else
vah := array.get(zoneBounds, pocInd - i)
[val, vah]
drawNewZone(update) =>
if bar_index > lookback and update and array.sum(vpGreen) + array.sum(vpRed) > 0
gap = (profHigh - profLow) / resolution
float leftMax = bar_index[lookback]
float rightMax = bar_index[int(lookback / 1.4)]
float rightMaxVol = array.max(vpGreen)+array.max(vpRed)
float buffer = gap / 10
if showLabels
label.new((bar_index - 1 + int(leftMax))/2, profHigh, sessionType, color=color.rgb(0,0,0,100), textcolor=chart.fg_color)
if showProf
for i = 0 to array.size(vpRed) - 1
greenEnd = int(leftMax + (rightMax - leftMax) * (array.get(vpGreen, i) / rightMaxVol))
redEnd = int(greenEnd + (rightMax - leftMax) * (array.get(vpRed, i) / rightMaxVol))
if dispMode == 'Mode 2'
box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0)
box.new(greenEnd, array.get(zoneBounds, i) - buffer, redEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0)
else if dispMode == 'Mode 1'
box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0)
else
box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0)
box.new(int(leftMax)-redEnd+greenEnd, array.get(zoneBounds, i) - buffer, int(leftMax), array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0)
poc = pocLevel()
[val, vah] = valueLevels(poc)
if showVAb
box.new(int(leftMax), vah, bar_index-1, val, border_color=color.rgb(54, 58, 69, 100), bgcolor=VAbCol)
if showSbox
box.new(int(leftMax), profHigh, bar_index-1, profLow, chart.fg_color, boxWid, line.style_dashed, bgcolor=color.rgb(0,0,0,100))
//if update
// resetProfile(true)
drawCurZone(update, delete) =>
var line pocLine = na
var line vahLine = na
var line valLine = na
var box outBox = na
var label sessionLab = na
var redBoxes = array.new_box(array.size(vpRed), na)
var greenBoxes = array.new_box(array.size(vpRed), na)
if bar_index > lookback and update and array.sum(vpGreen) + array.sum(vpRed) > 0
//Clearing the previous boxes and array
if not na(pocLine)
line.delete(pocLine)
if not na(vahLine)
line.delete(vahLine)
if not na(valLine)
line.delete(valLine)
if not na(outBox)
box.delete(outBox)
if not na(sessionLab)
label.delete(sessionLab)
for i = 0 to array.size(redBoxes) - 1
if not na(array.get(redBoxes, i))
box.delete(array.get(redBoxes, i))
box.delete(array.get(greenBoxes, i))
gap = (profHigh - profLow) / resolution
float leftMax = bar_index[lookback]
float rightMax = bar_index[int(lookback / 1.4)]
float rightMaxVol = array.max(vpGreen)+array.max(vpRed)
float buffer = gap / 10
if showLabels
sessionLab := label.new((bar_index - 1 + int(leftMax))/2, profHigh, sessionType, color=color.rgb(0,0,0,100), textcolor=chart.fg_color)
if showProf
for i = 0 to array.size(vpRed) - 1
greenEnd = int(leftMax + (rightMax - leftMax) * (array.get(vpGreen, i) / rightMaxVol))
redEnd = int(greenEnd + (rightMax - leftMax) * (array.get(vpRed, i) / rightMaxVol))
if dispMode == 'Mode 2'
array.set(greenBoxes, i, box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0))
array.set(redBoxes, i, box.new(greenEnd, array.get(zoneBounds, i) - buffer, redEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0))
else if dispMode == 'Mode 1'
array.set(greenBoxes, i, box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0))
else
array.set(greenBoxes, i, box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0))
array.set(redBoxes, i, box.new(int(leftMax)-redEnd+greenEnd, array.get(zoneBounds, i) - buffer, int(leftMax), array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0))
poc = pocLevel()
[val, vah] = valueLevels(poc)
if showVAb
box.new(int(leftMax), vah, bar_index-1, val, border_color=color.rgb(54, 58, 69, 100), bgcolor=VAbCol)
if showSbox
box.new(int(leftMax), profHigh, bar_index-1, profLow, chart.fg_color, boxWid, line.style_dashed, bgcolor=color.rgb(0,0,0,100))
if delete
box.delete(outBox)
line.delete(pocLine)
line.delete(vahLine)
line.delete(valLine)
for i = 0 to array.size(greenBoxes)-1
box.delete(array.get(greenBoxes, i))
for i = 0 to array.size(redBoxes)-1
box.delete(array.get(redBoxes, i))
drawForexBox(startBar, title, top, bottom) =>
box.new(int(startBar), top, bar_index-1, bottom, chart.fg_color, 2, line.style_dashed, bgcolor=color.rgb(0,0,0,100))
if showLabels
label.new((bar_index - 1 + int(startBar))/2, top, title, color=color.rgb(0,0,0,100), textcolor=chart.fg_color)
combArray(arr1, arr2) =>
out = array.copy(arr1)
if array.size(arr2) > 0
for i = 0 to array.size(arr2) - 1
array.push(out, array.get(arr2, i))
out
updateIntra(o, h, l, c, v) =>
if array.size(o) > 0
for i = 0 to array.size(o) - 1
array.push(ltfOpen, array.get(o, i))
array.push(ltfHigh,array.get(h, i))
array.push(ltfLow,array.get(l, i))
array.push(ltfClose,array.get(c, i))
array.push(ltfVolume,array.get(v, i))
//==========================
//Calculations
//==========================
//Detecting different start dates
newDaily = dayofweek != dayofweek[1]
newWeekly = (dayofweek != dayofweek[1] + 1) and (dayofweek != dayofweek[1])
newMonthly = (dayofmonth != dayofmonth[1] + 1) and (dayofmonth != dayofmonth[1])
utcHour = hour(time(timeframe.period, '0000-2400', 'GMT'), 'GMT')
newTokyo = utcHour != utcHour[1] + 1 and utcHour != utcHour[1]
endTokyo = utcHour >= 9 and utcHour[1] < 9
newLondon = utcHour >= 7 and utcHour[1] < 7
endLondon = utcHour >= 16 and utcHour[1] < 16
newNewYork = utcHour >= 13 and utcHour[1] < 13
endNewYork = utcHour >= 22 and utcHour[1] < 22
newSession = switch sessionType
'Tokyo' => newTokyo
'London' => newLondon
'New York' => newNewYork
'Daily' => newDaily
'Weekly' => newWeekly
'Monthly' => newMonthly
=> newDaily
zoneEnd = switch sessionType
'Tokyo' => endTokyo
'London' => endLondon
'New York' => endNewYork
'Daily' => newDaily
'Weekly' => newWeekly
'Monthly' => newMonthly
=> newDaily
isForex = sessionType == 'FX Session'
//Re calculating and drawing zones
calcSession((zoneEnd or (barstate.islast and showCur)) and not isForex)
drawNewZone(zoneEnd and not isForex)
drawCurZone(barstate.islast and not zoneEnd and showCur and activeZone and not isForex, zoneEnd)
//Reseting profie at start of new zone
resetProfile(newSession)
//Updating data arrays
updateIntra(dO, dH, dL, dC, dV)
//Reseting zone start value
if zoneEnd
activeZone := false
if newSession
zoneStart := bar_index
activeZone := true