ajiim

🎁

Sep 15th, 2026
2,094
3
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 107.63 KB | None | 3 0
  1. //@version=6
  2. indicator("Forever ProΒ°", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500)
  3.  
  4. grpalerts = "ALERTS SETTINGS"
  5. enableAlerts = input.bool(true, "Alerts?", group=grpalerts)
  6. alertSMTFVG = input.bool(true, "SMT & FVG Tagged?", group=grpalerts, active=enableAlerts)
  7. alertModelActive = input.bool(true, "Model Active?", group=grpalerts, active=enableAlerts)
  8. alertProjHit = input.bool(false, "Orderblock Projection Hit?", group=grpalerts, active=enableAlerts)
  9. alertERLHit = input.bool(false, "External Range Liquidity Hit?", group=grpalerts, active=enableAlerts)
  10.  
  11. grpgen = "GENERAL SETTINGS"
  12. showHistory = input.int(1, "History", group=grpgen, minval=1, tooltip="Number of setups to keep visible. Active trades always shown.")
  13. discardInvalid = input.bool(true, "Discard Invalidated History", group=grpgen, tooltip="When enabled, stopped-out (failed) trades are completely removed. If disabled, they turn gray.")
  14. bias = input.string("Neutral", "Bias", group=grpgen, options=["Neutral","Bullish","Bearish"])
  15. modelType = input.string("Auto", "Timeframe Alignment",group=grpgen, options=["Auto","1m-15m","3m-30m","5m-1H","15m-4H","1H-1D","4H-1W","1D-1W","6H-15m","90M-5m","Custom"])
  16. customLTF = input.timeframe("5", "Custom LTF ", group=grpgen, inline="custom", active=modelType=="Custom")
  17. customHTF = input.timeframe("60", "", group=grpgen, inline="custom", tooltip="Only active when Alignment is set to Custom", active=modelType=="Custom")
  18. obSLCalc = input.string("Automatic","OB Invalidation", group=grpgen, options=["Automatic","OB High Low","SMT Based Invalidation"], tooltip="Automatic uses SMT-based SL below 1H, OB High/Low on 1H and above.")
  19. obProjBool = input.bool(true, "", group=grpgen, inline="proj")
  20. obProjInput = input.string("1, 2","OB Projections",group=grpgen, inline="proj")
  21. projCalc = input.string("Confirmation Close", "Projection Calculation", group=grpgen, options=["Breaker Range", "Confirmation Close"], tooltip="Breaker Range calculates targets from the OB line. Confirmation Close calculates targets from the closing price of the breakout candle.")
  22.  
  23. grp_po3_main = "PO3Β° SETTINGS"
  24. enable_po3 = input.bool(true, "PO3 Candles", group = grp_po3_main)
  25. po3_tf = input.timeframe('', 'Timeframe', inline = 'po3_tf', group = grp_po3_main, active = enable_po3)
  26. po3_tf_auto = input.bool(true, 'Set Automatically', inline = 'po3_tf', group = grp_po3_main, active = enable_po3)
  27. po3_num = input.int(1, 'Number of HTF Candles', minval = 1, group = grp_po3_main, active = enable_po3)
  28. po3_offset = input.int(15, 'Offset', group = grp_po3_main, active = enable_po3)
  29. po3_size = input.string('Medium', 'Size', options = ['Small', 'Medium', 'Large'], group = grp_po3_main, active = enable_po3)
  30. po3_margin = input.int(1, 'Margin', minval = 1, group = grp_po3_main, active = enable_po3)
  31. po3_htf_data = input.string('Weekly', 'Use HTF data to generate candles', options = ['Weekly', 'Always', 'Never'], group = grp_po3_main, active = enable_po3)
  32.  
  33. grp_po3_up = "PO3Β° Up Candles"
  34. po3_up_col = input.color(color.new(#83b785, 0), 'Body', inline = 'po3_up', group = grp_po3_up, active = enable_po3)
  35. po3_up_col_wick = input.color(#5f5f5f, 'Wick', inline = 'po3_up', group = grp_po3_up, active = enable_po3)
  36. po3_up_col_border = input.color(#5f5f5f, 'Border', inline = 'po3_up', group = grp_po3_up, active = enable_po3)
  37.  
  38. grp_po3_dn = "PO3Β° Down Candles"
  39. po3_down_col = input.color(color.new(#5f5f5f, 0), 'Body', inline = 'po3_dn', group = grp_po3_dn, active = enable_po3)
  40. po3_down_col_wick = input.color(#5f5f5f, 'Wick', inline = 'po3_dn', group = grp_po3_dn, active = enable_po3)
  41. po3_down_col_border= input.color(#5f5f5f, 'Border', inline = 'po3_dn', group = grp_po3_dn, active = enable_po3)
  42.  
  43. grp_po3_proj = "PO3Β° Projections"
  44. po3_o_col = input.color(color.new(color.black, 10), '', inline = 'po3_o', group = grp_po3_proj, active = enable_po3)
  45. po3_o_style = input.string('Dotted', '', options = ['Solid', 'Dotted', 'Dashed'], inline = 'po3_o', group = grp_po3_proj, active = enable_po3)
  46. po3_o_width = input.int(1, 'Width', minval = 1, inline = 'po3_o', group = grp_po3_proj, active = enable_po3)
  47. po3_o_enabled = input.bool(true, 'Open', inline = 'po3_o', group = grp_po3_proj, active = enable_po3)
  48. po3_hl_col = input.color(color.new(color.black, 10), '', inline = 'po3_hl', group = grp_po3_proj, active = enable_po3)
  49. po3_hl_style = input.string('Dotted', '', options = ['Solid', 'Dotted', 'Dashed'], inline = 'po3_hl', group = grp_po3_proj, active = enable_po3)
  50. po3_hl_width = input.int(1, 'Width', minval = 1, inline = 'po3_hl', group = grp_po3_proj, active = enable_po3)
  51. po3_hl_enabled = input.bool(true, 'High/Low', inline = 'po3_hl', group = grp_po3_proj, active = enable_po3)
  52. po3_ohlc_col = input.color(color.new(color.black, 10), '', inline = 'po3_ohlc', group = grp_po3_proj, active = enable_po3)
  53. po3_ohlc_size = input.string('Small', '', options = ['Auto', 'Tiny', 'Small', 'Normal', 'Large', 'Huge'], inline = 'po3_ohlc', group = grp_po3_proj, active = enable_po3)
  54. po3_ohlc_enabled = input.bool(false, 'OHLC Prices', inline = 'po3_ohlc', group = grp_po3_proj, active = enable_po3)
  55.  
  56. grp_po3_time = "PO3Β° Time & Date Labels"
  57. po3_show_timelbl = input.bool(true, "Show Candle Time/Date Labels?", group = grp_po3_time, active = enable_po3)
  58. po3_timelbl_col = input.color(color.new(#1a1a1a, 0), "Text Color", inline = "po3_tl", group = grp_po3_time, active = enable_po3)
  59. po3_timelbl_size = input.string("Small", "Size", options = ["Tiny", "Small", "Normal", "Large"], inline = "po3_tl", group = grp_po3_time, active = enable_po3)
  60.  
  61. grpsmt = "SMT SETTINGS"
  62. autoSMT = input.bool(true, "Auto Detect SMT Pair", group=grpsmt)
  63. smtHistory = input.int(1, "SMT History Limit", group=grpsmt, minval=1, maxval=50, tooltip="Number of recent SMT lines to keep visible on the chart.")
  64. smtPair = input.symbol("ES1!", "Manual Pair 1", group=grpsmt, inline="smt1")
  65. inverse1 = input.bool(false, "Inverse?", group=grpsmt, inline="smt1")
  66. useSmtPair2 = input.bool(false, "2nd SMT Pair", group=grpsmt, inline="smt2")
  67. smtPair2 = input.symbol("YM1!", "", group=grpsmt, inline="smt2", active=useSmtPair2)
  68. inverse2 = input.bool(false, "Inverse?", group=grpsmt, inline="smt2", active=useSmtPair2)
  69.  
  70. grpmdl = "MODEL SETTINGS"
  71. labelSize = input.string("Small", "Label Size", group=grpmdl, options=["Tiny","Small","Normal","Large"])
  72. fvgCol = input.color(color.new(#787b86, 90), "FVG ", group=grpmdl, inline="fvg")
  73. showCE = input.bool(false, "CE ", group=grpmdl, inline="ce")
  74. ceColor = input.color(color.new(#787b86, 60), "", group=grpmdl, inline="ce", active=showCE)
  75. ceStyle = input.string("Solid", "", group=grpmdl, inline="ce", options=["Solid","Dashed","Dotted"], active=showCE)
  76. ceWidth = input.int(1, "", group=grpmdl, inline="ce", options=[1,2,3,4], active=showCE)
  77.  
  78. showInvFVG = input.bool(true, "Show Inversion FVGs?", group=grpmdl)
  79. bullInvBoxCol = input.color(color.new(#0068bd, 85), "Bullish iFVG Box", group=grpmdl, inline="ifvg_bull", active=showInvFVG)
  80. bullInvTxtCol = input.color(#0068bd, "Txt", group=grpmdl, inline="ifvg_bull", active=showInvFVG)
  81. bearInvBoxCol = input.color(color.new(#bd0000, 85), "Bearish iFVG Box", group=grpmdl, inline="ifvg_bear", active=showInvFVG)
  82. bearInvTxtCol = input.color(#bd0000, "Txt", group=grpmdl, inline="ifvg_bear", active=showInvFVG)
  83. erlColor = input.color(color.new(color.black, 0), "ERL ", group=grpmdl, inline="erl")
  84. erlStyle = input.string("Solid", "", group=grpmdl, inline="erl", options=["Solid","Dashed","Dotted"])
  85. erlWidth = input.int(1, "", group=grpmdl, inline="erl", options=[1,2,3,4])
  86. sweepLineCol = input.color(#1a1a1a, "Sweep ", group=grpmdl, inline="swp")
  87. sweepStyle = input.string("Dotted", "", group=grpmdl, inline="swp", options=["Solid","Dashed","Dotted"])
  88. sweepWidth = input.int(1, "", group=grpmdl, inline="swp", options=[1,2,3,4])
  89. smtColor = input.color(color.new(#000000, 0), "SMT ", group=grpmdl, inline="smt")
  90. smtLineStyle = input.string("Dotted", "", group=grpmdl, inline="smt", options=["Solid","Dashed","Dotted"])
  91. smtWidth = input.int(1, "", group=grpmdl, inline="smt", options=[1,2,3,4])
  92. bullOBColor = input.color(#0068bd, "OrderBlock", group=grpmdl, inline="ob")
  93. bearOBColor = input.color(#bd0000, "", group=grpmdl, inline="ob")
  94. obStyle = input.string("Solid", "", group=grpmdl, inline="ob", options=["Solid","Dashed","Dotted"])
  95. obWidth = input.int(1, "", group=grpmdl, inline="ob", options=[1,2,3,4])
  96.  
  97. grpTF = "TIME FILTER"
  98. enableTimeFilter = input.bool(true, "Enable Time Filter?", group=grpTF)
  99. useCustomTimezone = input.bool(false, "Custom Timezone?", group=grpTF, inline="tz", active=enableTimeFilter)
  100. timezoneHours = input.int(-4, "UTC", group=grpTF, inline="tz", minval=-12, maxval=14, active=useCustomTimezone)
  101. timezoneMinutes = input.int(0, "", group=grpTF, inline="tz", minval=0, maxval=59, active=useCustomTimezone)
  102. enableFilter1 = input.bool(true, "Filter 1", group=grpTF, inline="f1", active=enableTimeFilter)
  103. filter1Session = input.session("0200-0500", "", group=grpTF, inline="f1", active=enableFilter1)
  104. enableFilter2 = input.bool(true, "Filter 2", group=grpTF, inline="f2", active=enableTimeFilter)
  105. filter2Session = input.session("0800-1100", "", group=grpTF, inline="f2", active=enableFilter2)
  106. enableFilter3 = input.bool(true, "Filter 3", group=grpTF, inline="f3", active=enableTimeFilter)
  107. filter3Session = input.session("1330-1615", "", group=grpTF, inline="f3", active=enableFilter3)
  108. enableFilter4 = input.bool(true, "Filter 4", group=grpTF, inline="f4", active=enableTimeFilter)
  109. filter4Session = input.session("1800-2100", "", group=grpTF, inline="f4", active=enableFilter4)
  110.  
  111. grpbacktest = "BACKTEST MARKERS"
  112. showInvalid = input.bool(true, "", group=grpbacktest, inline="invalid")
  113. bullInvalidCol = input.color(color.new(#ff5252, 0), "Invalidation", group=grpbacktest, inline="invalid", active=showInvalid)
  114. bearInvalidCol = input.color(color.new(#ff5252, 0), "", group=grpbacktest, inline="invalid", active=showInvalid)
  115. invalidShape = input.string("x", "", group=grpbacktest, inline="invalid", active=showInvalid, options=["x","+","β—†"], tooltip="Marker shape for SL invalidation")
  116. showTargetMark = input.bool(true, "", group=grpbacktest, inline="target")
  117. bullTargetCol = input.color(color.new(#00a113, 0), "Target", group=grpbacktest, inline="target", active=showTargetMark)
  118. bearTargetCol = input.color(color.new(#00a113, 0), "", group=grpbacktest, inline="target", active=showTargetMark)
  119. targetShape = input.string("β—†", "", group=grpbacktest, inline="target", active=showTargetMark, options=["x","+","β—†"], tooltip="Marker shape for target hit")
  120. showNofill = input.bool(true, "", group=grpbacktest, inline="nofill")
  121. bullNofillCol = input.color(color.new(#ea9023, 0), "No Fill", group=grpbacktest, inline="nofill", active=showNofill)
  122. bearNofillCol = input.color(color.new(#ea9023, 0), "", group=grpbacktest, inline="nofill", active=showNofill)
  123. nofillShape = input.string("β—†", "", group=grpbacktest, inline="nofill", active=showNofill, options=["x","+","β—†"], tooltip="Marker shape for no-fill outcome")
  124. showERLMarker = input.bool(true, "", group=grpbacktest, inline="erl_mark")
  125. bullERLCol = input.color(color.new(#00a113, 0), "ERL", group=grpbacktest, inline="erl_mark", active=showERLMarker)
  126. bearERLCol = input.color(color.new(#00a113, 0), "", group=grpbacktest, inline="erl_mark", active=showERLMarker)
  127. erlShape = input.string("+", "", group=grpbacktest, inline="erl_mark", active=showERLMarker, options=["x","+","β—†"], tooltip="Marker shape for ERL hit")
  128.  
  129. grp_qt_main = "QUARTERLY THEORY"
  130. enable_qt = input.bool(true, "Enable Quarterly Theory Cycles?", group=grp_qt_main)
  131. qt_mdl1 = "Free"
  132. qt_mdl2 = "Daye's Theory"
  133. qt_mdl3 = "Zeussy's Theory"
  134. qt_mdl = input.string(qt_mdl1, "Selection Model for Daily Cycle", options=[qt_mdl1, qt_mdl2, qt_mdl3], group=grp_qt_main, active=enable_qt)
  135.  
  136. grp_qt_f = "Model Settings"
  137. qt_tz = input.string('GMT-4', '[Timezone]', options=['GMT-11', 'GMT-10', 'GMT-9', 'GMT-8', 'GMT-7', 'GMT-6', 'GMT-5', 'GMT-4', 'GMT-3', 'GMT-2', 'GMT-1', 'GMT', 'GMT+1', 'GMT+2', 'GMT+3', 'GMT+4', 'GMT+5', 'GMT+5:30', 'GMT+6', 'GMT+7', 'GMT+8', 'GMT+9', 'GMT+10', 'GMT+11', 'GMT+12'], group=grp_qt_f, active=enable_qt)
  138. qt_start_h = input.int(18, '[Start Hour]', group=grp_qt_f, inline='qt_t0', active=enable_qt)
  139. qt_start_m = input.int(0, '[Minute]', group=grp_qt_f, inline='qt_t0', active=enable_qt)
  140. qt_free_day = input.int(360,"[Duration of Daily Cycle (Minute)]", group=grp_qt_f, active=enable_qt)
  141. qt_X_ = input.int(4, '[Division Coefficient (X)]', minval=2, group=grp_qt_f, active=enable_qt)
  142.  
  143. grp_qt_disp = "Display & Color Settings"
  144. qt_history = input.int(4, "History (Max Boxes)", minval=1, maxval=50, group=grp_qt_disp, tooltip="Number of QT boxes to keep visible on the chart. e.g. 3 keeps only the last 3 boxes.", active=enable_qt)
  145. qt_divi_show = input.bool(false, '[Divider]', inline='qt_d1', group=grp_qt_disp, active=enable_qt)
  146. qt_divi_clr = input.color(color.new(color.navy, 80), "", inline='qt_d1', group=grp_qt_disp, active=enable_qt)
  147. qt_show_b = input.bool(true, '[Box]', inline='qt_y1', group=grp_qt_disp, active=enable_qt)
  148. qt_show_l = input.bool(false, '[Line]', inline='qt_y1', group=grp_qt_disp, active=enable_qt)
  149. qt_show_lbl = input.bool(false, '[Label]', inline='qt_y1', group=grp_qt_disp, active=enable_qt)
  150. qt_use_nm = input.bool(false, '[Numeric Labeling]', group=grp_qt_disp, active=enable_qt)
  151. qt_width = input.int(0, '[Border Width]', inline='qt_y3', group=grp_qt_disp, active=enable_qt)
  152. qt_style = input.string('Dashed', 'Type', options=['Solid', 'Dashed', 'Dotted'], inline='qt_y3', group=grp_qt_disp, active=enable_qt)
  153.  
  154. grp_qt_col = "Cycle Colors"
  155. qt_q1_clr = input.color(color.gray, "[Q1/W1/A Box]", inline="qt_c1", group=grp_qt_col, active=enable_qt)
  156. qt_q2_clr = input.color(color.red, "[Q2/W2/M Box]", inline="qt_c1", group=grp_qt_col, active=enable_qt)
  157. qt_q3_clr = input.color(color.teal, "[Q3/W3/D Box]", inline="qt_c2", group=grp_qt_col, active=enable_qt)
  158. qt_q4_clr = input.color(color.blue, "[Q4/W4/X Box]", inline="qt_c2", group=grp_qt_col, active=enable_qt)
  159. qt_contrast = input.int(95, '[Background Contrast]', minval=2, maxval=100, group=grp_qt_col, inline="qt_c3", active=enable_qt)
  160. qt_contrast2 = input.int(50, '[Border Contrast]', minval=2, maxval=100, group=grp_qt_col, inline="qt_c3", active=enable_qt)
  161. qt_show_lower = input.bool(false, "[Lower Cycle]", group=grp_qt_col, active=enable_qt)
  162.  
  163. grpi = "INFO TABLE / DASHBOARD"
  164. boolTable = input.bool(true, "Show Info Table?", group=grpi, inline="d1")
  165. dashboardSize = input.string("Small", "Text Size", group=grpi, inline="d1", options=["Tiny", "Small", "Normal", "Large", "Huge"])
  166. tableloc1 = input.string("Top", "Table Location", group=grpi, inline="d2", options=["Top","Middle","Bottom"])
  167. tableloc2 = input.string("Right", "", group=grpi, inline="d2", options=["Left","Centre","Right"])
  168. dashboardBgColor = input.color(color.new(color.gray, 90), "Background Color", group=grpi)
  169. dashboardBorderColor = input.color(color.new(#1a1a1a, 0), "Border Color", group=grpi)
  170. dashboardTextColor = input.color(color.new(#1a1a1a, 0), "Text Color", group=grpi)
  171. dashboardBorderWidth = input.int(2, "Border Width", group=grpi, minval=0, maxval=5)
  172. dashboardFrameColor = input.color(color.new(#1a1a1a, 0), "Frame Color", group=grpi)
  173. dashboardFrameWidth = input.int(2, "Frame Width", group=grpi, minval=0, maxval=5)
  174. alignmentInfo = input.bool(true, "Timeframe Alignment",group=grpi, inline="gen")
  175. biasInfo = input.bool(true, "Bias", group=grpi, inline="gen")
  176. timeInfo = input.bool(true, "Time Filter", group=grpi, inline="gen1")
  177. dateInfo = input.bool(true, "Date", group=grpi, inline="gen1")
  178.  
  179. f_autoSmtPair(string t) =>
  180. switch t
  181. "ES1!" => "NQ1!"
  182. "NQ1!" => "ES1!"
  183. "GC1!" => "SI1!"
  184. "SI1!" => "GC1!"
  185. "CL1!" => "RB1!"
  186. "RB1!" => "CL1!"
  187. "6E1!" => "6B1!"
  188. "6B1!" => "6E1!"
  189. "6A1!" => "6N1!"
  190. "6N1!" => "6A1!"
  191. "BTC1!" => "ETH1!"
  192. "ETH1!" => "BTC1!"
  193. "BTCUSD" => "ETHUSD"
  194. "ETHUSD" => "BTCUSD"
  195. "BTCUSDT" => "ETHUSDT"
  196. "ETHUSDT" => "BTCUSDT"
  197. "USDJPY" => "DXY"
  198. "USDCHF" => "DXY"
  199. "USDCAD" => "DXY"
  200. "DXY" => "USDJPY"
  201. "EURUSD" => "GBPUSD"
  202. "GBPUSD" => "EURUSD"
  203. "AUDUSD" => "NZDUSD"
  204. "NZDUSD" => "AUDUSD"
  205. "AUDCAD" => "NZDCAD"
  206. "NZDCAD" => "AUDCAD"
  207. "EURCAD" => "GBPCAD"
  208. "GBPCAD" => "EURCAD"
  209. "EURAUD" => "GBPAUD"
  210. "GBPAUD" => "EURAUD"
  211. "EURNZD" => "GBPNZD"
  212. "GBPNZD" => "EURNZD"
  213. "EURJPY" => "GBPJPY"
  214. "GBPJPY" => "EURJPY"
  215. "AUDJPY" => "NZDJPY"
  216. "NZDJPY" => "AUDJPY"
  217. "XAUUSD" => "XAGUSD"
  218. "XAGUSD" => "XAUUSD"
  219. => na
  220.  
  221. string _autoResult = f_autoSmtPair(syminfo.ticker)
  222. bool _smtAutoFound = autoSMT and not na(_autoResult)
  223. string resolvedSmtPair = _smtAutoFound ? _autoResult : smtPair
  224.  
  225. resolvedHTF = switch modelType
  226. "Custom" => customHTF
  227. "1m-15m" => "15"
  228. "3m-30m" => "30"
  229. "5m-1H" => "60"
  230. "15m-4H" => "240"
  231. "1H-1D" => "1D"
  232. "4H-1W" => "1W"
  233. "1D-1W" => "1W"
  234. "6H-15m" => "360"
  235. "90M-5m" => "90"
  236. => timeframe.period == "1" ? "15" : timeframe.period == "3" ? "30" : timeframe.period == "5" ? "60" :
  237. timeframe.period == "15" ? "240" : timeframe.period == "60" ? "1D" : "1W"
  238.  
  239. resolvedLTF = switch modelType
  240. "Custom" => customLTF
  241. "1m-15m" => "1"
  242. "3m-30m" => "3"
  243. "5m-1H" => "5"
  244. "15m-4H" => "15"
  245. "1H-1D" => "60"
  246. "4H-1W" => "240"
  247. "1D-1W" => "1D"
  248. "6H-15m" => "15"
  249. "90M-5m" => "5"
  250. => timeframe.period
  251.  
  252. validTF = timeframe.in_seconds(resolvedHTF) >= timeframe.in_seconds()
  253. cspacer = timeframe.in_seconds() * 1000
  254. htfMsec = timeframe.in_seconds(resolvedHTF) * 1000
  255.  
  256. const int MAX_FVGS = 50
  257. const color NO_COLOR = color.new(color.white, 100)
  258.  
  259. ls(string s) => s == "Dashed" ? line.style_dashed : s == "Dotted" ? line.style_dotted : line.style_solid
  260. lsz(string s) => s == "Tiny" ? size.tiny : s == "Normal" ? size.normal : s == "Large" ? size.large : size.small
  261.  
  262. simple string _ceStyleStr = ceStyle
  263. simple string _erlStyleStr = erlStyle
  264. simple string _sweepStyleStr = sweepStyle
  265. simple string _smtStyleStr = smtLineStyle
  266. simple string _obStyleStr = obStyle
  267. simple string _labelSzStr = labelSize
  268.  
  269. f_cleanTicker(string sym) =>
  270. parts = str.split(sym, ":")
  271. parts.get(parts.size() - 1)
  272.  
  273. f_tfLabel(string tf) =>
  274. string res = tf
  275. if tf == "1D"
  276. res := "1D"
  277. else if tf == "1W"
  278. res := "1W"
  279. else
  280. float mins = str.tonumber(tf)
  281. if not na(mins)
  282. if mins < 60
  283. res := str.tostring(int(mins)) + "m"
  284. else if mins % 60 == 0
  285. res := str.tostring(int(mins / 60)) + "H"
  286. else
  287. res := str.tostring(mins) + "m"
  288. res
  289.  
  290. f_tablePosH(string v, string h) =>
  291. switch h
  292. "Left" => v == "Top" ? position.top_left : v == "Middle" ? position.middle_left : position.bottom_left
  293. "Centre" => v == "Top" ? position.top_center : v == "Middle" ? position.middle_center : position.bottom_center
  294. => v == "Top" ? position.top_right : v == "Middle" ? position.middle_right : position.bottom_right
  295.  
  296. f_timeFilterLabel() =>
  297. if not enableTimeFilter
  298. ""
  299. else
  300. array<string> sessions = array.new_string()
  301. if enableFilter1 and str.length(str.trim(filter1Session)) > 0
  302. sessions.push(str.trim(filter1Session))
  303. if enableFilter2 and str.length(str.trim(filter2Session)) > 0
  304. sessions.push(str.trim(filter2Session))
  305. if enableFilter3 and str.length(str.trim(filter3Session)) > 0
  306. sessions.push(str.trim(filter3Session))
  307. if enableFilter4 and str.length(str.trim(filter4Session)) > 0
  308. sessions.push(str.trim(filter4Session))
  309. sessions.size() > 0 ? sessions.join(" | ") : ""
  310.  
  311. f_dashTz() =>
  312. if useCustomTimezone
  313. string sign = timezoneHours >= 0 ? "+" : "-"
  314. string hh = str.tostring(math.abs(timezoneHours))
  315. string mm = timezoneMinutes < 10 ? "0" + str.tostring(timezoneMinutes) : str.tostring(timezoneMinutes)
  316. "UTC" + sign + hh + (timezoneMinutes != 0 ? ":" + mm : "")
  317. else
  318. syminfo.timezone
  319.  
  320. f_inSession(string sess) =>
  321. not na(time(timeframe.period, sess, f_dashTz()))
  322.  
  323. f_timeFilterActive() =>
  324. if not enableTimeFilter
  325. true
  326. else
  327. bool any = false
  328. if enableFilter1 and str.length(str.trim(filter1Session)) > 0 and f_inSession(filter1Session)
  329. any := true
  330. if enableFilter2 and str.length(str.trim(filter2Session)) > 0 and f_inSession(filter2Session)
  331. any := true
  332. if enableFilter3 and str.length(str.trim(filter3Session)) > 0 and f_inSession(filter3Session)
  333. any := true
  334. if enableFilter4 and str.length(str.trim(filter4Session)) > 0 and f_inSession(filter4Session)
  335. any := true
  336. any
  337.  
  338. var string s1Ticker = na
  339. var string s2Ticker = na
  340.  
  341. var float[] obProjections = array.new<float>()
  342. var float _maxProj = na
  343.  
  344. if barstate.isfirst
  345. s1Ticker := f_cleanTicker(resolvedSmtPair)
  346. s2Ticker := f_cleanTicker(smtPair2)
  347. for part in str.split(str.replace_all(obProjInput, " ", ""), ",")
  348. v = str.tonumber(part)
  349. if not na(v)
  350. obProjections.push(v)
  351. if obProjections.size() > 0
  352. _maxProj := obProjections.get(0)
  353. for k = 1 to obProjections.size() - 1
  354. _maxProj := math.max(_maxProj, obProjections.get(k))
  355.  
  356. htfPivotH() =>
  357. var float v = na
  358. p = ta.pivothigh(high, 1, 1)
  359. if not na(p)
  360. v := p
  361. v
  362.  
  363. htfPivotL() =>
  364. var float v = na
  365. p = ta.pivotlow(low, 1, 1)
  366. if not na(p)
  367. v := p
  368. v
  369.  
  370. findPrice(float price, int t0, bool useHigh) =>
  371. int result = t0
  372. int span = (time - t0) / cspacer
  373. if span > 0 and span < 5000
  374. for j = 0 to span
  375. if (useHigh ? high[j] : low[j]) == price
  376. result := time[j]
  377. break
  378. result
  379.  
  380. f_smtFindPrice(float price, int t0, bool useHigh) =>
  381. int result = t0
  382. int span = math.min((time - t0) / cspacer, 500)
  383. if span > 0
  384. for j = 0 to span
  385. int lt = time[j]
  386. if lt < t0
  387. break
  388. float p = useHigh ? high[j] : low[j]
  389. if lt < t0 + htfMsec and p == price
  390. result := lt
  391. break
  392. result
  393.  
  394. f_findExtremeBar(float price, int t0, bool useHigh) =>
  395. int result = t0
  396. int span = math.min((time - t0) / cspacer, 5000)
  397. if span > 0
  398. for j = span to 0
  399. int lt = time[j]
  400. if lt >= t0
  401. float p = useHigh ? high[j] : low[j]
  402. if p == price
  403. result := lt
  404. break
  405. result
  406.  
  407. type SmtPair
  408. float anchorH
  409. float anchorL
  410. float bucketH
  411. float bucketL
  412. bool foundBull
  413. bool foundBear
  414. line lineBull
  415. line lineBear
  416. label labelBull
  417. label labelBear
  418. string ticker
  419. int smtBullBar
  420. int smtBearBar
  421.  
  422. type AnchorState
  423. int startTime
  424. float anchorH
  425. float anchorL
  426. int bucket
  427. float bucketH
  428. float bucketL
  429. float exH
  430. float exL
  431. SmtPair p1
  432. SmtPair p2
  433.  
  434. type SwingPivot
  435. float price
  436. int barTime
  437.  
  438. type PivotTier
  439. SwingPivot[] st
  440. SwingPivot[] it
  441. SwingPivot[] lt
  442.  
  443. type AnchorPivot
  444. float price
  445. int barTime
  446. bool swept
  447.  
  448. type InversionFVG
  449. int left
  450. float top
  451. int right
  452. float bot
  453. float mid
  454. int dir
  455. int state
  456. int creationBar
  457. int inversionBar
  458. box invBox
  459. label invLabel
  460. bool mitigated
  461. int mitigationTime
  462.  
  463. type OrderBlock
  464. float openPrice
  465. int barTime
  466. float pivotPrice
  467. int pivotTime
  468. float scHigh
  469. float scLow
  470. line obLine
  471. line sweepLine
  472. label obLabel
  473. line[] projLines
  474. label[] projLabels
  475. float slPrice
  476. bool active
  477. float targetPrice
  478. bool targetHit
  479. bool filled
  480. float erlPrice
  481. line erlLine
  482. label erlLabel
  483. bool erlHit
  484. bool frozen
  485. InversionFVG[] iFVGs
  486.  
  487. type FVG
  488. box bx
  489. line mid
  490. label lbl
  491. float hi
  492. float lo
  493. bool bull
  494. bool mitigated
  495. float erlLvl
  496. float pivotLvl
  497. int linkId
  498. AnchorState[] anchors
  499. PivotTier pivotH
  500. PivotTier pivotL
  501. AnchorPivot[] stHighAnc
  502. AnchorPivot[] itHighAnc
  503. AnchorPivot[] ltHighAnc
  504. AnchorPivot[] stLowAnc
  505. AnchorPivot[] itLowAnc
  506. AnchorPivot[] ltLowAnc
  507. OrderBlock[] pendingBullOB
  508. OrderBlock[] pendingBearOB
  509. OrderBlock[] confirmedBullOB
  510. OrderBlock[] confirmedBearOB
  511. bool done
  512. bool fvgFrozen
  513. bool smtAlerted
  514. bool obAlerted
  515.  
  516. type EntryRecord
  517. OrderBlock ob
  518. int obBarTime
  519.  
  520. var EntryRecord[] frozenEntries = array.new<EntryRecord>()
  521.  
  522. type Candle
  523. box body
  524. line upperWick
  525. line lowerWick
  526. line o
  527. line h
  528. line l
  529. label labelO
  530. label labelH
  531. label labelL
  532. label labelC
  533. label labelTime
  534. int cTime
  535.  
  536. type CycleLayer
  537. box[] boxes
  538. label[] labels
  539. float o
  540. float h
  541. float l
  542. float c
  543. int t
  544. int limit
  545. int b_width
  546. string b_style
  547. bool show_box
  548. bool show_line
  549. bool show_label
  550.  
  551. f_deleteEntryPlots(OrderBlock ob) =>
  552. if not na(ob.obLine)
  553. ob.obLine.delete()
  554. ob.obLine := na
  555. if not na(ob.sweepLine)
  556. ob.sweepLine.delete()
  557. ob.sweepLine := na
  558. if not na(ob.obLabel)
  559. ob.obLabel.delete()
  560. ob.obLabel := na
  561. if not na(ob.erlLine)
  562. ob.erlLine.delete()
  563. ob.erlLine := na
  564. if not na(ob.erlLabel)
  565. ob.erlLabel.delete()
  566. ob.erlLabel := na
  567. if ob.projLines.size() > 0
  568. for ln in ob.projLines
  569. ln.delete()
  570. ob.projLines.clear()
  571. if ob.projLabels.size() > 0
  572. for lb in ob.projLabels
  573. lb.delete()
  574. ob.projLabels.clear()
  575. if not na(ob.iFVGs) and ob.iFVGs.size() > 0
  576. for inv in ob.iFVGs
  577. if not na(inv.invBox)
  578. inv.invBox.delete()
  579. if not na(inv.invLabel)
  580. inv.invLabel.delete()
  581. ob.iFVGs.clear()
  582.  
  583. f_grayOutOB(OrderBlock ob) =>
  584. if not na(ob.sweepLine)
  585. ob.sweepLine.delete()
  586. ob.sweepLine := na
  587. if ob.projLines.size() > 0
  588. for ln in ob.projLines
  589. ln.delete()
  590. ob.projLines.clear()
  591. if ob.projLabels.size() > 0
  592. for lb in ob.projLabels
  593. lb.delete()
  594. ob.projLabels.clear()
  595. if not na(ob.obLine)
  596. line.set_color(ob.obLine, color.gray)
  597. line.set_width(ob.obLine, 1)
  598. if not na(ob.obLabel)
  599. label.set_textcolor(ob.obLabel, color.gray)
  600. if not na(ob.erlLine)
  601. line.set_color(ob.erlLine, color.new(color.gray, 60))
  602. if not na(ob.erlLabel)
  603. label.set_textcolor(ob.erlLabel, color.gray)
  604. if not na(ob.iFVGs) and ob.iFVGs.size() > 0
  605. for inv in ob.iFVGs
  606. if not na(inv.invBox)
  607. box.set_bgcolor(inv.invBox, color.new(color.gray, 92))
  608. if not na(inv.invLabel)
  609. label.set_textcolor(inv.invLabel, color.gray)
  610.  
  611. var InversionFVG[] g_bullFVGArray = array.new<InversionFVG>()
  612. var InversionFVG[] g_bearFVGArray = array.new<InversionFVG>()
  613. var InversionFVG[] g_bullInvArray = array.new<InversionFVG>()
  614. var InversionFVG[] g_bearInvArray = array.new<InversionFVG>()
  615.  
  616. fvgManage(InversionFVG[] fvgArray, InversionFVG[] invArray) =>
  617. if fvgArray.size() >= 100
  618. fvgArray.shift()
  619. if fvgArray.size() > 0
  620. float cTop = math.max(open, close)
  621. float cBot = math.min(open, close)
  622. for k = fvgArray.size() - 1 to 0
  623. fvg = fvgArray.get(k)
  624. if fvg.dir == 1 and cBot < fvg.bot
  625. fvg.inversionBar := bar_index
  626. fvg.right := time
  627. invArray.push(fvgArray.remove(k))
  628. else if fvg.dir == -1 and cTop > fvg.top
  629. fvg.inversionBar := bar_index
  630. fvg.right := time
  631. invArray.push(fvgArray.remove(k))
  632.  
  633. invManage(InversionFVG[] invArray) =>
  634. float cTop = math.max(open, close)
  635. float cBot = math.min(open, close)
  636. if invArray.size() >= 100
  637. invArray.shift()
  638. if invArray.size() > 0
  639. for k = invArray.size() - 1 to 0
  640. inv = invArray.get(k)
  641. if inv.state == 0
  642. inv.state := 1
  643. inv.dir := inv.dir == 1 ? -1 : 1
  644. if inv.state >= 1
  645. inv.right := time
  646. bool isMitigated = inv.dir == -1 ? cTop > inv.top : cBot < inv.bot
  647. if isMitigated
  648. inv.mitigated := true
  649. invArray.remove(k)
  650.  
  651. findInversionFVGs(bool isBullSetup, int pivotBar, int confBar, float obPrice) =>
  652. InversionFVG[] found = array.new<InversionFVG>()
  653. InversionFVG[] src = isBullSetup ? g_bullInvArray : g_bearInvArray
  654. if src.size() > 0
  655. for k = 0 to src.size() - 1
  656. inv = src.get(k)
  657. if not inv.mitigated and not na(inv.creationBar) and not na(inv.inversionBar)
  658. if inv.creationBar >= pivotBar and inv.inversionBar <= confBar
  659. bool validLocation = isBullSetup ? (inv.top <= obPrice or inv.mid <= obPrice) : (inv.bot >= obPrice or inv.mid >= obPrice)
  660. if validLocation
  661. bool exists = false
  662. if found.size() > 0
  663. for ex in found
  664. if math.abs(ex.top - inv.top) < syminfo.mintick and math.abs(ex.bot - inv.bot) < syminfo.mintick
  665. exists := true
  666. break
  667. if not exists
  668. InversionFVG copyInv = InversionFVG.new(
  669. inv.left, inv.top, inv.right, inv.bot, inv.mid,
  670. inv.dir, inv.state, inv.creationBar, inv.inversionBar,
  671. na, na, false, na)
  672. found.push(copyInv)
  673. found
  674.  
  675. f_registerFrozenEntry(OrderBlock ob) =>
  676. frozenEntries.push(EntryRecord.new(ob, ob.barTime))
  677. int n = frozenEntries.size()
  678. if n > 1
  679. for a = n - 1 to 1
  680. ea = frozenEntries.get(a)
  681. eb = frozenEntries.get(a - 1)
  682. if ea.obBarTime < eb.obBarTime
  683. frozenEntries.set(a, eb)
  684. frozenEntries.set(a - 1, ea)
  685. else
  686. break
  687. while frozenEntries.size() > showHistory
  688. evicted = frozenEntries.get(0)
  689. f_deleteEntryPlots(evicted.ob)
  690. frozenEntries.remove(0)
  691.  
  692. f_removeFrozenEntry(int obBarTime) =>
  693. if frozenEntries.size() > 0
  694. for k = frozenEntries.size() - 1 to 0
  695. if frozenEntries.get(k).obBarTime == obBarTime
  696. frozenEntries.remove(k)
  697. break
  698.  
  699. var bool plotBullSL = false
  700. var bool plotBearSL = false
  701. var bool plotBullTarget = false
  702. var bool plotBearTarget = false
  703. var bool plotBullNofill = false
  704. var bool plotBearNofill = false
  705. var bool plotBullERL = false
  706. var bool plotBearERL = false
  707.  
  708. var bool fireSMTFVG = false
  709. var bool fireModelActive = false
  710. var bool fireProjHit = false
  711. var bool fireERLHit = false
  712. var string alertSmtMsg = ""
  713. var string alertObMsg = ""
  714. var string alertProjMsg = ""
  715. var string alertErlMsg = ""
  716.  
  717. f_drawSmtLine(bool isBull, float anchorP, float currentP, int anchorT, int currentT) =>
  718. int x1 = f_smtFindPrice(anchorP, anchorT, not isBull)
  719. int x2 = f_findExtremeBar(currentP, currentT, not isBull)
  720. line.new(x1, anchorP, x2, currentP, xloc=xloc.bar_time, color=smtColor, width=smtWidth, style=ls(_smtStyleStr))
  721.  
  722. f_drawSmtLabel(bool isBull, line ln, string txt) =>
  723. int lx = line.get_x1(ln) + int((line.get_x2(ln) - line.get_x1(ln)) / 2)
  724. float ly = (line.get_y1(ln) + line.get_y2(ln)) / 2
  725. label.new(lx, ly, txt,
  726. xloc=xloc.bar_time,
  727. style=isBull ? label.style_label_up : label.style_label_down,
  728. color=NO_COLOR, textcolor=smtColor, size=lsz(_labelSzStr),
  729. text_font_family=font.family_monospace)
  730.  
  731. f_updateSmtLine(bool isBull, float currentP, int currentT, line ln) =>
  732. int x2 = f_findExtremeBar(currentP, currentT, not isBull)
  733. line.set_x2(ln, x2)
  734. line.set_y2(ln, currentP)
  735.  
  736. f_linesMatch(line a, line b) =>
  737. na(a) or na(b) ? false :
  738. line.get_x1(a) == line.get_x1(b) and line.get_y1(a) == line.get_y1(b) and
  739. line.get_x2(a) == line.get_x2(b) and line.get_y2(a) == line.get_y2(b)
  740.  
  741. var line[] activeSmtLines = array.new<line>()
  742. var label[] activeSmtLabels = array.new<label>()
  743.  
  744. f_drawPair(SmtPair p, bool isBull, float anchorP, float extremeP, int anchorT, int currentT) =>
  745. ln = f_drawSmtLine(isBull, anchorP, extremeP, anchorT, currentT)
  746. lbl = f_drawSmtLabel(isBull, ln, p.ticker)
  747. array.push(activeSmtLines, ln)
  748. array.push(activeSmtLabels, lbl)
  749. while array.size(activeSmtLines) > smtHistory
  750. line oldLn = array.shift(activeSmtLines)
  751. label oldLbl = array.shift(activeSmtLabels)
  752. if not na(oldLn)
  753. oldLn.delete()
  754. if not na(oldLbl)
  755. oldLbl.delete()
  756. if isBull
  757. p.lineBull := ln
  758. p.labelBull := lbl
  759. p.foundBull := true
  760. p.smtBullBar := bar_index
  761. else
  762. p.lineBear := ln
  763. p.labelBear := lbl
  764. p.foundBear := true
  765. p.smtBearBar := bar_index
  766.  
  767. f_syncLabels(bool isBull, SmtPair p1, SmtPair p2, string combinedTxt) =>
  768. line ln1 = isBull ? p1.lineBull : p1.lineBear
  769. line ln2 = isBull ? p2.lineBull : p2.lineBear
  770. label _ret = na
  771. if not na(ln1) and not na(ln2)
  772. merged = f_linesMatch(ln1, ln2)
  773. line.set_color(ln2, merged ? NO_COLOR : smtColor)
  774. lbl1 = isBull ? p1.labelBull : p1.labelBear
  775. lbl2 = isBull ? p2.labelBull : p2.labelBear
  776. if not na(lbl1)
  777. lbl1.delete()
  778. if not na(lbl2)
  779. lbl2.delete()
  780. newLbl1 = f_drawSmtLabel(isBull, ln1, merged ? combinedTxt : p1.ticker)
  781. newLbl2 = merged ? na : f_drawSmtLabel(isBull, ln2, p2.ticker)
  782. if isBull
  783. p1.labelBull := newLbl1
  784. p2.labelBull := newLbl2
  785. p2.smtBullBar := merged ? p1.smtBullBar : p2.smtBullBar
  786. else
  787. p1.labelBear := newLbl1
  788. p2.labelBear := newLbl2
  789. p2.smtBearBar := merged ? p1.smtBearBar : p2.smtBearBar
  790. _ret := newLbl1
  791. else if na(ln1) and not na(ln2)
  792. lbl2 = isBull ? p2.labelBull : p2.labelBear
  793. if not na(lbl2)
  794. lbl2.delete()
  795. newLbl2 = f_drawSmtLabel(isBull, ln2, p2.ticker)
  796. if isBull
  797. p2.labelBull := newLbl2
  798. else
  799. p2.labelBear := newLbl2
  800. _ret := newLbl2
  801. _ret
  802.  
  803. f_deleteSmtPairLine(SmtPair p, bool isBull) =>
  804. ln = isBull ? p.lineBull : p.lineBear
  805. lbl = isBull ? p.labelBull : p.labelBear
  806. if not na(ln)
  807. ln.delete()
  808. if isBull
  809. p.lineBull := na
  810. else
  811. p.lineBear := na
  812. if not na(lbl)
  813. lbl.delete()
  814. if isBull
  815. p.labelBull := na
  816. else
  817. p.labelBear := na
  818.  
  819. f_resolveBestSmt(SmtPair p1, SmtPair p2, bool isBull) =>
  820. line ln1 = isBull ? p1.lineBull : p1.lineBear
  821. line ln2 = isBull ? p2.lineBull : p2.lineBear
  822. int bar1 = isBull ? p1.smtBullBar : p1.smtBearBar
  823. int bar2 = isBull ? p2.smtBullBar : p2.smtBearBar
  824. bool found1 = isBull ? p1.foundBull : p1.foundBear
  825. bool found2 = isBull ? p2.foundBull : p2.foundBear
  826. float y2_1 = not na(ln1) ? line.get_y2(ln1) : float(na)
  827. float y2_2 = not na(ln2) ? line.get_y2(ln2) : float(na)
  828. bool merged = useSmtPair2 and found1 and found2 and not na(ln1) and not na(ln2) and f_linesMatch(ln1, ln2)
  829. int winBar = na
  830. line winLine = na
  831. float winY2 = float(na)
  832. if merged
  833. winBar := bar1
  834. winLine := ln1
  835. winY2 := y2_1
  836. else if useSmtPair2 and found1 and found2 and not na(ln1) and not na(ln2)
  837. bool p1wins = isBull ? y2_1 < y2_2 : y2_1 > y2_2
  838. if p1wins
  839. winBar := bar1
  840. winLine := ln1
  841. winY2 := y2_1
  842. ln2.delete()
  843. lbl2 = isBull ? p2.labelBull : p2.labelBear
  844. if not na(lbl2)
  845. lbl2.delete()
  846. else
  847. winBar := bar2
  848. winLine := ln2
  849. winY2 := y2_2
  850. ln1.delete()
  851. lbl1 = isBull ? p1.labelBull : p1.labelBear
  852. if not na(lbl1)
  853. lbl1.delete()
  854. else if found1 and not na(ln1)
  855. winBar := bar1
  856. winLine := ln1
  857. winY2 := y2_1
  858. else if useSmtPair2 and found2 and not na(ln2)
  859. winBar := bar2
  860. winLine := ln2
  861. winY2 := y2_2
  862. [winBar, winLine, winY2]
  863.  
  864. f_promoteSwingLevel(SwingPivot[] src, SwingPivot[] dst, bool isHigh) =>
  865. if src.size() > 2
  866. float y1 = src.get(src.size() - 1).price
  867. float y2 = src.get(src.size() - 2).price
  868. float y3 = src.get(src.size() - 3).price
  869. if isHigh ? (y1 < y2 and y2 > y3) : (y1 > y2 and y2 < y3)
  870. cand = src.get(src.size() - 2)
  871. if dst.size() == 0 or dst.last().price != cand.price
  872. dst.push(SwingPivot.new(cand.price, cand.barTime))
  873. src.remove(src.size() - 2)
  874.  
  875. f_promoteAnc(AnchorPivot[] src, AnchorPivot[] dst, int barTime) =>
  876. if src.size() > 0
  877. for k = src.size() - 1 to 0
  878. anc = src.get(k)
  879. if anc.barTime == barTime and not anc.swept
  880. src.remove(k)
  881. dst.push(AnchorPivot.new(anc.price, anc.barTime, false))
  882. break
  883.  
  884. f_ictSwing(PivotTier tier,
  885. AnchorPivot[] stAnc, AnchorPivot[] itAnc, AnchorPivot[] ltAnc,
  886. bool isHigh, int hBars, int lBars) =>
  887. float price = isHigh ? high[1] : low[1]
  888. if (isHigh ? hBars : lBars) == -1
  889. tier.st.push(SwingPivot.new(price, time[1]))
  890. stAnc.push(AnchorPivot.new(price, time[1], false))
  891. f_promoteSwingLevel(tier.st, tier.it, isHigh)
  892. f_promoteSwingLevel(tier.it, tier.lt, isHigh)
  893. if tier.st.size() > 2
  894. sp = tier.st.get(tier.st.size() - 2)
  895. if tier.it.size() > 0 and tier.it.last().barTime == sp.barTime
  896. f_promoteAnc(stAnc, itAnc, sp.barTime)
  897. if tier.it.size() > 2
  898. sp = tier.it.get(tier.it.size() - 2)
  899. if tier.lt.size() > 0 and tier.lt.last().barTime == sp.barTime
  900. f_promoteAnc(itAnc, ltAnc, sp.barTime)
  901.  
  902. f_cleanTier(AnchorPivot[] anchors, bool isBull) =>
  903. if anchors.size() > 0
  904. for j = anchors.size() - 1 to 0
  905. anc = anchors.get(j)
  906. if not anc.swept and (isBull ? low < anc.price : high > anc.price)
  907. anc.swept := true
  908. if anc.swept
  909. anchors.remove(j)
  910.  
  911. f_sweepTier(AnchorPivot[] anchors, OrderBlock[] pending, bool isBull) =>
  912. int bestIdx = -1
  913. float bestPrice = na
  914. int bestBar = na
  915. if anchors.size() > 0
  916. for i = anchors.size() - 1 to 0
  917. anc = anchors.get(i)
  918. bool hit = isBull ? low < anc.price : high > anc.price
  919. if not anc.swept and hit
  920. anc.swept := true
  921. if bestIdx == -1 or (isBull ? anc.price < bestPrice : anc.price > bestPrice)
  922. bestIdx := i, bestPrice := anc.price, bestBar := anc.barTime
  923. if anc.swept
  924. anchors.remove(i)
  925. if bestIdx != -1
  926. float candr = high - low
  927. bool ok = candr > 0 and math.abs(close - open) * 100 / candr >= 50 and (isBull ? close < open : close > open)
  928. if ok
  929. pending.push(OrderBlock.new(open, time, bestPrice, bestBar, high, low,
  930. na, na, na,
  931. array.new<line>(), array.new<label>(),
  932. float(na), true,
  933. float(na), false,
  934. false,
  935. float(na), na, na, false, false,
  936. array.new<InversionFVG>()))
  937. bestIdx
  938.  
  939. f_processSweeps(AnchorPivot[] ltAnc, AnchorPivot[] itAnc, AnchorPivot[] stAnc,
  940. OrderBlock[] pending, bool isBull) =>
  941. if f_sweepTier(ltAnc, pending, isBull) != -1
  942. f_cleanTier(itAnc, isBull)
  943. f_cleanTier(stAnc, isBull)
  944. else if f_sweepTier(itAnc, pending, isBull) != -1
  945. f_cleanTier(stAnc, isBull)
  946. else
  947. f_sweepTier(stAnc, pending, isBull)
  948. bool(na)
  949.  
  950. f_resolveObSL(bool isBull, float smtLineY2, float scH, float scL) =>
  951. bool useSMT = obSLCalc == "SMT Based Invalidation" or (obSLCalc == "Automatic" and timeframe.in_seconds(timeframe.period) < timeframe.in_seconds("60"))
  952. useSMT ? smtLineY2 : (isBull ? scL : scH)
  953.  
  954. method deleteOB(OrderBlock self) =>
  955. f_deleteEntryPlots(self)
  956.  
  957. f_hasActiveOB(OrderBlock[] obs) =>
  958. bool found = false
  959. if obs.size() > 0
  960. for ob in obs
  961. if ob.active and not ob.targetHit and not ob.frozen
  962. found := true
  963. break
  964. found
  965.  
  966. f_confirm(OrderBlock[] pending, OrderBlock[] confirmed, bool isBull, int winBar, line winLine, float winY2,
  967. float erlLvlSnap, int t1Snap, int t2Snap,
  968. SmtPair pa1, SmtPair pa2, SmtPair pb1, SmtPair pb2, SmtPair pc1, SmtPair pc2) =>
  969. if pending.size() > 0
  970. bool plotted = false
  971. for i = 0 to pending.size() - 1
  972. ob = pending.get(i)
  973. bool confirmedBar = time > ob.barTime and (isBull ? close[1] > ob.openPrice : close[1] < ob.openPrice)
  974. bool wouldConfirm = confirmedBar and not na(winBar) and bar_index > winBar
  975. if wouldConfirm and not plotted and f_timeFilterActive()
  976. plotted := true
  977. color obColor = isBull ? bullOBColor : bearOBColor
  978. int obRightTime = time + cspacer * 2
  979. ob.sweepLine := line.new(ob.pivotTime, ob.pivotPrice, ob.barTime, ob.pivotPrice,
  980. xloc=xloc.bar_time, color=sweepLineCol, width=sweepWidth, style=ls(_sweepStyleStr))
  981. ob.obLine := line.new(ob.barTime, ob.openPrice, obRightTime, ob.openPrice,
  982. xloc=xloc.bar_time, color=obColor, width=obWidth, style=ls(_obStyleStr))
  983. ob.obLabel := label.new(obRightTime, ob.openPrice, isBull ? "+ OB" : "- OB",
  984. xloc=xloc.bar_time, style=label.style_label_left,
  985. color=NO_COLOR, textcolor=obColor, size=size.small,
  986. text_font_family=font.family_monospace)
  987. float sl = f_resolveObSL(isBull, winY2, ob.scHigh, ob.scLow)
  988. ob.slPrice := sl
  989. ob.active := true
  990. ob.frozen := false
  991. ob.filled := (projCalc == "Confirmation Close")
  992. if obProjBool and obProjections.size() > 0 and not na(sl)
  993. float basePrice = projCalc == "Confirmation Close" ? close[1] : ob.openPrice
  994. float risk = math.abs(basePrice - sl)
  995. ob.targetPrice := isBull ? basePrice + risk * _maxProj : basePrice - risk * _maxProj
  996. for dv in obProjections
  997. float pp = isBull ? basePrice + risk * dv : basePrice - risk * dv
  998. pln = line.new(ob.barTime, pp, ob.barTime + cspacer * 2, pp,
  999. xloc=xloc.bar_time, color=obColor, width=1)
  1000. plb = label.new(ob.barTime + cspacer, pp, "+" + str.tostring(dv, "#.#"),
  1001. xloc=xloc.bar_time,
  1002. style=isBull ? label.style_label_down : label.style_label_up,
  1003. color=NO_COLOR, textcolor=obColor, size=size.small,
  1004. text_font_family=font.family_monospace)
  1005. ob.projLines.push(pln)
  1006. ob.projLabels.push(plb)
  1007. if isBull
  1008. pa1.smtBullBar := na, pa2.smtBullBar := na
  1009. pb1.smtBullBar := na, pb2.smtBullBar := na
  1010. pc1.smtBullBar := na, pc2.smtBullBar := na
  1011. else
  1012. pa1.smtBearBar := na, pa2.smtBearBar := na
  1013. pb1.smtBearBar := na, pb2.smtBearBar := na
  1014. pc1.smtBearBar := na, pc2.smtBearBar := na
  1015. ob.erlPrice := erlLvlSnap
  1016. if not na(erlLvlSnap)
  1017. int erlX = isBull ? findPrice(erlLvlSnap, t1Snap, true) : findPrice(erlLvlSnap, t1Snap, false)
  1018. if erlX == t1Snap
  1019. erlX := isBull ? findPrice(erlLvlSnap, t2Snap, true) : findPrice(erlLvlSnap, t2Snap, false)
  1020. ob.erlLine := line.new(erlX, erlLvlSnap, time + cspacer * 2, erlLvlSnap,
  1021. xloc=xloc.bar_time, color=erlColor, width=erlWidth, style=ls(_erlStyleStr))
  1022. ob.erlLabel := label.new(erlX, erlLvlSnap, "ERL",
  1023. xloc=xloc.bar_time,
  1024. style=isBull ? label.style_label_lower_right : label.style_label_upper_right,
  1025. color=NO_COLOR, textcolor=erlColor, size=lsz(_labelSzStr),
  1026. text_font_family=font.family_monospace)
  1027. if showInvFVG
  1028. int pOffset = math.max(0, bar_index - int((time - ob.barTime) / cspacer))
  1029. ob.iFVGs := findInversionFVGs(isBull, pOffset, bar_index, ob.openPrice)
  1030. if ob.iFVGs.size() > 0
  1031. int ifvgEndTime = time + cspacer * 4
  1032. color currentBoxCol = isBull ? bullInvBoxCol : bearInvBoxCol
  1033. color currentTxtCol = isBull ? bullInvTxtCol : bearInvTxtCol
  1034. for inv in ob.iFVGs
  1035. inv.invBox := box.new(inv.left, inv.top, ifvgEndTime, inv.bot,
  1036. xloc=xloc.bar_time, bgcolor=currentBoxCol, border_color=NO_COLOR)
  1037. inv.invLabel := label.new(ifvgEndTime, inv.mid, isBull ? "iFVG+" : "iFVG-",
  1038. xloc=xloc.bar_time,
  1039. style=label.style_label_left,
  1040. color=NO_COLOR, textcolor=currentTxtCol, size=lsz(_labelSzStr),
  1041. text_font_family=font.family_monospace)
  1042. confirmed.push(ob)
  1043. if plotted
  1044. for j = pending.size() - 1 to 0
  1045. ob = pending.get(j)
  1046. if ob.active
  1047. pending.remove(j)
  1048. else
  1049. for i = pending.size() - 1 to 0
  1050. ob = pending.get(i)
  1051. bool brokeThrough = time > ob.barTime and (isBull ? close[1] > ob.openPrice : close[1] < ob.openPrice)
  1052. bool wouldConfirmI = brokeThrough and not na(winBar) and bar_index > winBar
  1053. if brokeThrough and not wouldConfirmI
  1054. pending.remove(i)
  1055.  
  1056. f_extendOBLines(OrderBlock[] obs) =>
  1057. for ob in obs
  1058. if not ob.frozen
  1059. if not na(ob.obLine) and not ob.targetHit
  1060. bool shouldExtend = projCalc == "Confirmation Close" or not ob.filled
  1061. if shouldExtend
  1062. int rightEdge = time + cspacer * 2
  1063. line.set_x2(ob.obLine, rightEdge)
  1064. if not na(ob.obLabel)
  1065. label.set_x(ob.obLabel, rightEdge)
  1066. if not na(ob.erlLine) and not ob.erlHit
  1067. line.set_x2(ob.erlLine, time + cspacer * 2)
  1068.  
  1069. f_checkOBInvalidation(OrderBlock[] obs, bool isBull) =>
  1070. bool triggered = false
  1071. if obs.size() > 0
  1072. for j = obs.size() - 1 to 0
  1073. ob = obs.get(j)
  1074. if ob.active and not ob.targetHit and not ob.frozen and not na(ob.slPrice)
  1075. bool invalidated = isBull ? low < ob.slPrice : high > ob.slPrice
  1076. if invalidated
  1077. ob.active := false
  1078. ob.frozen := true
  1079. if discardInvalid
  1080. ob.deleteOB()
  1081. f_removeFrozenEntry(ob.barTime)
  1082. obs.remove(j)
  1083. else
  1084. f_grayOutOB(ob)
  1085. f_registerFrozenEntry(ob)
  1086. triggered := true
  1087. triggered
  1088.  
  1089. f_checkOBFillAndTarget(OrderBlock[] obs, bool isBull) =>
  1090. bool tgtTriggered = false
  1091. bool nofillTriggered = false
  1092. if obs.size() > 0
  1093. for j = obs.size() - 1 to 0
  1094. ob = obs.get(j)
  1095. if ob.active and not ob.targetHit and not ob.frozen
  1096. if not ob.filled
  1097. bool fillHit = isBull ? low <= ob.openPrice : high >= ob.openPrice
  1098. if fillHit
  1099. ob.filled := true
  1100. if not na(ob.targetPrice)
  1101. bool tgtHit = isBull ? high >= ob.targetPrice : low <= ob.targetPrice
  1102. if tgtHit
  1103. ob.targetHit := true
  1104. ob.active := false
  1105. ob.frozen := true
  1106. f_registerFrozenEntry(ob)
  1107. if ob.filled
  1108. tgtTriggered := true
  1109. else
  1110. nofillTriggered := true
  1111. [tgtTriggered, nofillTriggered]
  1112.  
  1113. f_checkOBERL(OrderBlock[] obs, bool isBull) =>
  1114. bool triggered = false
  1115. if obs.size() > 0
  1116. for j = obs.size() - 1 to 0
  1117. ob = obs.get(j)
  1118. if not ob.erlHit and not na(ob.erlPrice) and not ob.frozen
  1119. bool erlHitNow = isBull ? high >= ob.erlPrice : low <= ob.erlPrice
  1120. if erlHitNow
  1121. ob.erlHit := true
  1122. if not na(ob.erlLine)
  1123. line.set_x2(ob.erlLine, time)
  1124. triggered := true
  1125. triggered
  1126.  
  1127. method deleteAnchor(AnchorState self) =>
  1128. if not na(self.p1.lineBull)
  1129. self.p1.lineBull.delete()
  1130. if not na(self.p1.lineBear)
  1131. self.p1.lineBear.delete()
  1132. if not na(self.p1.labelBull)
  1133. self.p1.labelBull.delete()
  1134. if not na(self.p1.labelBear)
  1135. self.p1.labelBear.delete()
  1136. if not na(self.p2.lineBull)
  1137. self.p2.lineBull.delete()
  1138. if not na(self.p2.lineBear)
  1139. self.p2.lineBear.delete()
  1140. if not na(self.p2.labelBull)
  1141. self.p2.labelBull.delete()
  1142. if not na(self.p2.labelBear)
  1143. self.p2.labelBear.delete()
  1144.  
  1145. f_inv1H(float h, float l) => inverse1 ? 1.0 / l : h
  1146. f_inv1L(float h, float l) => inverse1 ? 1.0 / h : l
  1147. f_inv2H(float h, float l) => inverse2 ? 1.0 / l : h
  1148. f_inv2L(float h, float l) => inverse2 ? 1.0 / h : l
  1149.  
  1150. f_processAnchor(AnchorState a, bool isBull, float curH, float curL, float s1H, float s1L, float s2H, float s2L) =>
  1151. if time >= a.startTime and not na(a.anchorH)
  1152. string combinedTicker = s1Ticker + "+" + s2Ticker
  1153. int currentBucket = math.floor((time - a.startTime) / htfMsec) * htfMsec + a.startTime
  1154. if na(a.bucket) or currentBucket != a.bucket
  1155. a.bucket := currentBucket
  1156. a.bucketH := curH
  1157. a.bucketL := curL
  1158. a.p1.bucketH := s1H
  1159. a.p1.bucketL := s1L
  1160. a.p2.bucketH := s2H
  1161. a.p2.bucketL := s2L
  1162. else
  1163. if curH > a.bucketH
  1164. a.bucketH := curH
  1165. if curL < a.bucketL
  1166. a.bucketL := curL
  1167. a.p1.bucketH := math.max(a.p1.bucketH, s1H)
  1168. a.p1.bucketL := math.min(a.p1.bucketL, s1L)
  1169. a.p2.bucketH := math.max(a.p2.bucketH, s2H)
  1170. a.p2.bucketL := math.min(a.p2.bucketL, s2L)
  1171. if isBull
  1172. if not na(a.p1.anchorL)
  1173. if not a.p1.foundBull and (a.bucketL - a.anchorL) * (a.p1.bucketL - a.p1.anchorL) < 0
  1174. f_drawPair(a.p1, true, a.anchorL, a.bucketL, a.startTime, a.bucket)
  1175. if useSmtPair2 and not na(a.p2.anchorL)
  1176. if not a.p2.foundBull and (a.bucketL - a.anchorL) * (a.p2.bucketL - a.p2.anchorL) < 0
  1177. f_drawPair(a.p2, true, a.anchorL, a.bucketL, a.startTime, a.bucket)
  1178. f_syncLabels(true, a.p1, a.p2, combinedTicker)
  1179. else
  1180. if not na(a.p1.anchorH)
  1181. if not a.p1.foundBear and (a.bucketH - a.anchorH) * (a.p1.bucketH - a.p1.anchorH) < 0
  1182. f_drawPair(a.p1, false, a.anchorH, a.bucketH, a.startTime, a.bucket)
  1183. if useSmtPair2 and not na(a.p2.anchorH)
  1184. if not a.p2.foundBear and (a.bucketH - a.anchorH) * (a.p2.bucketH - a.p2.anchorH) < 0
  1185. f_drawPair(a.p2, false, a.anchorH, a.bucketH, a.startTime, a.bucket)
  1186. f_syncLabels(false, a.p1, a.p2, combinedTicker)
  1187. if a.p1.foundBull or a.p1.foundBear or (useSmtPair2 and (a.p2.foundBull or a.p2.foundBear))
  1188. if na(a.exH)
  1189. a.exH := high
  1190. a.exL := low
  1191. else
  1192. if high > a.exH
  1193. a.exH := high
  1194. if not isBull
  1195. if not na(a.p1.lineBear)
  1196. if (a.exH - a.anchorH) * (s1H - a.p1.anchorH) < 0
  1197. f_updateSmtLine(false, a.exH, currentBucket, a.p1.lineBear)
  1198. a.p1.smtBearBar := bar_index
  1199. if useSmtPair2 and a.p2.foundBear
  1200. f_syncLabels(false, a.p1, a.p2, combinedTicker)
  1201. else
  1202. if not na(a.p1.labelBear)
  1203. a.p1.labelBear.delete()
  1204. a.p1.labelBear := f_drawSmtLabel(false, a.p1.lineBear, a.p1.ticker)
  1205. else
  1206. a.p1.smtBearBar := na
  1207. if useSmtPair2 and not na(a.p2.lineBear)
  1208. if (a.exH - a.anchorH) * (s2H - a.p2.anchorH) < 0
  1209. f_updateSmtLine(false, a.exH, currentBucket, a.p2.lineBear)
  1210. a.p2.smtBearBar := bar_index
  1211. f_syncLabels(false, a.p1, a.p2, combinedTicker)
  1212. else
  1213. a.p2.smtBearBar := na
  1214. if low < a.exL
  1215. a.exL := low
  1216. if isBull
  1217. if not na(a.p1.lineBull)
  1218. if (a.exL - a.anchorL) * (s1L - a.p1.anchorL) < 0
  1219. f_updateSmtLine(true, a.exL, currentBucket, a.p1.lineBull)
  1220. a.p1.smtBullBar := bar_index
  1221. if useSmtPair2 and a.p2.foundBull
  1222. f_syncLabels(true, a.p1, a.p2, combinedTicker)
  1223. else
  1224. if not na(a.p1.labelBull)
  1225. a.p1.labelBull.delete()
  1226. a.p1.labelBull := f_drawSmtLabel(true, a.p1.lineBull, a.p1.ticker)
  1227. else
  1228. a.p1.smtBullBar := na
  1229. if useSmtPair2 and not na(a.p2.lineBull)
  1230. if (a.exL - a.anchorL) * (s2L - a.p2.anchorL) < 0
  1231. f_updateSmtLine(true, a.exL, currentBucket, a.p2.lineBull)
  1232. a.p2.smtBullBar := bar_index
  1233. f_syncLabels(true, a.p1, a.p2, combinedTicker)
  1234. else
  1235. a.p2.smtBullBar := na
  1236. float(na)
  1237.  
  1238. f_crossAnchorResolve(FVG f, bool isBull) =>
  1239. [wBar0, wLine0, wY2_0] = f_resolveBestSmt(f.anchors.get(0).p1, f.anchors.get(0).p2, isBull)
  1240. [wBar1, wLine1, wY2_1] = f_resolveBestSmt(f.anchors.get(1).p1, f.anchors.get(1).p2, isBull)
  1241. [wBar2, wLine2, wY2_2] = f_resolveBestSmt(f.anchors.get(2).p1, f.anchors.get(2).p2, isBull)
  1242. float best = na
  1243. if not na(wY2_0)
  1244. best := wY2_0
  1245. if not na(wY2_1)
  1246. best := na(best) ? wY2_1 : (isBull ? math.min(best, wY2_1) : math.max(best, wY2_1))
  1247. if not na(wY2_2)
  1248. best := na(best) ? wY2_2 : (isBull ? math.min(best, wY2_2) : math.max(best, wY2_2))
  1249. bool keep0 = not na(wY2_0) and not na(best) and (isBull ? wY2_0 <= best : wY2_0 >= best)
  1250. bool keep1 = not na(wY2_1) and not na(best) and (isBull ? wY2_1 <= best : wY2_1 >= best)
  1251. bool keep2 = not na(wY2_2) and not na(best) and (isBull ? wY2_2 <= best : wY2_2 >= best)
  1252. if not keep0
  1253. f_deleteSmtPairLine(f.anchors.get(0).p1, isBull)
  1254. f_deleteSmtPairLine(f.anchors.get(0).p2, isBull)
  1255. if not keep1
  1256. f_deleteSmtPairLine(f.anchors.get(1).p1, isBull)
  1257. f_deleteSmtPairLine(f.anchors.get(1).p2, isBull)
  1258. if not keep2
  1259. f_deleteSmtPairLine(f.anchors.get(2).p1, isBull)
  1260. f_deleteSmtPairLine(f.anchors.get(2).p2, isBull)
  1261. int winBar = na
  1262. line winLine = na
  1263. float winY2 = float(na)
  1264. if keep0
  1265. winBar := wBar0, winLine := wLine0, winY2 := wY2_0
  1266. if keep1 and (na(winBar) or (isBull ? wY2_1 <= winY2 : wY2_1 >= winY2))
  1267. winBar := wBar1, winLine := wLine1, winY2 := wY2_1
  1268. if keep2 and (na(winBar) or (isBull ? wY2_2 <= winY2 : wY2_2 >= winY2))
  1269. winBar := wBar2, winLine := wLine2, winY2 := wY2_2
  1270. [winBar, winLine, winY2]
  1271.  
  1272. method delete(FVG self) =>
  1273. self.bx.delete()
  1274. self.mid.delete()
  1275. self.lbl.delete()
  1276. for a in self.anchors
  1277. a.deleteAnchor()
  1278. for ob in self.pendingBullOB
  1279. ob.deleteOB()
  1280. for ob in self.pendingBearOB
  1281. ob.deleteOB()
  1282. for ob in self.confirmedBullOB
  1283. ob.deleteOB()
  1284. for ob in self.confirmedBearOB
  1285. ob.deleteOB()
  1286.  
  1287. method removeFVG(FVG[] self, int i) =>
  1288. self.get(i).delete()
  1289. self.remove(i)
  1290.  
  1291. method beyondFVG(FVG self, float c) => self.bull ? c < self.lo : c > self.hi
  1292. method inFVG(FVG self, float h, float l) => self.bull ? l < self.hi : h > self.lo
  1293.  
  1294. [h1, h2, h3, l1, l2, l3, t1, t2, t3, htfClose1, tfTime, htfPH, htfPL] = request.security(syminfo.tickerid, resolvedHTF,
  1295. [high[1], high[2], high[3], low[1], low[2], low[3], time[1], time[2], time[3], close[1], time, htfPivotH(), htfPivotL()],
  1296. lookahead=barmerge.lookahead_on)
  1297.  
  1298. [s1_h1, s1_h2, s1_h3, s1_l1, s1_l2, s1_l3, smt1H_raw, smt1L_raw] = request.security(resolvedSmtPair, resolvedHTF,
  1299. [high[1], high[2], high[3], low[1], low[2], low[3], high, low],
  1300. lookahead=barmerge.lookahead_on)
  1301.  
  1302. float smt1H = f_inv1H(smt1H_raw, smt1L_raw)
  1303. float smt1L = f_inv1L(smt1H_raw, smt1L_raw)
  1304.  
  1305. var float s2_h1 = na, var float s2_h2 = na, var float s2_h3 = na
  1306. var float s2_l1 = na, var float s2_l2 = na, var float s2_l3 = na
  1307. var float smt2H = na, var float smt2L = na
  1308. if useSmtPair2
  1309. [_a, _b, _c, _d, _e, _f, _g, _h] = request.security(smtPair2, resolvedHTF,
  1310. [high[1], high[2], high[3], low[1], low[2], low[3], high, low],
  1311. lookahead=barmerge.lookahead_on)
  1312. s2_h1 := _a, s2_h2 := _b, s2_h3 := _c, s2_l1 := _d, s2_l2 := _e, s2_l3 := _f
  1313. smt2H := f_inv2H(_g, _h)
  1314. smt2L := f_inv2L(_g, _h)
  1315.  
  1316. max_bars_back(high, 1000)
  1317. max_bars_back(low, 1000)
  1318. max_bars_back(time, 1000)
  1319.  
  1320. newHTFBar = ta.change(tfTime) != 0
  1321.  
  1322. var float liveHigh = na, var float liveLow = na
  1323. if newHTFBar
  1324. liveHigh := high, liveLow := low
  1325. else
  1326. if high > liveHigh
  1327. liveHigh := high
  1328. if low < liveLow
  1329. liveLow := low
  1330.  
  1331. int _hBars = ta.highestbars(3)
  1332. int _lBars = ta.lowestbars(3)
  1333.  
  1334. var FVG[] fvgs = array.new<FVG>()
  1335.  
  1336. f_makeAnchorState(int sTime, float aH, float aL, float p1H, float p1L, float p2H, float p2L) =>
  1337. SmtPair p1 = SmtPair.new(p1H, p1L, na, na, false, false, na, na, na, na, s1Ticker, na, na)
  1338. SmtPair p2 = SmtPair.new(p2H, p2L, na, na, false, false, na, na, na, na, s2Ticker, na, na)
  1339. AnchorState.new(sTime, aH, aL, na, na, na, na, na, p1, p2)
  1340.  
  1341. f_makeAnchors() =>
  1342. AnchorState[] anchors = array.new<AnchorState>()
  1343. anchors.push(f_makeAnchorState(int(t1), h1, l1,
  1344. f_inv1H(s1_h1, s1_l1), f_inv1L(s1_h1, s1_l1),
  1345. f_inv2H(s2_h1, s2_l1), f_inv2L(s2_h1, s2_l1)))
  1346. anchors.push(f_makeAnchorState(int(t2), h2, l2,
  1347. f_inv1H(s1_h2, s1_l2), f_inv1L(s1_h2, s1_l2),
  1348. f_inv2H(s2_h2, s2_l2), f_inv2L(s2_h2, s2_l2)))
  1349. anchors.push(f_makeAnchorState(int(t3), h3, l3,
  1350. f_inv1H(s1_h3, s1_l3), f_inv1L(s1_h3, s1_l3),
  1351. f_inv2H(s2_h3, s2_l3), f_inv2L(s2_h3, s2_l3)))
  1352. anchors
  1353.  
  1354. f_seedPivots(AnchorPivot[] stH, AnchorPivot[] stL, int seedFromTime) =>
  1355. int span = math.min((time - seedFromTime) / cspacer, 500)
  1356. if span >= 2
  1357. for j = span - 1 to 1
  1358. int bt = time[j]
  1359. if bt >= seedFromTime
  1360. float h_prev = high[j + 1]
  1361. float h_cur = high[j]
  1362. float h_next = high[j - 1]
  1363. float l_prev = low[j + 1]
  1364. float l_cur = low[j]
  1365. float l_next = low[j - 1]
  1366. if h_cur > h_prev and h_cur > h_next
  1367. stH.push(AnchorPivot.new(h_cur, bt, false))
  1368. if l_cur < l_prev and l_cur < l_next
  1369. stL.push(AnchorPivot.new(l_cur, bt, false))
  1370.  
  1371. pushFVG(bool isBull) =>
  1372. float top = isBull ? l1 : l3
  1373. float bot = isBull ? h3 : h1
  1374. float fmid = (top + bot) / 2
  1375. int ltX = int(t3)
  1376. int rtX = time
  1377. float erl = isBull ? math.max(h1, h2) : math.min(l1, l2)
  1378. float pivLvl = isBull ? (not na(htfPL) and htfPL < bot ? htfPL : float(na))
  1379. : (not na(htfPH) and htfPH > top ? htfPH : float(na))
  1380. bx = box.new(ltX, top, rtX, bot, xloc=xloc.bar_time, bgcolor=fvgCol, border_color=NO_COLOR, border_width=0)
  1381. midLine = line.new(ltX, fmid, rtX, fmid, xloc=xloc.bar_time, color=showCE ? ceColor : NO_COLOR, style=ls(_ceStyleStr), width=ceWidth)
  1382. string fvgTag = (isBull ? "FVG+ " : "FVG- ") + f_tfLabel(resolvedHTF)
  1383. lbl = label.new(rtX, fmid, fvgTag,
  1384. xloc=xloc.bar_time,
  1385. style=label.style_label_right,
  1386. textcolor=color.new(#787b86, 0), color=NO_COLOR, size=lsz(_labelSzStr),
  1387. text_font_family=font.family_monospace)
  1388. PivotTier newPivH = PivotTier.new(array.new<SwingPivot>(), array.new<SwingPivot>(), array.new<SwingPivot>())
  1389. PivotTier newPivL = PivotTier.new(array.new<SwingPivot>(), array.new<SwingPivot>(), array.new<SwingPivot>())
  1390. AnchorPivot[] newStH = array.new<AnchorPivot>()
  1391. AnchorPivot[] newItH = array.new<AnchorPivot>()
  1392. AnchorPivot[] newLtH = array.new<AnchorPivot>()
  1393. AnchorPivot[] newStL = array.new<AnchorPivot>()
  1394. AnchorPivot[] newItL = array.new<AnchorPivot>()
  1395. AnchorPivot[] newLtL = array.new<AnchorPivot>()
  1396. f_seedPivots(newStH, newStL, int(t3))
  1397. fvgs.push(FVG.new(
  1398. bx, midLine, lbl, top, bot, isBull, false, erl, pivLvl, bar_index,
  1399. f_makeAnchors(),
  1400. newPivH, newPivL,
  1401. newStH, newItH, newLtH,
  1402. newStL, newItL, newLtL,
  1403. array.new<OrderBlock>(), array.new<OrderBlock>(),
  1404. array.new<OrderBlock>(), array.new<OrderBlock>(),
  1405. false, false, false, false))
  1406.  
  1407. if validTF and newHTFBar
  1408. if l1 > h3 and (bias == "Neutral" or bias == "Bullish")
  1409. pushFVG(true)
  1410. if h1 < l3 and (bias == "Neutral" or bias == "Bearish")
  1411. pushFVG(false)
  1412.  
  1413. plotBullSL := false
  1414. plotBearSL := false
  1415. plotBullTarget := false
  1416. plotBearTarget := false
  1417. plotBullNofill := false
  1418. plotBearNofill := false
  1419. plotBullERL := false
  1420. plotBearERL := false
  1421.  
  1422. fireSMTFVG := false
  1423. fireModelActive := false
  1424. fireProjHit := false
  1425. fireERLHit := false
  1426. alertSmtMsg := ""
  1427. alertObMsg := ""
  1428. alertProjMsg := ""
  1429. alertErlMsg := ""
  1430.  
  1431. bool _ltfFvgUp = low > high[2] and close[1] > high[2]
  1432. bool _ltfFvgDn = high < low[2] and close[1] < low[2]
  1433. if _ltfFvgUp
  1434. g_bullFVGArray.push(InversionFVG.new(time[1], low, na, high[2], math.avg(low, high[2]), 1, 0, bar_index, na, na, na, false, na))
  1435. if _ltfFvgDn
  1436. g_bearFVGArray.push(InversionFVG.new(time[1], low[2], na, high, math.avg(low[2], high), -1, 0, bar_index, na, na, na, false, na))
  1437.  
  1438. fvgManage(g_bullFVGArray, g_bullInvArray)
  1439. fvgManage(g_bearFVGArray, g_bullInvArray)
  1440. invManage(g_bullInvArray)
  1441. invManage(g_bearInvArray)
  1442.  
  1443. int i = 0
  1444. while i < fvgs.size()
  1445. FVG f = fvgs.get(i)
  1446. bool deleted = false
  1447.  
  1448. bool bullTradeActive = f_hasActiveOB(f.confirmedBullOB)
  1449. bool bearTradeActive = f_hasActiveOB(f.confirmedBearOB)
  1450. bool anyTradeActive = bullTradeActive or bearTradeActive
  1451.  
  1452. if not f.fvgFrozen
  1453. if not f.mitigated
  1454. box.set_right(f.bx, time)
  1455. line.set_x2(f.mid, time)
  1456. label.set_x(f.lbl, time)
  1457.  
  1458. bool fvgBroken = f.bull ? low <= f.lo : high >= f.hi
  1459. if not f.mitigated and fvgBroken
  1460. f.mitigated := true
  1461. box.set_right(f.bx, time)
  1462. line.set_x2(f.mid, time)
  1463. label.set_x(f.lbl, time)
  1464.  
  1465. if newHTFBar and not anyTradeActive
  1466. if f.beyondFVG(htfClose1)
  1467. fvgs.removeFVG(i)
  1468. deleted := true
  1469.  
  1470. if not deleted
  1471. if not anyTradeActive
  1472. if not f.mitigated
  1473. f.erlLvl := f.bull ? math.max(f.erlLvl, liveHigh) : math.min(f.erlLvl, liveLow)
  1474. if not f.mitigated and f.inFVG(liveHigh, liveLow)
  1475. f.mitigated := true
  1476. if f.mitigated and (f.bull ? liveHigh > f.erlLvl : liveLow < f.erlLvl)
  1477. fvgs.removeFVG(i)
  1478. deleted := true
  1479. if not deleted and not na(f.pivotLvl) and (f.bull ? liveLow < f.pivotLvl : liveHigh > f.pivotLvl)
  1480. fvgs.removeFVG(i)
  1481. deleted := true
  1482.  
  1483. if not deleted
  1484. if not f.done
  1485. for a in f.anchors
  1486. f_processAnchor(a, f.bull, high, low, smt1H, smt1L, smt2H, smt2L)
  1487.  
  1488. [wBarBull, wLineBull, wY2Bull] = f_crossAnchorResolve(f, true)
  1489. [wBarBear, wLineBear, wY2Bear] = f_crossAnchorResolve(f, false)
  1490.  
  1491. f_ictSwing(f.pivotH, f.stHighAnc, f.itHighAnc, f.ltHighAnc, true, _hBars, _lBars)
  1492. f_ictSwing(f.pivotL, f.stLowAnc, f.itLowAnc, f.ltLowAnc, false, _hBars, _lBars)
  1493.  
  1494. if f.bull
  1495. f_processSweeps(f.ltLowAnc, f.itLowAnc, f.stLowAnc, f.pendingBullOB, true)
  1496. f_confirm(f.pendingBullOB, f.confirmedBullOB, true, wBarBull, wLineBull, wY2Bull,
  1497. f.erlLvl, f.anchors.get(0).startTime, f.anchors.get(1).startTime,
  1498. f.anchors.get(0).p1, f.anchors.get(0).p2,
  1499. f.anchors.get(1).p1, f.anchors.get(1).p2,
  1500. f.anchors.get(2).p1, f.anchors.get(2).p2)
  1501. else
  1502. f_processSweeps(f.ltHighAnc, f.itHighAnc, f.stHighAnc, f.pendingBearOB, false)
  1503. f_confirm(f.pendingBearOB, f.confirmedBearOB, false, wBarBear, wLineBear, wY2Bear,
  1504. f.erlLvl, f.anchors.get(0).startTime, f.anchors.get(1).startTime,
  1505. f.anchors.get(0).p1, f.anchors.get(0).p2,
  1506. f.anchors.get(1).p1, f.anchors.get(1).p2,
  1507. f.anchors.get(2).p1, f.anchors.get(2).p2)
  1508.  
  1509. f_extendOBLines(f.confirmedBullOB)
  1510. f_extendOBLines(f.confirmedBearOB)
  1511.  
  1512. if f.bull
  1513. [bullTgt, bullNofill] = f_checkOBFillAndTarget(f.confirmedBullOB, true)
  1514. if bullTgt
  1515. f.done := true
  1516. f.fvgFrozen := true
  1517. plotBullTarget := true
  1518. fireProjHit := true
  1519. alertProjMsg := "+ " + f_tfLabel(resolvedLTF) + "-" + f_tfLabel(resolvedHTF) + " Projection Target Hit"
  1520. if bullNofill
  1521. f.done := true
  1522. f.fvgFrozen := true
  1523. plotBullNofill := true
  1524. if f_checkOBERL(f.confirmedBullOB, true)
  1525. plotBullERL := true
  1526. fireERLHit := true
  1527. alertErlMsg := "+ " + f_tfLabel(resolvedLTF) + "-" + f_tfLabel(resolvedHTF) + " External Range Liquidity Hit"
  1528. if not f.fvgFrozen
  1529. if f_checkOBInvalidation(f.confirmedBullOB, true)
  1530. plotBullSL := true
  1531. if not discardInvalid
  1532. f.done := true
  1533. f.fvgFrozen := true
  1534. else
  1535. [bearTgt, bearNofill] = f_checkOBFillAndTarget(f.confirmedBearOB, false)
  1536. if bearTgt
  1537. f.done := true
  1538. f.fvgFrozen := true
  1539. plotBearTarget := true
  1540. fireProjHit := true
  1541. alertProjMsg := "- " + f_tfLabel(resolvedLTF) + "-" + f_tfLabel(resolvedHTF) + " Projection Target Hit"
  1542. if bearNofill
  1543. f.done := true
  1544. f.fvgFrozen := true
  1545. plotBearNofill := true
  1546. if f_checkOBERL(f.confirmedBearOB, false)
  1547. plotBearERL := true
  1548. fireERLHit := true
  1549. alertErlMsg := "- " + f_tfLabel(resolvedLTF) + "-" + f_tfLabel(resolvedHTF) + " External Range Liquidity Hit"
  1550. if not f.fvgFrozen
  1551. if f_checkOBInvalidation(f.confirmedBearOB, false)
  1552. plotBearSL := true
  1553. if not discardInvalid
  1554. f.done := true
  1555. f.fvgFrozen := true
  1556.  
  1557. if not f.smtAlerted and not f.done
  1558. bool smtNowFound = false
  1559. for a in f.anchors
  1560. if (f.bull ? a.p1.foundBull : a.p1.foundBear) or (useSmtPair2 and (f.bull ? a.p2.foundBull : a.p2.foundBear))
  1561. smtNowFound := true
  1562. break
  1563. if smtNowFound
  1564. f.smtAlerted := true
  1565. fireSMTFVG := true
  1566. alertSmtMsg := (f.bull ? "+ " : "- ") + f_tfLabel(resolvedLTF) + " FVG and SMT formed, waiting for Entry"
  1567.  
  1568. if not f.obAlerted
  1569. bool obNowActive = f_hasActiveOB(f.bull ? f.confirmedBullOB : f.confirmedBearOB)
  1570. if obNowActive
  1571. f.obAlerted := true
  1572. fireModelActive := true
  1573. alertObMsg := "FVG + SMT Model Active " + f_tfLabel(resolvedLTF) + "-" + f_tfLabel(resolvedHTF)
  1574.  
  1575. i += 1
  1576.  
  1577. while fvgs.size() > MAX_FVGS
  1578. fvgs.removeFVG(0)
  1579.  
  1580. _shapeInvalid = invalidShape == "x" ? shape.xcross : invalidShape == "+" ? shape.cross : shape.diamond
  1581. _shapeTarget = targetShape == "x" ? shape.xcross : targetShape == "+" ? shape.cross : shape.diamond
  1582. _shapeNofill = nofillShape == "x" ? shape.xcross : nofillShape == "+" ? shape.cross : shape.diamond
  1583. _shapeERL = erlShape == "x" ? shape.xcross : erlShape == "+" ? shape.cross : shape.diamond
  1584.  
  1585. plotshape(showInvalid and plotBullSL, title="Bull SL", style=_shapeInvalid, location=location.belowbar, color=bullInvalidCol, size=size.auto)
  1586. plotshape(showInvalid and plotBearSL, title="Bear SL", style=_shapeInvalid, location=location.abovebar, color=bearInvalidCol, size=size.auto)
  1587. plotshape(showTargetMark and plotBullTarget, title="Bull Target", style=_shapeTarget, location=location.abovebar, color=bullTargetCol, size=size.auto)
  1588. plotshape(showTargetMark and plotBearTarget, title="Bear Target", style=_shapeTarget, location=location.belowbar, color=bearTargetCol, size=size.auto)
  1589. plotshape(showNofill and plotBullNofill, title="Bull No Fill", style=_shapeNofill, location=location.abovebar, color=bullNofillCol, size=size.auto)
  1590. plotshape(showNofill and plotBearNofill, title="Bear No Fill", style=_shapeNofill, location=location.belowbar, color=bearNofillCol, size=size.auto)
  1591. plotshape(showERLMarker and plotBullERL, title="Bull ERL", style=_shapeERL, location=location.abovebar, color=bullERLCol, size=size.auto)
  1592. plotshape(showERLMarker and plotBearERL, title="Bear ERL", style=_shapeERL, location=location.belowbar, color=bearERLCol, size=size.auto)
  1593.  
  1594. if enableAlerts
  1595. if alertSMTFVG and fireSMTFVG and str.length(alertSmtMsg) > 0
  1596. alert(alertSmtMsg, alert.freq_once_per_bar)
  1597. if alertModelActive and fireModelActive and str.length(alertObMsg) > 0
  1598. alert(alertObMsg, alert.freq_once_per_bar)
  1599. if alertProjHit and fireProjHit and str.length(alertProjMsg) > 0
  1600. alert("FVG + SMT " + alertProjMsg, alert.freq_once_per_bar)
  1601. if alertERLHit and fireERLHit and str.length(alertErlMsg) > 0
  1602. alert("FVG + SMT " + alertErlMsg, alert.freq_once_per_bar)
  1603.  
  1604. f_dashSize(string s) =>
  1605. switch s
  1606. "Tiny" => size.tiny
  1607. "Small" => size.small
  1608. "Normal" => size.normal
  1609. "Large" => size.large
  1610. "Huge" => size.huge
  1611. => size.small
  1612.  
  1613. f_tableRow(table t, int row, string txt, color txtColor, color bgColor, string sz) =>
  1614. table.cell(t, 0, row, txt, text_color=txtColor, bgcolor=bgColor, text_size=sz,
  1615. text_halign=text.align_center, text_font_family=font.family_monospace)
  1616. table.cell(t, 1, row, "", text_color=txtColor, bgcolor=bgColor, text_size=sz,
  1617. text_halign=text.align_center, text_font_family=font.family_monospace)
  1618. table.merge_cells(t, 0, row, 1, row)
  1619.  
  1620. f_qt_durLabel(int mins) =>
  1621. string res = na
  1622. if mins >= 1440 and mins % 1440 == 0
  1623. res := str.tostring(int(mins / 1440)) + "D"
  1624. else if mins >= 60 and mins % 60 == 0
  1625. res := str.tostring(int(mins / 60)) + "H"
  1626. else
  1627. res := str.tostring(mins) + "m"
  1628. res
  1629.  
  1630. f_qt_modelLabel(string m) =>
  1631. m == qt_mdl2 ? "Daye's Cycles" : m == qt_mdl3 ? "Zeussy's Cycles" : "Free Cycles"
  1632.  
  1633. var table infoTable = na
  1634. if barstate.islast
  1635. if boolTable
  1636. tfStr = f_timeFilterLabel()
  1637. string p1tag = _smtAutoFound ? " (auto)" : ""
  1638. string p2tag = useSmtPair2 ? " / " + f_cleanTicker(smtPair2) + " (2nd)" : ""
  1639. pairStr = syminfo.ticker + " / " + f_cleanTicker(resolvedSmtPair) + p1tag + p2tag
  1640. bool showWarning = autoSMT and not _smtAutoFound
  1641. string warnMsg = "⚠ No auto SMT for '" + syminfo.ticker + "' β€” using " + f_cleanTicker(smtPair) + " (manual)"
  1642.  
  1643. int qtDurMin = qt_mdl == qt_mdl1 ? qt_free_day : qt_mdl == qt_mdl2 ? 360 : 270
  1644. string qtCycleLbl = f_qt_durLabel(qtDurMin)
  1645. string qtSubLbl = f_qt_durLabel(int(math.max(1, math.round(qtDurMin / float(qt_mdl == qt_mdl1 ? qt_X_ : qt_mdl == qt_mdl2 ? 4 : 3)))))
  1646. string smt1Tag = _smtAutoFound ? " (Auto)" : ""
  1647. string smt2Tag = autoSMT ? " (Auto)" : ""
  1648. string smt2Line = useSmtPair2 ? "\nSMT2: " + f_cleanTicker(smtPair2) + smt2Tag + (inverse2 ? " (Inv)" : "") : ""
  1649. string qtPairStr = "Ticker: " + syminfo.ticker + "\nSMT1: " + f_cleanTicker(resolvedSmtPair) + smt1Tag + smt2Line
  1650. string pairBlock = enable_qt ? qtPairStr : pairStr
  1651.  
  1652. int rowCount = 1
  1653. if biasInfo or alignmentInfo or (timeInfo and str.length(tfStr) > 0)
  1654. rowCount += 1
  1655. if dateInfo
  1656. rowCount += 1
  1657. if enable_qt
  1658. rowCount += 1
  1659. if showWarning
  1660. rowCount += 1
  1661.  
  1662. if na(infoTable)
  1663. infoTable := table.new(f_tablePosH(tableloc1, tableloc2), 2, rowCount,
  1664. bgcolor=dashboardBgColor,
  1665. border_color=dashboardBorderColor,
  1666. border_width=dashboardBorderWidth,
  1667. frame_color=dashboardFrameColor,
  1668. frame_width=dashboardFrameWidth)
  1669.  
  1670. dTextSize = f_dashSize(dashboardSize)
  1671.  
  1672. string titleTxt = alignmentInfo ? "Forever Model (" + f_tfLabel(resolvedLTF) + " - " + f_tfLabel(resolvedHTF) + ")" : "Forever Model"
  1673. f_tableRow(infoTable, 0, titleTxt, dashboardTextColor, dashboardBgColor, dTextSize)
  1674.  
  1675. int currentRow = 1
  1676. if biasInfo or alignmentInfo or (timeInfo and str.length(tfStr) > 0)
  1677. biasColor = bias == "Bullish" ? color.new(#00c853, 0) : bias == "Bearish" ? color.new(#d50000, 0) : dashboardTextColor
  1678. biasLine = biasInfo ? "Bias : " + bias : ""
  1679. timeLine = (timeInfo and str.length(tfStr) > 0) ? tfStr : ""
  1680. combined = biasLine + (biasLine != "" ? "\n\n" : "") + pairBlock + (timeLine != "" ? "\n\n" : "") + timeLine
  1681. f_tableRow(infoTable, currentRow, combined, biasColor, dashboardBgColor, dTextSize)
  1682. currentRow += 1
  1683.  
  1684. if dateInfo
  1685. f_tableRow(infoTable, currentRow, str.format_time(time_close, "dd MMM yyyy", f_dashTz()), dashboardTextColor, dashboardBgColor, dTextSize)
  1686. currentRow += 1
  1687.  
  1688. if enable_qt
  1689. string cycleTxt = "Cycle Mode\n" + f_tfLabel(resolvedLTF) + " Β· " + qtCycleLbl + " SMT setups\n" + f_qt_modelLabel(qt_mdl) + " Β· Q = " + qtSubLbl
  1690. f_tableRow(infoTable, currentRow, cycleTxt, dashboardTextColor, dashboardBgColor, dTextSize)
  1691. currentRow += 1
  1692.  
  1693. if showWarning
  1694. warnBg = color.new(#cc0000, 0)
  1695. warnTxt = color.new(color.white, 0)
  1696. f_tableRow(infoTable, currentRow, warnMsg, warnTxt, warnBg, dTextSize)
  1697.  
  1698. qt_get_style(string s) =>
  1699. s == 'Dashed' ? line.style_dashed : s == 'Dotted' ? line.style_dotted : line.style_solid
  1700.  
  1701. f_qt_get_lbl(string[] arr, int idx, bool extime_check) =>
  1702. if idx >= 1 and idx <= arr.size() and (qt_mdl == qt_mdl3 ? not extime_check : true)
  1703. arr.get(idx - 1)
  1704. else
  1705. ''
  1706.  
  1707. f_qt_update_data(CycleLayer layer, bool is_new, bool tf_vis, bool extime_check) =>
  1708. var float layl0 = na, var float layh0 = na, var float layc0 = na, var float layo0 = na
  1709. var int layt0 = na
  1710. if tf_vis and (qt_mdl == qt_mdl3 ? not extime_check : true)
  1711. if is_new
  1712. layt0 := time
  1713. layo0 := open, layh0 := high, layl0 := low, layc0 := close
  1714. else
  1715. layh0 := math.max(high, layh0)
  1716. layl0 := math.min(low, layl0)
  1717. layc0 := close
  1718. layer.l := layl0, layer.h := layh0, layer.c := layc0, layer.o := layo0, layer.t := layt0
  1719.  
  1720. f_qt_manage_layer(bool cond, bool tf_vis, CycleLayer layer, string id_text, int k, bool extime_check) =>
  1721. sz_ = k == 1 ? size.small : size.tiny
  1722. layer.limit := qt_history
  1723. if cond and tf_vis and (qt_mdl == qt_mdl3 ? not extime_check : true)
  1724. color phase_col = color.gray
  1725. if id_text == 'Q1' or id_text == 'W1' or id_text == 'A' or id_text == '1'
  1726. phase_col := qt_q1_clr
  1727. else if id_text == 'Q2' or id_text == 'W2' or id_text == 'M' or id_text == '2'
  1728. phase_col := qt_q2_clr
  1729. else if id_text == 'Q3' or id_text == 'W3' or id_text == 'D' or id_text == '3'
  1730. phase_col := qt_q3_clr
  1731. else if id_text == 'Q4' or id_text == 'W4' or id_text == 'X' or id_text == 'Fr' or id_text == '4'
  1732. phase_col := qt_q4_clr
  1733.  
  1734. b_c = color.new(phase_col, qt_contrast2)
  1735. bg_c = layer.show_box ? color.new(phase_col, qt_contrast) : color.new(phase_col, 100)
  1736.  
  1737. if layer.show_line and (qt_mdl == qt_mdl3 ? not extime_check : true)
  1738. line.new(bar_index, low, bar_index, high, extend = extend.both, color = color.new(phase_col, 40), style = qt_get_style(layer.b_style))
  1739.  
  1740. if qt_mdl == qt_mdl3 ? not extime_check : true
  1741. nb = box.new(bar_index, high, bar_index, low, border_color = b_c, bgcolor = bg_c, border_width = layer.b_width, border_style = qt_get_style(layer.b_style))
  1742. layer.boxes.push(nb)
  1743. nl = label.new(bar_index, high, xloc=xloc.bar_index, text = layer.show_label ? id_text : '', color = color.new(color.white, 100), textcolor = phase_col, style = label.style_label_down, size = sz_)
  1744. layer.labels.push(nl)
  1745.  
  1746. while layer.boxes.size() > layer.limit
  1747. box.delete(layer.boxes.shift())
  1748. label.delete(layer.labels.shift())
  1749.  
  1750. f_qt_update_visual(bool tf_vis, CycleLayer layer, bool extime_check) =>
  1751. if layer.boxes.size() > 0 and (qt_mdl == qt_mdl3 ? not extime_check : true)
  1752. b = layer.boxes.get(layer.boxes.size() - 1)
  1753. l = layer.labels.get(layer.labels.size() - 1)
  1754. if layer.show_box
  1755. box.set_top(b, layer.h)
  1756. box.set_bottom(b, layer.l)
  1757. box.set_right(b, bar_index)
  1758. label.set_xy(l, math.round(math.avg(box.get_left(b), bar_index)), layer.h)
  1759.  
  1760. var Year_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1761. var Quart_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1762. var Month_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1763. var Week_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1764. var Day_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1765. var Sub_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1766. var Micro_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_b, qt_show_l, qt_show_lbl)
  1767. var Mini_qt = CycleLayer.new(array.new<box>(), array.new<label>(), na, na, na, na, na, qt_history, qt_width, qt_style, qt_show_lower, false, qt_show_lbl)
  1768.  
  1769. var int qt_extdaystart = time
  1770. var line qt_new_line = na
  1771.  
  1772. var qt_lbl_q = array.from('Q1', 'Q2', 'Q3', 'Q4')
  1773. var qt_lbl_w = array.from('W1', 'W2', 'W3', 'W4', 'Gap')
  1774. var qt_lbl_d = array.from('A', 'M', 'D', 'X', 'Fr', 'Sat', 'Sun')
  1775. var qt_lbl_gen = array.from('A', 'M', 'D', 'X')
  1776. var qt_lbl_zeday = array.from('Lo', 'AM', 'PM', '')
  1777. var qt_lbl_nm = array.from('1', '2', '3', '4','Fr', 'Sat', 'Sun')
  1778.  
  1779. if enable_qt
  1780. qt_tf_sec = timeframe.in_seconds(timeframe.period)
  1781. qt_is_min = qt_tf_sec >= 60 and qt_tf_sec < 86400
  1782. qt_is_year = qt_tf_sec == 604800
  1783. qt_is_quart = qt_tf_sec == 86400
  1784. qt_is_mon = qt_is_min and timeframe.multiplier >= 240
  1785. qt_is_week = qt_is_min and timeframe.multiplier >= 60 and timeframe.multiplier <= 120
  1786. qt_is_day = qt_is_min and timeframe.multiplier >= 15 and timeframe.multiplier <= 30
  1787. qt_is_sub = qt_is_min and timeframe.multiplier >= 3 and timeframe.multiplier <= 10
  1788. qt_is_micro = qt_is_min and timeframe.multiplier >= 1 and timeframe.multiplier <= 2
  1789.  
  1790. qt_dur_h = 60 * 60 * 1000
  1791. qt_dur_m = 60 * 1000
  1792. qt_msDay = 24 * 60 * 60 * 1000
  1793.  
  1794. qt_dur_day = qt_mdl == qt_mdl1 ? qt_free_day * qt_dur_m : qt_mdl == qt_mdl2 ? 6 * qt_dur_h : 270 * qt_dur_m
  1795. qt_X = qt_mdl == qt_mdl1 ? qt_X_ : qt_mdl == qt_mdl2 ? 4 : 3
  1796. qt_dur_sub = qt_dur_day / qt_X
  1797. qt_dur_micro = qt_dur_sub / qt_X
  1798. qt_dur_mini = qt_dur_micro / qt_X
  1799.  
  1800. qt_st_h = qt_mdl == qt_mdl1 ? qt_start_h : qt_mdl == qt_mdl2 ? 18 : 2
  1801. qt_st_m = qt_mdl == qt_mdl1 ? qt_start_m : qt_mdl == qt_mdl2 ? 00 : 30
  1802.  
  1803. qt_yy = year(time, qt_tz)
  1804. qt_mo = month(time, qt_tz)
  1805. qt_dom = dayofmonth(time, qt_tz)
  1806.  
  1807. qt_dayStartToday = timestamp(qt_tz, qt_yy, qt_mo, qt_dom, qt_st_h, qt_st_m)
  1808. qt_dayStart = time >= qt_dayStartToday ? qt_dayStartToday : qt_dayStartToday - qt_msDay
  1809.  
  1810. if timeframe.change("1D")
  1811. qt_extdaystart := time
  1812.  
  1813. qt_extimestart = timestamp(qt_tz, qt_yy, qt_mo, qt_dom, 16, 00)
  1814. qt_extimefinish = timestamp(qt_tz, qt_yy, qt_mo, qt_dom, 02, 30)
  1815. qt_extime = time > qt_extimestart or (time >= qt_extdaystart and time < qt_extimefinish)
  1816.  
  1817. qt_yy_c = year(qt_dayStart, qt_tz)
  1818. qt_mo_c = month(qt_dayStart, qt_tz)
  1819. qt_dow_c = dayofweek(qt_dayStart, qt_tz)
  1820.  
  1821. qYear_val = qt_mo_c <= 3 ? 1 : qt_mo_c <= 6 ? 2 : qt_mo_c <= 9 ? 3 : 4
  1822.  
  1823. qs_m_val = math.floor((qt_mo_c - 1) / 3) * 3 + 1
  1824. qs_t_val = timestamp(qt_tz, qt_yy_c, qs_m_val, 1, qt_st_h, 0)
  1825. qe_t_val = timestamp(qt_tz, qt_yy_c, qs_m_val + 3, 1, qt_st_h, 0)
  1826. q_dur_val = qe_t_val - qs_t_val
  1827. q2Month_val = int(math.floor((time - qs_t_val) / q_dur_val * 4)) + 1
  1828. q2Month_val := math.max(1, math.min(4, q2Month_val))
  1829.  
  1830. monday_t_val = qt_dayStart - (qt_dow_c == dayofweek.sunday ? -1 : qt_dow_c - 2) * qt_msDay
  1831. mon_d_val = dayofmonth(monday_t_val, qt_tz)
  1832.  
  1833. dow_1st_val = ((1 - (mon_d_val - 1) % 7 + 7) % 7) + 1
  1834. first_mon_m = dow_1st_val == dayofweek.monday ? 1 :
  1835. dow_1st_val == dayofweek.tuesday ? 7 :
  1836. dow_1st_val == dayofweek.wednesday ? 6 :
  1837. dow_1st_val == dayofweek.thursday ? 5 :
  1838. dow_1st_val == dayofweek.friday ? 4 :
  1839. dow_1st_val == dayofweek.saturday ? 3 : 2
  1840.  
  1841. week_idx_val = math.round((mon_d_val - first_mon_m) / 7)
  1842. qMonth_val = week_idx_val + 1
  1843.  
  1844. qWeek_val = qt_dow_c == dayofweek.sunday ? 1 : qt_dow_c == dayofweek.monday ? 2 : qt_dow_c == dayofweek.tuesday ? 3 : qt_dow_c == dayofweek.wednesday ? 4 : qt_dow_c == dayofweek.thursday ? 5 : qt_dow_c == dayofweek.friday ? 6 : qt_dow_c == dayofweek.saturday ? 7 : 0
  1845.  
  1846. msFromDay_val = (time - qt_dayStart) % qt_msDay
  1847. qDay_val = int(math.floor(msFromDay_val / qt_dur_day)) + 1
  1848. msInmain_val = msFromDay_val % qt_dur_day
  1849. qsub_val = int(math.floor(msInmain_val / qt_dur_sub)) + 1
  1850. msInSub_val = msFromDay_val % qt_dur_sub
  1851. qMicro_val = int(math.max(1, math.min(qt_X, int(math.floor(msInSub_val / qt_dur_micro)) + 1)))
  1852. msInmicro_val = msFromDay_val % qt_dur_micro
  1853. qMini_val = int(math.max(1, math.min(qt_X, int(math.floor(msInmicro_val / qt_dur_mini)) + 1)))
  1854.  
  1855. new_year_qt = nz(ta.change(qYear_val)) != 0
  1856. new_quart_qt = nz(ta.change(q2Month_val)) != 0
  1857. new_month_qt = nz(ta.change(qMonth_val)) != 0
  1858. new_week_qt = nz(ta.change(qWeek_val)) != 0
  1859. new_daily_qt = nz(ta.change(qDay_val)) != 0
  1860. new_sub_qt = nz(ta.change(qsub_val)) != 0
  1861. new_micro_qt = nz(ta.change(qMicro_val)) != 0
  1862. new_mini_qt = nz(ta.change(qMini_val)) != 0
  1863.  
  1864. f_qt_update_data(Year_qt, qt_mdl == qt_mdl3 ? false : new_year_qt, qt_is_year, qt_extime)
  1865. f_qt_update_data(Quart_qt, qt_mdl == qt_mdl3 ? false : new_quart_qt, qt_is_quart or (qt_is_year and qt_show_lower), qt_extime)
  1866. f_qt_update_data(Month_qt, qt_mdl == qt_mdl3 ? false : new_month_qt, qt_is_mon or (qt_is_quart and qt_show_lower), qt_extime)
  1867. f_qt_update_data(Week_qt, qt_mdl == qt_mdl3 ? false : new_week_qt, qt_is_week or (qt_is_mon and qt_show_lower), qt_extime)
  1868. f_qt_update_data(Day_qt, new_daily_qt, qt_is_day or (qt_is_week and qt_show_lower), qt_extime)
  1869. f_qt_update_data(Sub_qt, new_sub_qt or new_daily_qt, qt_is_sub or (qt_is_day and qt_show_lower), qt_extime)
  1870. f_qt_update_data(Micro_qt, new_micro_qt, qt_is_micro or (qt_is_sub and qt_show_lower), qt_extime)
  1871. f_qt_update_data(Mini_qt, new_mini_qt, qt_is_micro and qt_show_lower, qt_extime)
  1872.  
  1873. yearlb_qt = qt_mdl == qt_mdl3 ? "" : f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_q, qYear_val, qt_extime)
  1874. quarlb_qt = qt_mdl == qt_mdl3 ? "" : f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_q, q2Month_val, qt_extime)
  1875. montlb_qt = qt_mdl == qt_mdl3 ? "" : f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_w, qMonth_val, qt_extime)
  1876. weeklb_qt = qt_mdl == qt_mdl3 ? "" : f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_d, qWeek_val, qt_extime)
  1877. daylb_qt = f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : (qt_mdl == qt_mdl3 ? qt_lbl_zeday : qt_lbl_gen), qDay_val, qt_extime)
  1878. sublb_qt = f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_gen, qsub_val, qt_extime)
  1879. miclb_qt = f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_gen, qMicro_val, qt_extime)
  1880. minlb_qt = f_qt_get_lbl(qt_use_nm ? qt_lbl_nm : qt_lbl_gen, qMini_val, qt_extime)
  1881.  
  1882. f_qt_manage_layer(qt_mdl == qt_mdl3 ? false : new_year_qt, qt_is_year, Year_qt, yearlb_qt, 1, qt_extime)
  1883. f_qt_manage_layer(qt_mdl == qt_mdl3 ? false : new_quart_qt, qt_is_quart or (qt_is_year and qt_show_lower), Quart_qt, quarlb_qt, qt_is_quart ? 1 : 0, qt_extime)
  1884. f_qt_manage_layer(qt_mdl == qt_mdl3 ? false : new_month_qt, qt_is_mon or (qt_is_quart and qt_show_lower), Month_qt, montlb_qt, qt_is_mon ? 1 : 0, qt_extime)
  1885. f_qt_manage_layer(qt_mdl == qt_mdl3 ? false : new_week_qt, qt_is_week or (qt_is_mon and qt_show_lower), Week_qt, weeklb_qt, qt_is_week ? 1 : 0, qt_extime)
  1886. f_qt_manage_layer(new_daily_qt, qt_is_day or (qt_is_week and qt_show_lower), Day_qt, daylb_qt, qt_is_day ? 1 : 0, qt_extime)
  1887. f_qt_manage_layer(new_sub_qt or new_daily_qt, qt_is_sub or (qt_is_day and qt_show_lower), Sub_qt, sublb_qt, qt_is_sub ? 1 : 0, qt_extime)
  1888. f_qt_manage_layer(new_micro_qt, qt_is_micro or (qt_is_sub and qt_show_lower), Micro_qt, miclb_qt, qt_is_micro ? 1 : 0, qt_extime)
  1889. f_qt_manage_layer(new_mini_qt, qt_is_micro and qt_show_lower, Mini_qt, minlb_qt, 0, qt_extime)
  1890.  
  1891. f_qt_update_visual(qt_mdl == qt_mdl3 ? false : qt_is_year, Year_qt, qt_extime)
  1892. f_qt_update_visual(qt_mdl == qt_mdl3 ? false : (qt_is_quart or (qt_is_year and qt_show_lower)), Quart_qt, qt_extime)
  1893. f_qt_update_visual(qt_mdl == qt_mdl3 ? false : (qt_is_mon or (qt_is_quart and qt_show_lower)), Month_qt, qt_extime)
  1894. f_qt_update_visual(qt_mdl == qt_mdl3 ? false : (qt_is_week or (qt_is_mon and qt_show_lower)), Week_qt, qt_extime)
  1895. f_qt_update_visual(qt_is_day or (qt_is_week and qt_show_lower), Day_qt, qt_extime)
  1896. f_qt_update_visual(qt_is_sub or (qt_is_day and qt_show_lower), Sub_qt, qt_extime)
  1897. f_qt_update_visual(qt_is_micro or (qt_is_sub and qt_show_lower), Micro_qt, qt_extime)
  1898. f_qt_update_visual(qt_is_micro and qt_show_lower, Mini_qt, qt_extime)
  1899.  
  1900. if new_year_qt and qt_show_b and (qt_mdl == qt_mdl3 ? not qt_extime : true) and not qt_is_mon
  1901. qt_new_line := line.new(bar_index, low, bar_index, high, extend = extend.both, color = qt_divi_show ? qt_divi_clr : color.new(qt_divi_clr, 100))
  1902. if qt_show_b and (qt_mdl == qt_mdl3 ? not qt_extime : true) and qt_is_mon
  1903. if montlb_qt[1] != "W1" and montlb_qt == "W1"
  1904. qt_new_line := line.new(bar_index, low, bar_index, high, extend = extend.both, color = qt_divi_show ? qt_divi_clr : color.new(qt_divi_clr, 100))
  1905.  
  1906. f_po3_determineAutoTimeframe() =>
  1907. string tf = timeframe.period
  1908. switch tf
  1909. "1" => "15"
  1910. "3" => "30"
  1911. "5" => "60"
  1912. "15" => "240"
  1913. "60" => "1D"
  1914. "240" => "1W"
  1915. "1D" => "1M"
  1916. "1W" => "3M"
  1917. =>
  1918. if timeframe.isseconds
  1919. "1"
  1920. else if timeframe.isminutes
  1921. if timeframe.multiplier <= 1
  1922. "15"
  1923. else if timeframe.multiplier <= 3
  1924. "30"
  1925. else if timeframe.multiplier <= 5
  1926. "60"
  1927. else if timeframe.multiplier <= 15
  1928. "240"
  1929. else if timeframe.multiplier <= 60
  1930. "1D"
  1931. else
  1932. "1W"
  1933. else if timeframe.isdaily
  1934. "1M"
  1935. else if timeframe.isweekly
  1936. "3M"
  1937. else
  1938. "1M"
  1939.  
  1940. f_po3_getSizeMultiplier() =>
  1941. switch po3_size
  1942. 'Small' => 1
  1943. 'Medium' => 2
  1944. 'Large' => 3
  1945.  
  1946. f_po3_getLineStyle(style) =>
  1947. switch style
  1948. 'Solid' => line.style_solid
  1949. 'Dotted' => line.style_dotted
  1950. 'Dashed' => line.style_dashed
  1951.  
  1952. f_po3_getLabelSize(string szInput) =>
  1953. switch szInput
  1954. 'Auto' => size.auto
  1955. 'Tiny' => size.tiny
  1956. 'Small' => size.small
  1957. 'Normal' => size.normal
  1958. 'Large' => size.large
  1959. 'Huge' => size.huge
  1960. => size.small
  1961.  
  1962. f_po3_getCandlePosition(int l_pos, int sizeMult) =>
  1963. m_pos = l_pos + sizeMult
  1964. r_pos = l_pos + sizeMult * 2
  1965. [m_pos, r_pos]
  1966.  
  1967. f_po3_formatTimeLabel(int cTime, string tf) =>
  1968. if na(cTime) or cTime == 0
  1969. ""
  1970. else
  1971. int sec = timeframe.in_seconds(tf)
  1972. if sec < 3600
  1973. str.format_time(cTime, "h:mm a", syminfo.timezone)
  1974. else if sec < 86400
  1975. str.format_time(cTime, "h a", syminfo.timezone)
  1976. else if sec == 86400
  1977. str.format_time(cTime, "EEE", syminfo.timezone)
  1978. else if sec >= 604800 and sec < 2592000
  1979. int d = dayofmonth(cTime, syminfo.timezone)
  1980. int wkNum = int(math.ceil(d / 7.0))
  1981. string mName = str.format_time(cTime, "MMM", syminfo.timezone)
  1982. "Wk" + str.tostring(wkNum) + " " + mName
  1983. else
  1984. str.format_time(cTime, "MMM", syminfo.timezone)
  1985.  
  1986. f_po3_createLabel(int r_pos, float s) =>
  1987. label.new(r_pos, s, str.tostring(s, format.mintick), style = label.style_label_left, color = color.new(color.black, 100), textcolor = po3_ohlc_col, size = f_po3_getLabelSize(po3_ohlc_size))
  1988.  
  1989. f_po3_createLabels(Candle candle, float o, float h, float l, float c, int l_pos, int sizeMult) =>
  1990. if po3_ohlc_enabled
  1991. [_, r_pos] = f_po3_getCandlePosition(l_pos, sizeMult)
  1992. candle.labelO := f_po3_createLabel(r_pos, o)
  1993. candle.labelH := f_po3_createLabel(r_pos, h)
  1994. candle.labelL := f_po3_createLabel(r_pos, l)
  1995. candle.labelC := f_po3_createLabel(r_pos, c)
  1996.  
  1997. f_po3_moveLabel(label la, int r_pos, float s) =>
  1998. if not na(la)
  1999. la.set_text(str.tostring(s, format.mintick))
  2000. la.set_xy(r_pos, s)
  2001.  
  2002. f_po3_moveLabels(Candle candle, int l_pos, float o, float h, float l, float c, int sizeMult) =>
  2003. if po3_ohlc_enabled
  2004. [_, r_pos] = f_po3_getCandlePosition(l_pos, sizeMult)
  2005. f_po3_moveLabel(candle.labelO, r_pos, o)
  2006. f_po3_moveLabel(candle.labelH, r_pos, h)
  2007. f_po3_moveLabel(candle.labelL, r_pos, l)
  2008. f_po3_moveLabel(candle.labelC, r_pos, c)
  2009.  
  2010. f_po3_deleteLabels(Candle candle) =>
  2011. if not na(candle.labelO)
  2012. candle.labelO.delete()
  2013. candle.labelO := na
  2014. if not na(candle.labelH)
  2015. candle.labelH.delete()
  2016. candle.labelH := na
  2017. if not na(candle.labelL)
  2018. candle.labelL.delete()
  2019. candle.labelL := na
  2020. if not na(candle.labelC)
  2021. candle.labelC.delete()
  2022. candle.labelC := na
  2023.  
  2024. f_po3_createProjections(Candle candle, float o, float h, float l, float curr_o, float curr_h, float curr_l, float htf_o, float htf_h, float htf_l, int l_pos, bool useHtfData_flag, int sizeMult) =>
  2025. [m_pos, _] = f_po3_getCandlePosition(l_pos, sizeMult)
  2026. b_o = bar_index
  2027. b_h = bar_index
  2028. b_l = bar_index
  2029. o_o = o
  2030. o_h = h
  2031. o_l = l
  2032. if useHtfData_flag
  2033. if htf_o != o
  2034. b_o -= 1
  2035. o_o := curr_o
  2036. if htf_h != h
  2037. b_h -= 1
  2038. o_h := curr_h
  2039. if htf_l != l
  2040. b_l -= 1
  2041. o_l := curr_l
  2042.  
  2043. if po3_o_enabled
  2044. candle.o := line.new(b_o, o_o, m_pos, o_o, style = f_po3_getLineStyle(po3_o_style), color = po3_o_col, width = po3_o_width)
  2045. if po3_hl_enabled
  2046. candle.h := line.new(b_h, o_h, m_pos, o_h, style = f_po3_getLineStyle(po3_hl_style), color = po3_hl_col, width = po3_hl_width)
  2047. candle.l := line.new(b_l, o_l, m_pos, o_l, style = f_po3_getLineStyle(po3_hl_style), color = po3_hl_col, width = po3_hl_width)
  2048.  
  2049. f_po3_moveProjections(Candle candle, int l_pos, float o, float h, float l, float curr_o, float curr_h, float curr_l, bool useHtfData_flag, int sizeMult) =>
  2050. [m_pos, _] = f_po3_getCandlePosition(l_pos, sizeMult)
  2051. if po3_o_enabled and not na(candle.o)
  2052. candle.o.set_y1(curr_o)
  2053. candle.o.set_xy2(m_pos, curr_o)
  2054. if po3_hl_enabled and not na(candle.h) and not na(candle.l)
  2055. old_h = candle.h.get_y1()
  2056. old_l = candle.l.get_y1()
  2057.  
  2058. if h > old_h or (useHtfData_flag and h[1] < old_h)
  2059. candle.h.set_x1(bar_index)
  2060. candle.h.set_y1(curr_h)
  2061. candle.h.set_xy2(m_pos, curr_h)
  2062.  
  2063. if l < old_l or (useHtfData_flag and l[1] > old_l)
  2064. candle.l.set_x1(bar_index)
  2065. candle.l.set_y1(curr_l)
  2066. candle.l.set_xy2(m_pos, curr_l)
  2067.  
  2068. f_po3_deleteProjections(Candle candle) =>
  2069. if not na(candle.o)
  2070. candle.o.delete()
  2071. candle.o := na
  2072. if not na(candle.h)
  2073. candle.h.delete()
  2074. candle.h := na
  2075. if not na(candle.l)
  2076. candle.l.delete()
  2077. candle.l := na
  2078.  
  2079. f_po3_getCandleProperties(float o, float h, float l, float c) =>
  2080. h_body = math.max(o, c)
  2081. l_body = math.min(o, c)
  2082. body_col = o > c ? po3_down_col : po3_up_col
  2083. wick_col = o > c ? po3_down_col_wick : po3_up_col_wick
  2084. border_col = o > c ? po3_down_col_border : po3_up_col_border
  2085. [h_body, l_body, body_col, wick_col, border_col]
  2086.  
  2087. f_po3_createCandle(int l_pos, float o, float h, float l, float c, int sizeMult, int candleTime, string currTf) =>
  2088. [m_pos, r_pos] = f_po3_getCandlePosition(l_pos, sizeMult)
  2089. [h_body, l_body, body_col, wick_col, border_col] = f_po3_getCandleProperties(o, h, l, c)
  2090. Candle candle = Candle.new()
  2091. candle.cTime := candleTime
  2092. candle.body := box.new(l_pos, h_body, r_pos, l_body, border_col, bgcolor = body_col)
  2093. candle.upperWick := line.new(m_pos, h_body, m_pos, h, color = wick_col)
  2094. candle.lowerWick := line.new(m_pos, l_body, m_pos, l, color = wick_col)
  2095. if po3_show_timelbl and not na(candleTime)
  2096. string txt = f_po3_formatTimeLabel(candleTime, currTf)
  2097. candle.labelTime := label.new(m_pos, l, txt, style = label.style_label_up, color = color.new(color.black, 100), textcolor = po3_timelbl_col, size = f_po3_getLabelSize(po3_timelbl_size))
  2098. candle
  2099.  
  2100. f_po3_moveCandle(Candle candle, int l_pos, int sizeMult, string currTf) =>
  2101. [m_pos, r_pos] = f_po3_getCandlePosition(l_pos, sizeMult)
  2102. if not na(candle.body)
  2103. candle.body.set_left(l_pos)
  2104. candle.body.set_right(r_pos)
  2105. if not na(candle.upperWick)
  2106. candle.upperWick.set_x1(m_pos)
  2107. candle.upperWick.set_x2(m_pos)
  2108. if not na(candle.lowerWick)
  2109. candle.lowerWick.set_x1(m_pos)
  2110. candle.lowerWick.set_x2(m_pos)
  2111.  
  2112. if po3_show_timelbl and not na(candle.cTime)
  2113. float lowVal = not na(candle.lowerWick) ? candle.lowerWick.get_y2() : (not na(candle.body) ? candle.body.get_bottom() : na)
  2114. string txt = f_po3_formatTimeLabel(candle.cTime, currTf)
  2115. if na(candle.labelTime)
  2116. candle.labelTime := label.new(m_pos, lowVal, txt, style = label.style_label_up, color = color.new(color.black, 100), textcolor = po3_timelbl_col, size = f_po3_getLabelSize(po3_timelbl_size))
  2117. else
  2118. candle.labelTime.set_text(txt)
  2119. candle.labelTime.set_xy(m_pos, lowVal)
  2120. candle.labelTime.set_textcolor(po3_timelbl_col)
  2121. candle.labelTime.set_size(f_po3_getLabelSize(po3_timelbl_size))
  2122.  
  2123. if not po3_show_timelbl and not na(candle.labelTime)
  2124. candle.labelTime.delete()
  2125. candle.labelTime := na
  2126.  
  2127. f_po3_updateCandle(Candle candle, int l_pos, float o, float h, float l, float c, int sizeMult, int candleTime, string currTf) =>
  2128. [m_pos, r_pos] = f_po3_getCandlePosition(l_pos, sizeMult)
  2129. [h_body, l_body, body_col, wick_col, border_col] = f_po3_getCandleProperties(o, h, l, c)
  2130. candle.cTime := candleTime
  2131. if not na(candle.body)
  2132. candle.body.set_bgcolor(body_col)
  2133. candle.body.set_lefttop(l_pos, h_body)
  2134. candle.body.set_rightbottom(r_pos, l_body)
  2135. candle.body.set_border_color(border_col)
  2136. if not na(candle.upperWick)
  2137. candle.upperWick.set_color(wick_col)
  2138. candle.upperWick.set_xy1(m_pos, h_body)
  2139. candle.upperWick.set_xy2(m_pos, h)
  2140. if not na(candle.lowerWick)
  2141. candle.lowerWick.set_color(wick_col)
  2142. candle.lowerWick.set_xy1(m_pos, l_body)
  2143. candle.lowerWick.set_xy2(m_pos, l)
  2144. if po3_show_timelbl
  2145. string txt = f_po3_formatTimeLabel(candleTime, currTf)
  2146. if na(candle.labelTime)
  2147. candle.labelTime := label.new(m_pos, l, txt, style = label.style_label_up, color = color.new(color.black, 100), textcolor = po3_timelbl_col, size = f_po3_getLabelSize(po3_timelbl_size))
  2148. candle.labelTime.set_text(txt)
  2149. candle.labelTime.set_xy(m_pos, l)
  2150. candle.labelTime.set_textcolor(po3_timelbl_col)
  2151. candle.labelTime.set_size(f_po3_getLabelSize(po3_timelbl_size))
  2152. else
  2153. if not na(candle.labelTime)
  2154. candle.labelTime.delete()
  2155. candle.labelTime := na
  2156. candle.body.set_left(l_pos)
  2157.  
  2158. f_po3_deleteCandle(Candle candle) =>
  2159. if not na(candle.body)
  2160. candle.body.delete()
  2161. if not na(candle.upperWick)
  2162. candle.upperWick.delete()
  2163. if not na(candle.lowerWick)
  2164. candle.lowerWick.delete()
  2165. if not na(candle.labelTime)
  2166. candle.labelTime.delete()
  2167. f_po3_deleteLabels(candle)
  2168. f_po3_deleteProjections(candle)
  2169.  
  2170. var Candle[] po3_candles = array.new<Candle>()
  2171.  
  2172. if enable_po3
  2173. var int po3_maxIndex = po3_num - 1
  2174. var string po3_curr_tf = po3_tf_auto ? f_po3_determineAutoTimeframe() : po3_tf
  2175. var bool po3_useHtfData = timeframe.isweekly and po3_htf_data == 'Weekly' or po3_htf_data == 'Always'
  2176. var int po3_sizeMultiplier = f_po3_getSizeMultiplier()
  2177.  
  2178. if po3_candles.size() == 0
  2179. for k = 0 to po3_maxIndex
  2180. po3_candles.push(Candle.new())
  2181.  
  2182. bool po3_newCandle = ta.change(time(po3_curr_tf)) != 0
  2183.  
  2184. [po3_htf_o, po3_htf_h, po3_htf_l, po3_htf_c, po3_htf_t] = request.security(syminfo.tickerid, po3_curr_tf, [open, high, low, close, time], lookahead = barmerge.lookahead_on)
  2185.  
  2186. var float po3_o = na
  2187. var float po3_h = na
  2188. var float po3_l = na
  2189. float po3_c = close
  2190.  
  2191. if po3_newCandle
  2192. po3_o := open
  2193. po3_h := high
  2194. po3_l := low
  2195. else
  2196. po3_h := math.max(high, po3_h)
  2197. po3_l := math.min(low, po3_l)
  2198.  
  2199. float po3_curr_o = po3_o
  2200. float po3_curr_h = po3_h
  2201. float po3_curr_l = po3_l
  2202. float po3_curr_c = po3_c
  2203.  
  2204. if po3_useHtfData
  2205. po3_curr_o := po3_htf_o
  2206. po3_curr_h := po3_htf_h
  2207. po3_curr_l := po3_htf_l
  2208. po3_curr_c := po3_htf_c
  2209.  
  2210. float po3_candle_o = po3_curr_o
  2211. float po3_candle_h = po3_curr_h
  2212. float po3_candle_l = po3_curr_l
  2213. float po3_candle_c = po3_curr_c
  2214.  
  2215. int candleTimestamp = na(po3_htf_t) ? time : int(po3_htf_t)
  2216.  
  2217. if po3_newCandle and po3_candles.size() > 0
  2218. Candle oldCandle = po3_candles.shift()
  2219. f_po3_deleteCandle(oldCandle)
  2220. int pos = bar_index + po3_offset + po3_maxIndex * (po3_margin + 2 * po3_sizeMultiplier)
  2221. Candle newCandleObj = f_po3_createCandle(pos, po3_candle_o, po3_candle_h, po3_candle_l, po3_candle_c, po3_sizeMultiplier, candleTimestamp, po3_curr_tf)
  2222. f_po3_createProjections(newCandleObj, po3_o, po3_h, po3_l, po3_curr_o, po3_curr_h, po3_curr_l, po3_htf_o, po3_htf_h, po3_htf_l, pos, po3_useHtfData, po3_sizeMultiplier)
  2223. f_po3_createLabels(newCandleObj, po3_curr_o, po3_curr_h, po3_curr_l, po3_curr_c, pos, po3_sizeMultiplier)
  2224. po3_candles.push(newCandleObj)
  2225.  
  2226. if po3_candles.size() > 0
  2227. for k = 0 to po3_candles.size() - 1
  2228. Candle cObj = po3_candles.get(k)
  2229. int new_pos = bar_index + po3_offset + k * (po3_margin + 2 * po3_sizeMultiplier)
  2230. if k < po3_maxIndex
  2231. f_po3_moveCandle(cObj, new_pos, po3_sizeMultiplier, po3_curr_tf)
  2232. f_po3_deleteProjections(cObj)
  2233. f_po3_deleteLabels(cObj)
  2234. else
  2235. f_po3_updateCandle(cObj, new_pos, po3_candle_o, po3_candle_h, po3_candle_l, po3_candle_c, po3_sizeMultiplier, candleTimestamp, po3_curr_tf)
  2236. f_po3_moveProjections(cObj, new_pos, po3_o, po3_h, po3_l, po3_curr_o, po3_curr_h, po3_curr_l, po3_useHtfData, po3_sizeMultiplier)
  2237. f_po3_moveLabels(cObj, new_pos, po3_curr_o, po3_curr_h, po3_curr_l, po3_curr_c, po3_sizeMultiplier)
Advertisement
Add Comment
Please, Sign In to add comment