xmd79

VPFR-HSAF

Nov 6th, 2022
275
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.36 KB | None | 0 0
  1. // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
  2. // © HSAF
  3.  
  4. //@version=5
  5. indicator("VPFR-HSAF", overlay=true, max_boxes_count=500)
  6.  
  7. //==========================
  8. //Inputs
  9. //==========================
  10. sessionType = input.string('Daily', 'Session Type', options=['Tokyo','London','New York','Daily','Weekly', 'Monthly'])
  11.  
  12. showProf = input.bool(true, 'Show Volume Profile', group='Display')
  13. showPoc = input.bool(true, 'Show POC', group='Display')
  14. showVA = input.bool(true, 'Show Value Area', group='Display')
  15. showCur = input.bool(true, 'Show Live Zone', group='Display')
  16. resolution = input.int(30, 'Resolution', minval=5, tooltip='The higher the value, the more refined of a profile, but less profiles shown on chart', group='Volume Profile Settings')
  17. smoothVol = input.bool(false, 'Smooth Volume Data', tooltip='Useful for assets that have very large spikes in volume over large bars, helps create better profiles', group='Volume Profile Settings')
  18. dataTf = ''
  19.  
  20. bullCol = input.color(color.rgb(76, 175, 79, 50), 'Up Volume', group='Appearance')
  21. bearCol = input.color(color.rgb(255, 82, 82, 50), 'Down Volume', group='Appearance')
  22. pocCol = input.color(color.red, 'POC', inline='p', group='Appearance')
  23. pocWid = input.int(1, 'Thickness', inline='p', group='Appearance')
  24. vahCol = input.color(color.aqua, 'VAH', inline='h', group='Appearance')
  25. vahWid = input.int(1, 'Thickness', inline='h', group='Appearance')
  26. valCol = input.color(color.aqua, 'VAL', inline='l', group='Appearance')
  27. valWid = input.int(1, 'Thickness', inline='l', group='Appearance')
  28. boxWid = input.int(1, 'Session Box Thickness', group='Appearance')
  29.  
  30. //==========================
  31. //Constants / Variable Declaration
  32. //==========================
  33. var int zoneStart = 0
  34. int lookback = bar_index - zoneStart
  35. var activeZone = false
  36.  
  37. // Defining arrays that store the information
  38. var vpGreen = array.new_float(resolution, 0) // Sum of volume on long bars
  39. var vpRed = array.new_float(resolution, 0) // Same thing but with red bars
  40. var zoneBounds = array.new_float(resolution, 0) // array that stores the highest value that can be in a zone
  41.  
  42. //Values to store current intra bar data
  43. var float[] ltfOpen = array.new_float(0)
  44. var float[] ltfClose = array.new_float(0)
  45. var float[] ltfHigh = array.new_float(0)
  46. var float[] ltfLow = array.new_float(0)
  47. var float[] ltfVolume = array.new_float(0)
  48.  
  49.  
  50. vol() =>
  51. smoothVol ? ta.ema(volume, 5) : volume
  52.  
  53. //Getting intrabar intial data
  54. [dO, dC, dH, dL, dV] = request.security_lower_tf(syminfo.tickerid, dataTf, [open, close, high, low, vol()])
  55.  
  56. //==========================
  57. //Functions
  58. //==========================
  59. resetProfile(enable) =>
  60. if enable
  61. array.fill(vpGreen, 0)
  62. array.fill(vpRed, 0)
  63. array.clear(ltfOpen)
  64. array.clear(ltfHigh)
  65. array.clear(ltfLow)
  66. array.clear(ltfClose)
  67. array.clear(ltfVolume)
  68.  
  69. profHigh = ta.highest(high, lookback+1)[1]
  70. profLow = ta.lowest(low, lookback+1)[1]
  71.  
  72. tr = ta.atr(1)
  73. atr = ta.atr(14)
  74.  
  75. get_vol(y11, y12, y21, y22, height, vol) =>
  76. 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)
  77.  
  78. profileAdd(o, h, l, c, v, g, w) =>
  79. //Array to store how much to distribute in each zone, on scale of 1 for full gap size to 0
  80. zoneDist = array.new_float(resolution, 0)
  81. distSum = 0.0
  82. // Going over each zone
  83. for i = 0 to array.size(vpGreen) - 1
  84. // Checking to see if cur bar is in zone
  85. zoneTop = array.get(zoneBounds, i)
  86. zoneBot = zoneTop - g
  87.  
  88. body_top = math.max(c, o)
  89. body_bot = math.min(c, o)
  90. itsgreen = c >= o
  91.  
  92. topwick = h - body_top
  93. bottomwick = body_bot - l
  94. body = body_top - body_bot
  95.  
  96. bodyvol = body * v / (2 * topwick + 2 * bottomwick + body)
  97. topwickvol = 2 * topwick * v / (2 * topwick + 2 * bottomwick + body)
  98. bottomwickvol = 2 * bottomwick * v / (2 * topwick + 2 * bottomwick + body)
  99.  
  100. 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)
  101. 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)
  102.  
  103. calcSession(update) =>
  104. array.fill(vpGreen, 0)
  105. array.fill(vpRed, 0)
  106. if bar_index > lookback and update
  107. gap = (profHigh - profLow) / resolution
  108.  
  109. // Defining profile bounds
  110. for i = 0 to resolution - 1
  111. array.set(zoneBounds, i, profHigh - gap * i)
  112.  
  113. // Putting each bar inside zone into the volume profile array
  114. if array.size(ltfOpen) > 0
  115. for j = 0 to array.size(ltfOpen) - 1
  116. profileAdd(array.get(ltfOpen, j), array.get(ltfHigh, j), array.get(ltfLow, j), array.get(ltfClose, j), array.get(ltfVolume, j), gap, 1)
  117.  
  118. pocLevel() =>
  119. float maxVol = 0
  120. int levelInd = 0
  121. for i = 0 to array.size(vpRed) - 1
  122. if array.get(vpRed, i) + array.get(vpGreen, i) > maxVol
  123. maxVol := array.get(vpRed, i) + array.get(vpGreen, i)
  124. levelInd := i
  125.  
  126. float outLevel = na
  127. if levelInd != array.size(vpRed) - 1
  128. outLevel := array.get(zoneBounds, levelInd) - (array.get(zoneBounds, levelInd) - array.get(zoneBounds, levelInd+1)) / 2
  129. outLevel
  130.  
  131. valueLevels(poc) =>
  132. float gap = (profHigh - profLow) / resolution
  133. float volSum = array.sum(vpRed) + array.sum(vpGreen)
  134. float volCnt = 0
  135.  
  136. float vah = profHigh
  137. float val = profLow
  138.  
  139. //Finding poc index
  140. int pocInd = 0
  141. for i = 0 to array.size(zoneBounds)-2
  142. if array.get(zoneBounds, i) >= poc and array.get(zoneBounds, i + 1) < poc
  143. pocInd := i
  144.  
  145. volCnt += (array.get(vpRed, pocInd) + array.get(vpGreen, pocInd))
  146. for i = 1 to array.size(vpRed)
  147. if pocInd + i >= 0 and pocInd + i < array.size(vpRed)
  148. volCnt += (array.get(vpRed, pocInd + i) + array.get(vpGreen, pocInd + i))
  149. if volCnt >= volSum * 0.7
  150. break
  151. else
  152. val := array.get(zoneBounds, pocInd + i) - gap
  153. if pocInd - i >= 0 and pocInd - i < array.size(vpRed)
  154. volCnt += (array.get(vpRed, pocInd - i) + array.get(vpGreen, pocInd - i))
  155. if volCnt >= volSum * 0.7
  156. break
  157. else
  158. vah := array.get(zoneBounds, pocInd - i)
  159.  
  160. [val, vah]
  161.  
  162. drawNewZone(update) =>
  163. if bar_index > lookback and update and array.sum(vpGreen) + array.sum(vpRed) > 0
  164. gap = (profHigh - profLow) / resolution
  165. float leftMax = bar_index[lookback]
  166. float rightMax = bar_index[int(lookback / 1.4)]
  167. float rightMaxVol = array.max(vpGreen)+array.max(vpRed)
  168. float buffer = gap / 10
  169. if showProf
  170. for i = 0 to array.size(vpRed) - 1
  171. greenEnd = int(leftMax + (rightMax - leftMax) * (array.get(vpGreen, i) / rightMaxVol))
  172. redEnd = int(greenEnd + (rightMax - leftMax) * (array.get(vpRed, i) / rightMaxVol))
  173. box.new(int(leftMax), array.get(zoneBounds, i) - buffer, greenEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bullCol, border_width=0)
  174. box.new(greenEnd, array.get(zoneBounds, i) - buffer, redEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0)
  175. box.new(int(leftMax), profHigh, bar_index-1, profLow, chart.fg_color, boxWid, line.style_dashed, bgcolor=color.rgb(0,0,0,100))
  176. poc = pocLevel()
  177. [val, vah] = valueLevels(poc)
  178. if showPoc
  179. line.new(int(leftMax), poc, bar_index-1, poc, color=pocCol, width=pocWid)
  180. if showVA
  181. line.new(int(leftMax), vah, bar_index-1, vah, color=vahCol, width=vahWid)
  182. line.new(int(leftMax), val, bar_index-1, val, color=valCol, width=valWid)
  183.  
  184.  
  185. //if update
  186. // resetProfile(true)
  187.  
  188. drawCurZone(update) =>
  189. var line pocLine = na
  190. var line vahLine = na
  191. var line valLine = na
  192. var box outBox = na
  193.  
  194. var redBoxes = array.new_box(array.size(vpRed), na)
  195. var greenBoxes = array.new_box(array.size(vpRed), na)
  196.  
  197. if bar_index > lookback and update and array.sum(vpGreen) + array.sum(vpRed) > 0
  198. //Clearing the previous boxes and array
  199. if not na(pocLine)
  200. line.delete(pocLine)
  201. if not na(vahLine)
  202. line.delete(vahLine)
  203. if not na(valLine)
  204. line.delete(valLine)
  205. if not na(outBox)
  206. box.delete(outBox)
  207.  
  208. for i = 0 to array.size(redBoxes) - 1
  209. if not na(array.get(redBoxes, i))
  210. box.delete(array.get(redBoxes, i))
  211. box.delete(array.get(greenBoxes, i))
  212.  
  213.  
  214. gap = (profHigh - profLow) / resolution
  215. float leftMax = bar_index[lookback]
  216. float rightMax = bar_index[int(lookback / 1.4)]
  217. float rightMaxVol = array.max(vpGreen)+array.max(vpRed)
  218. float buffer = gap / 10
  219. if showProf
  220. for i = 0 to array.size(vpRed) - 1
  221. greenEnd = int(leftMax + (rightMax - leftMax) * (array.get(vpGreen, i) / rightMaxVol))
  222. redEnd = int(greenEnd + (rightMax - leftMax) * (array.get(vpRed, i) / rightMaxVol))
  223. 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))
  224. array.set(redBoxes, i, box.new(greenEnd, array.get(zoneBounds, i) - buffer, redEnd, array.get(zoneBounds, i) - gap + buffer, bgcolor=bearCol, border_width=0))
  225. outBox := box.new(int(leftMax), profHigh, bar_index-1, profLow, chart.fg_color, boxWid, line.style_dashed, bgcolor=color.rgb(0,0,0,100))
  226.  
  227. poc = pocLevel()
  228. [val, vah] = valueLevels(poc)
  229. if showPoc
  230. line.new(int(leftMax), poc, bar_index-1, poc, color=pocCol, width=pocWid)
  231. if showVA
  232. line.new(int(leftMax), vah, bar_index-1, vah, color=vahCol, width=vahWid)
  233. line.new(int(leftMax), val, bar_index-1, val, color=valCol, width=valWid)
  234.  
  235. combArray(arr1, arr2) =>
  236. out = array.copy(arr1)
  237. if array.size(arr2) > 0
  238. for i = 0 to array.size(arr2) - 1
  239. array.push(out, array.get(arr2, i))
  240. out
  241.  
  242. updateIntra(o, h, l, c, v) =>
  243. if array.size(o) > 0
  244. for i = 0 to array.size(o) - 1
  245. array.push(ltfOpen, array.get(o, i))
  246. array.push(ltfHigh,array.get(h, i))
  247. array.push(ltfLow,array.get(l, i))
  248. array.push(ltfClose,array.get(c, i))
  249. array.push(ltfVolume,array.get(v, i))
  250.  
  251.  
  252. //==========================
  253. //Calculations
  254. //==========================
  255. //Detecting different start dates
  256. newDaily = dayofweek != dayofweek[1]
  257. newWeekly = (dayofweek != dayofweek[1] + 1) and (dayofweek != dayofweek[1])
  258. newMonthly = (dayofmonth != dayofmonth[1] + 1) and (dayofmonth != dayofmonth[1])
  259.  
  260. utcHour = hour(time(timeframe.period, '0000-2400', 'GMT'), 'GMT')
  261.  
  262. newTokyo = utcHour != utcHour[1] + 1 and utcHour != utcHour[1]
  263. endTokyo = utcHour >= 9 and utcHour[1] < 9
  264.  
  265. newLondon = utcHour >= 7 and utcHour[1] < 7
  266. endLondon = utcHour >= 16 and utcHour[1] < 16
  267.  
  268. newNewYork = utcHour >= 13 and utcHour[1] < 13
  269. endNewYork = utcHour >= 22 and utcHour[1] < 22
  270.  
  271. newSession = switch sessionType
  272. 'Tokyo' => newTokyo
  273. 'London' => newLondon
  274. 'New York' => newNewYork
  275. 'Daily' => newDaily
  276. 'Weekly' => newWeekly
  277. 'Monthly' => newMonthly
  278.  
  279. zoneEnd = switch sessionType
  280. 'Tokyo' => endTokyo
  281. 'London' => endLondon
  282. 'New York' => endNewYork
  283. 'Daily' => newDaily
  284. 'Weekly' => newWeekly
  285. 'Monthly' => newMonthly
  286.  
  287. //Re calculating and drawing zones
  288. calcSession(zoneEnd or (barstate.islast and showCur))
  289. drawNewZone(zoneEnd)
  290. drawCurZone(barstate.islast and not zoneEnd and showCur and activeZone)
  291.  
  292. //Reseting profie at start of new zone
  293. resetProfile(newSession)
  294.  
  295. //Updating data arrays
  296. updateIntra(dO, dH, dL, dC, dV)
  297.  
  298. //Reseting zone start value
  299. if zoneEnd
  300. activeZone := false
  301.  
  302. if newSession
  303. zoneStart := bar_index
  304. activeZone := true
  305.  
Advertisement
Add Comment
Please, Sign In to add comment