Guest User

ICT SESSION TIME RANGES

a guest
Nov 3rd, 2026
363
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.36 KB | Source Code | 1 0
  1. // Independent TradingView port of Distilled Desk's New York and London Time Ranges.
  2. // © DistilledTrades. Private research display; no orders or trade signals.
  3. //@version=6
  4. indicator("Time Ranges",overlay=true,dynamic_requests=true,max_boxes_count=300,max_lines_count=500,max_labels_count=500)
  5. const string NY="America/New_York"
  6. const string LONDON="Europe/London"
  7. a0=input.bool(true,"08:50–09:10 → 10:55",group="New York windows")
  8. a1=input.bool(true,"10:50–11:10 → 12:10",group="New York windows")
  9. a2=input.bool(false,"Bell · 09:00–09:30 → 10:30",group="New York windows")
  10. a3=input.bool(false,"Pre-news · 07:30–08:30 → 12:30",group="New York windows")
  11. a4=input.bool(true,"Opening hour · 09:30–10:30 → 12:30",group="New York windows")
  12. a5=input.bool(false,"09:50–10:10 → 12:10",group="New York windows")
  13. a6=input.bool(false,"Pre-open · 07:00–08:00 → 10:00 UK",group="London windows")
  14. a7=input.bool(true,"Opening hour · 08:00–09:00 → 12:00 UK",group="London windows")
  15. showBands=input.bool(true,"Historical P30–P70 zones",group="Display",tooltip="Earlier complete same-symbol/feed sessions only, separately grouped by first edge and final outcome. 30+ observations for qualified bands; optional dashed previews use3–29. Conditional historical excursions, not targets or forecast probabilities.")
  16. previewBands=input.bool(true,"Show low-sample P-box previews",group="Display",tooltip="Exploratory preview with 3–29 earlier complete sessions in that exact side/outcome cohort. Dashed outline, LOW SAMPLE label and n. Does not relax the 30-session percentage threshold or mark a preview as qualified.")
  17. showLabels=input.bool(true,"Chart labels",group="Display")
  18. showPanel=input.bool(true,"Range status table",group="Display")
  19. keepDays=input.int(3,"Recent chart days",minval=1,maxval=5,group="Display")
  20. rangeInk=input.color(#4CAF50,"Range",group="Display")
  21. contInk=input.color(#29946e,"Continuation",group="Display")
  22. revInk=input.color(#ce6570,"Reversal",group="Display")
  23. header=input.color(#283238,"Table header",group="Display")
  24. rowsInk=input.color(#f0f0f0,"Table rows",group="Display")
  25. textInk=input.color(#20252b,"Table text",group="Display")
  26. where=input.string("Bottom right","Table position",options=["Top right","Top left","Bottom right","Bottom left"],group="Display")
  27. textSize=input.string(size.small,"Table text size",options=[size.tiny,size.small,size.normal],group="Display")
  28. weekdayFilter=input.string("All weekdays","Historical weekday filter",options=["All weekdays","Current range weekday"],group="Historical tendency")
  29. firstFilter=input.string("Auto · observed first edge","Historical first-break filter",options=["Auto · observed first edge","Both","High first","Low first"],group="Historical tendency",tooltip="Auto uses both sides before the first break, then the actual observed first edge. Fixed High/Low selections are labelled explicitly and are not today's detected direction.")
  30. cohortMax=input.int(250,"Earlier sessions retained per window",minval=60,maxval=500,group="History")
  31. sharedHistory=input.bool(true,"Use deeper shared minute history",group="History",tooltip="Loads actual native minutes through a background 1H context. The same symbol, range, first-side and outcome definitions are preserved. Only earlier complete sessions qualify. Each statistic uses the source with more samples; never adds overlapping source counts.")
  32. fineHistory=input.int(200000,"Native minute lookback",minval=5000,maxval=200000,step=5000,group="History",tooltip="Actual history depends on TradingView's plan, symbol and intrabar availability. Missing minutes are not filled. Low sample cohorts remain withheld.")
  33. int sec=int(timeframe.in_seconds(timeframe.main_period))
  34. bool supported=chart.is_standard and sec>=30 and sec<=3600
  35. // One exact closed minute is the atomic observation, including on a 30s chart.
  36. type Minute
  37. int t
  38. int e
  39. float o
  40. float h
  41. float l
  42. float c
  43. f_minute()=>
  44. Minute.new(time,time_close,open,high,low,close)
  45. type Sample
  46. int deadline
  47. int side
  48. int outcome
  49. float excursion
  50. float opposing
  51. type Range
  52. int id
  53. int start
  54. int finish
  55. int deadline
  56. string name
  57. bool enabled
  58. int last=na
  59. bool valid=true
  60. float hi=na
  61. float lo=na
  62. float postHi=na
  63. float postLo=na
  64. int side=0
  65. int firstAt=na
  66. int reversalAt=na
  67. int state=0 // building 0, waiting 1, pending 2, reversal 3, continuation 4, ambiguous 5, unavailable 6, no break 7
  68. bool archived=false
  69. array<float> bands=na // high continuation P30/50/70, high reversal, low continuation, low reversal
  70. array<int> counts=na
  71. array<int> tendency=na // high C/R, low C/R; frozen at this range close
  72. string historySource="Chart"
  73. f_name(int i)=>
  74. i==0?"08:50–09:10":i==1?"10:50–11:10":i==2?"09:00–09:30":i==3?"07:30–08:30":i==4?"09:30–10:30":i==5?"09:50–10:10":i==6?"London 07:00–08:00":"London 08:00–09:00"
  75. f_zone(int i)=>
  76. i>=6?LONDON:NY
  77. f_zoneLabel(int i)=>
  78. i>=6?"UK":"NY"
  79. f_clocks(int t,int i)=>
  80. int startM=i==0?530:i==1?650:i==2?540:i==3?450:i==4?570:i==5?590:i==6?420:480
  81. int endM=i==0?550:i==1?670:i==2?570:i==3?510:i==4?630:i==5?610:i==6?480:540
  82. int stopM=i==0?655:i==1?730:i==2?630:i==3?750:i==4?750:i==5?730:i==6?600:720
  83. string zone=f_zone(i)
  84. int y=year(t,zone),m=month(t,zone),d=dayofmonth(t,zone)
  85. [timestamp(zone,y,m,d,int(startM/60),startM%60),timestamp(zone,y,m,d,int(endM/60),endM%60),timestamp(zone,y,m,d,int(stopM/60),stopM%60)]
  86. // NumPy method="linear" parity: percentile position is (n-1)*q.
  87. f_linear(array<float> values,float q)=>
  88. float at=(values.size()-1)*q
  89. int left=int(math.floor(at))
  90. int right=int(math.ceil(at))
  91. values.get(left)+(values.get(right)-values.get(left))*(at-left)
  92. f_quantiles(array<Sample> history,Range r)=>
  93. r.bands:=array.new_float(12,na)
  94. r.counts:=array.new_int(4,0)
  95. r.tendency:=array.new_int(4,0)
  96. for sample in history
  97. if sample.deadline<r.start and (weekdayFilter=="All weekdays" or dayofweek(sample.deadline,f_zone(r.id))==dayofweek(r.start,f_zone(r.id)))
  98. int slot=(sample.side==1?0:2)+(sample.outcome==3?1:0)
  99. r.tendency.set(slot,r.tendency.get(slot)+1)
  100. for cohort=0 to 3
  101. array<float> values=array.new_float()
  102. int side=cohort<2?1:-1
  103. int outcome=cohort%2==0?4:3
  104. for sample in history
  105. if sample.deadline<r.start and sample.side==side and sample.outcome==outcome
  106. values.push(outcome==4?sample.excursion:sample.opposing)
  107. r.counts.set(cohort,values.size())
  108. if values.size()>=30 or previewBands and values.size()>=3
  109. values.sort()
  110. r.bands.set(cohort*3,f_linear(values,.3))
  111. r.bands.set(cohort*3+1,f_linear(values,.5))
  112. r.bands.set(cohort*3+2,f_linear(values,.7))
  113. 0
  114. method step(Range r,Minute b,array<Sample> history)=>
  115. if b.t>=r.start and b.t<r.deadline and not r.archived
  116. bool prices=not na(b.o) and not na(b.h) and not na(b.l) and not na(b.c) and b.h>=math.max(b.o,b.c) and b.l<=math.min(b.o,b.c)
  117. if b.e-b.t!=60000 or (na(r.last)?b.t!=r.start:b.t!=r.last) or not prices
  118. r.valid:=false
  119. r.last:=b.e
  120. if b.t<r.finish
  121. r.hi:=na(r.hi)?b.h:math.max(r.hi,b.h)
  122. r.lo:=na(r.lo)?b.l:math.min(r.lo,b.l)
  123. if b.e==r.finish
  124. r.valid:=r.valid and r.hi>r.lo
  125. r.state:=r.valid?1:6
  126. if r.valid
  127. f_quantiles(history,r)
  128. else if r.valid
  129. bool up=b.h>r.hi
  130. bool down=b.l<r.lo
  131. if r.side==0 and r.state!=5
  132. if up and down
  133. r.state:=5
  134. r.firstAt:=b.e
  135. else if up or down
  136. r.side:=up?1:-1
  137. r.firstAt:=b.e
  138. r.state:=2
  139. if r.side!=0
  140. r.postHi:=na(r.postHi)?b.h:math.max(r.postHi,b.h)
  141. r.postLo:=na(r.postLo)?b.l:math.min(r.postLo,b.l)
  142. if na(r.reversalAt) and (r.side==1?down:up)
  143. r.reversalAt:=b.e
  144. r.state:=3
  145. if not r.valid
  146. r.state:=6
  147. if b.e==r.deadline
  148. if r.valid and r.state!=5
  149. r.state:=r.side==0?7:not na(r.reversalAt)?3:4
  150. if r.state==3 or r.state==4
  151. float width=r.hi-r.lo
  152. float excursion=r.side==1?(r.postHi-r.hi)/width:(r.lo-r.postLo)/width
  153. float opposing=math.max(0,r.side==1?(r.lo-r.postLo)/width:(r.postHi-r.hi)/width)
  154. history.push(Sample.new(r.deadline,r.side,r.state,excursion,opposing))
  155. if history.size()>cohortMax
  156. history.shift()
  157. r.archived:=true
  158. else if b.t>=r.deadline and not r.archived
  159. // Even one absent minute through the deadline invalidates the whole cohort.
  160. r.valid:=false
  161. r.state:=6
  162. r.archived:=true
  163. 0
  164. var h0=array.new<Sample>()
  165. var h1=array.new<Sample>()
  166. var h2=array.new<Sample>()
  167. var h3=array.new<Sample>()
  168. var h4=array.new<Sample>()
  169. var h5=array.new<Sample>()
  170. var h6=array.new<Sample>()
  171. var h7=array.new<Sample>()
  172. f_history(int i)=>
  173. i==0?h0:i==1?h1:i==2?h2:i==3?h3:i==4?h4:i==5?h5:i==6?h6:h7
  174. var ranges=array.new<Range>()
  175. var int dateKey=na
  176. var int lastEnd=na
  177. var int gaps=0
  178. f_dayKey(int t,string zone)=>
  179. year(t,zone)*10000+month(t,zone)*100+dayofmonth(t,zone)
  180. f_enabled(int i)=>
  181. i==0?a0:i==1?a1:i==2?a2:i==3?a3:i==4?a4:i==5?a5:i==6?a6:a7
  182. // Each profile rolls on its own local date. London must not be reset at NY midnight.
  183. var profileDays=array.new_int(8,na)
  184. f_dispatch(Minute b,int key)=>
  185. for i=0 to 7
  186. string zone=f_zone(i)
  187. int today=f_dayKey(b.t,zone)
  188. if na(profileDays.get(i)) or today!=profileDays.get(i)
  189. for r in ranges
  190. if r.id==i and not r.archived
  191. r.state:=6
  192. r.valid:=false
  193. r.archived:=true
  194. if dayofweek(b.t,zone)>=dayofweek.monday and dayofweek(b.t,zone)<=dayofweek.friday
  195. [s,e,d]=f_clocks(b.t,i)
  196. ranges.push(Range.new(i,s,e,d,f_name(i),f_enabled(i)))
  197. profileDays.set(i,today)
  198. while ranges.size()>keepDays*8
  199. ranges.shift()
  200. for r in ranges
  201. if not r.archived
  202. r.step(b,f_history(r.id))
  203. f_dayKey(b.t,NY)
  204. // Native 1m requests on charts >=1m; native 30s pairs on the seconds chart.
  205. var int halfStart=na
  206. var Minute half=na
  207. if supported
  208. int cutoff=barstate.isrealtime?int(math.floor(timenow/60000)*60000):time_close
  209. array<Minute> incoming=array.new<Minute>()
  210. if sec>60
  211. incoming:=request.security_lower_tf(syminfo.tickerid,"1",f_minute(),calc_bars_count=fineHistory)
  212. else if sec==60
  213. incoming.push(f_minute())
  214. else
  215. int minuteStart=time("1")
  216. if barstate.isconfirmed
  217. if time==minuteStart and time_close-time==30000
  218. halfStart:=minuteStart
  219. half:=f_minute()
  220. else if not na(half) and halfStart==minuteStart and time==half.e and time_close-time==30000 and time_close==time_close("1")
  221. incoming.push(Minute.new(half.t,time_close,half.o,math.max(half.h,high),math.min(half.l,low),close))
  222. half:=na
  223. for b in incoming
  224. if b.e<=cutoff and (na(lastEnd) or b.e>lastEnd)
  225. if not na(lastEnd) and b.t!=lastEnd
  226. gaps+=1
  227. dateKey:=f_dispatch(b,dateKey)
  228. lastEnd:=b.e
  229. // Shared calibration runs in a deeper 1H context using complete native minute arrays.
  230. // It never returns or imports an event state into the chart's live detector.
  231. type HistoryBook
  232. array<Range> views
  233. array<int> days
  234. array<Sample> h0
  235. array<Sample> h1
  236. array<Sample> h2
  237. array<Sample> h3
  238. array<Sample> h4
  239. array<Sample> h5
  240. array<Sample> h6
  241. array<Sample> h7
  242. int last=na
  243. int first=na
  244. int minutes=0
  245. type HistoryBundle
  246. array<Range> views
  247. int last
  248. int first
  249. int minutes
  250. f_sharedBook()=>
  251. HistoryBook.new(array.new<Range>(),array.new_int(8,na),array.new<Sample>(),array.new<Sample>(),array.new<Sample>(),array.new<Sample>(),array.new<Sample>(),array.new<Sample>(),array.new<Sample>(),array.new<Sample>())
  252. f_sharedSamples(HistoryBook book,int i)=>
  253. i==0?book.h0:i==1?book.h1:i==2?book.h2:i==3?book.h3:i==4?book.h4:i==5?book.h5:i==6?book.h6:book.h7
  254. method ingestShared(HistoryBook book,Minute b)=>
  255. if na(book.last) or b.e>book.last
  256. if na(book.first)
  257. book.first:=b.t
  258. book.minutes+=1
  259. for i=0 to 7
  260. string zone=f_zone(i)
  261. int today=f_dayKey(b.t,zone)
  262. if na(book.days.get(i)) or today!=book.days.get(i)
  263. for view in book.views
  264. if view.id==i and not view.archived
  265. view.state:=6
  266. view.valid:=false
  267. view.archived:=true
  268. if dayofweek(b.t,zone)>=dayofweek.monday and dayofweek(b.t,zone)<=dayofweek.friday
  269. [s,e,d]=f_clocks(b.t,i)
  270. Range view=Range.new(i,s,e,d,f_name(i),true)
  271. f_quantiles(f_sharedSamples(book,i),view)
  272. book.views.push(view)
  273. book.days.set(i,today)
  274. while book.views.size()>keepDays*8
  275. book.views.shift()
  276. for view in book.views
  277. if not view.archived
  278. view.step(b,f_sharedSamples(book,view.id))
  279. book.last:=b.e
  280. 0
  281. f_sharedCalibration()=>
  282. var HistoryBook book=f_sharedBook()
  283. string historyTicker=ticker.modify(syminfo.tickerid,session=syminfo.session)
  284. array<Minute> native=request.security_lower_tf(historyTicker,"1",f_minute(),currency=syminfo.currency,calc_bars_count=fineHistory)
  285. int cutoff=barstate.isrealtime?int(math.floor(timenow/60000)*60000):time_close
  286. for b in native
  287. if b.e<=cutoff
  288. book.ingestShared(b)
  289. // Returning collections on every requested bar would duplicate large buffers.
  290. HistoryBundle result=na
  291. if barstate.islast or barstate.islastconfirmedhistory
  292. result:=HistoryBundle.new(book.views,book.last,book.first,book.minutes)
  293. result
  294. // Direct minute context avoids reusing a short chart-minute dataset when available.
  295. f_sharedMinuteCalibration()=>
  296. var HistoryBook book=f_sharedBook()
  297. int cutoff=barstate.isrealtime?int(math.floor(timenow/60000)*60000):time_close
  298. if time_close<=cutoff
  299. book.ingestShared(f_minute())
  300. HistoryBundle result=na
  301. if barstate.islast or barstate.islastconfirmedhistory
  302. result:=HistoryBundle.new(book.views,book.last,book.first,book.minutes)
  303. result
  304. f_applyShared(Range local,Range remote)=>
  305. bool used=false
  306. // Exact window/session key; frozen remote facts contain only deadlines before start.
  307. if local.id==remote.id and local.start==remote.start and not na(remote.tendency)
  308. if na(local.tendency)
  309. local.tendency:=array.new_int(4,0)
  310. if na(local.counts)
  311. local.counts:=array.new_int(4,0)
  312. if na(local.bands)
  313. local.bands:=array.new_float(12,na)
  314. if remote.tendency.sum()>local.tendency.sum()
  315. local.tendency:=remote.tendency.copy()
  316. used:=true
  317. for cohort=0 to 3
  318. if remote.counts.get(cohort)>local.counts.get(cohort)
  319. local.counts.set(cohort,remote.counts.get(cohort))
  320. for q=0 to 2
  321. local.bands.set(cohort*3+q,remote.bands.get(cohort*3+q))
  322. used:=true
  323. if used
  324. local.historySource:="Shared 1m"
  325. used
  326. HistoryBundle shared=na
  327. HistoryBundle sharedMinute=na
  328. if sharedHistory and supported
  329. shared:=request.security(syminfo.tickerid,"60",f_sharedCalibration(),gaps=barmerge.gaps_off,lookahead=barmerge.lookahead_off,calc_bars_count=int(math.ceil(fineHistory/60.0))+48)
  330. if sec<=60
  331. sharedMinute:=request.security(ticker.modify(syminfo.tickerid,session=syminfo.session),"1",f_sharedMinuteCalibration(),gaps=barmerge.gaps_off,lookahead=barmerge.lookahead_off,calc_bars_count=fineHistory)
  332. if barstate.islast
  333. for source=0 to 1
  334. HistoryBundle bundle=source==0?shared:sharedMinute
  335. if not na(bundle) and not na(bundle.views)
  336. for local in ranges
  337. for remote in bundle.views
  338. if local.id==remote.id and local.start==remote.start
  339. f_applyShared(local,remote)
  340. if not na(sharedMinute) and (na(shared) or sharedMinute.minutes>shared.minutes)
  341. shared:=sharedMinute
  342. // Render only after a new closed minute. State and calibration never use a forming minute.
  343. var boxes=array.new<box>()
  344. var lines=array.new<line>()
  345. var labels=array.new<label>()
  346. f_line(int a,int z,float p,color ink,string caption="",float offset=0)=>
  347. lines.push(line.new(a,p,z,p,xloc=xloc.bar_time,color=ink,width=1))
  348. if showLabels and caption!=""
  349. labels.push(label.new(z,p+offset,caption,xloc=xloc.bar_time,style=label.style_label_left,color=color.new(ink,100),textcolor=ink,size=size.tiny))
  350. 0
  351. f_draw(Range r)=>
  352. int cursor=math.min(nz(lastEnd,r.start),r.deadline)
  353. if r.enabled and cursor>r.start and not na(r.hi) and r.state!=6
  354. float width=r.hi-r.lo
  355. float pad=width*.04
  356. int right=math.min(r.deadline,cursor+600000)
  357. boxes.push(box.new(r.start,r.hi,math.min(r.finish,cursor),r.lo,xloc=xloc.bar_time,bgcolor=color.new(rangeInk,91),border_color=rangeInk))
  358. f_line(r.start,right,r.hi,rangeInk,showLabels?r.name+" "+f_zoneLabel(r.id)+" · High "+str.tostring(r.hi,format.mintick)+(r.side==1 or not na(r.reversalAt)?" · BSL taken":" · BSL"):"",pad)
  359. f_line(r.start,right,r.lo,rangeInk,showLabels?r.name+" "+f_zoneLabel(r.id)+" · Low "+str.tostring(r.lo,format.mintick)+(r.side==-1 or not na(r.reversalAt)?" · SSL taken":" · SSL"):"",-pad)
  360. if cursor>=r.finish
  361. lines.push(line.new(r.finish,r.hi,r.finish,r.lo,xloc=xloc.bar_time,color=rangeInk,style=line.style_dashed))
  362. if not na(r.firstAt) and r.side!=0 and showLabels
  363. labels.push(label.new(r.firstAt-60000,r.side==1?r.hi:r.lo,r.side==1?"▲":"▼",xloc=xloc.bar_time,style=label.style_label_center,color=color.new(color.black,100),textcolor=color.black,size=size.tiny))
  364. if not na(r.reversalAt)
  365. lines.push(line.new(r.reversalAt-60000,r.hi,r.reversalAt-60000,r.lo,xloc=xloc.bar_time,color=revInk,style=line.style_dashed))
  366. if showBands and cursor>=r.finish and r.state!=5 and not na(r.bands)
  367. for cohort=0 to 3
  368. int side=cohort<2?1:-1
  369. bool reversal=cohort%2==1
  370. if not na(r.bands.get(cohort*3)) and (r.side==0?not reversal:r.side==side)
  371. float anchor=reversal?(side==1?r.lo:r.hi):(side==1?r.hi:r.lo)
  372. int sign=reversal?-side:side
  373. float p30=anchor+sign*width*r.bands.get(cohort*3)
  374. float p50=anchor+sign*width*r.bands.get(cohort*3+1)
  375. float p70=anchor+sign*width*r.bands.get(cohort*3+2)
  376. int left=na(r.firstAt)?r.finish:math.max(r.finish,r.firstAt-60000)
  377. color ink=reversal?revInk:contInk
  378. int direction=reversal?-side:side
  379. string title=(r.side==0?"If "+(side==1?"high":"low")+" breaks · ":"")+(direction==1?"▲ Bullish ":"▼ Bearish ")+(reversal?"reversal":"continuation")+" P30–P70 · n="+str.tostring(r.counts.get(cohort))+(r.counts.get(cohort)<30?" · LOW SAMPLE PREVIEW":"")
  380. if right>left
  381. boxes.push(box.new(left,math.max(p30,p70),right,math.min(p30,p70),xloc=xloc.bar_time,bgcolor=color.new(ink,86),border_color=r.counts.get(cohort)<30?#c08a25:ink,border_style=r.counts.get(cohort)<30?line.style_dashed:line.style_solid))
  382. f_line(left,right,p50,ink,title+" · P50",pad)
  383. 0
  384. f_state(Range r)=>
  385. int direction=r.state==3?-r.side:r.side
  386. string side=direction==1?"▲ BULL ":direction==-1?"▼ BEAR ":""
  387. r.state==6?"UNAVAILABLE":lastEnd<r.start?"SCHEDULED":r.state==0?"BUILDING":r.state==1?"WAIT BREAK":r.state==2?side+"BREAK · PENDING":r.state==3?side+"REVERSAL":r.state==4?side+"CONTINUATION":r.state==5?"AMBIGUOUS":"NO BREAK"
  388. var table panel=table.new(where=="Top right"?position.top_right:where=="Top left"?position.top_left:where=="Bottom left"?position.bottom_left:position.bottom_right,4,10,border_width=0,frame_color=header,frame_width=1)
  389. var int rendered=na
  390. if barstate.islast
  391. if na(rendered) or rendered!=lastEnd or sharedHistory and not na(shared)
  392. for b in boxes
  393. box.delete(b)
  394. for l in lines
  395. line.delete(l)
  396. for l in labels
  397. label.delete(l)
  398. boxes.clear()
  399. lines.clear()
  400. labels.clear()
  401. for r in ranges
  402. f_draw(r)
  403. rendered:=lastEnd
  404. table.clear(panel,0,0,3,9)
  405. if showPanel
  406. table.cell(panel,0,0,"DSTL TIME RANGES",text_color=color.white,bgcolor=header,text_size=textSize,text_halign=text.align_left)
  407. table.cell(panel,1,0,"STATE",text_color=color.white,bgcolor=header,text_size=textSize)
  408. table.cell(panel,2,0,"CONT / REV · n",text_color=color.white,bgcolor=header,text_size=textSize)
  409. table.cell(panel,3,0,"P BOXES · C / R",text_color=color.white,bgcolor=header,text_size=textSize)
  410. int row=1
  411. for r in ranges
  412. if not na(lastEnd) and f_dayKey(r.start,f_zone(r.id))==f_dayKey(lastEnd-1,f_zone(r.id)) and r.enabled
  413. int filterSide=firstFilter=="High first"?1:firstFilter=="Low first"?-1:firstFilter=="Both"?0:r.side
  414. string filterName=filterSide==1?"High first":filterSide==-1?"Low first":"Both first edges"
  415. int c=0
  416. int v=0
  417. if not na(r.tendency)
  418. c:=filterSide==0?r.tendency.get(0)+r.tendency.get(2):r.tendency.get(filterSide==1?0:2)
  419. v:=filterSide==0?r.tendency.get(1)+r.tendency.get(3):r.tendency.get(filterSide==1?1:3)
  420. int n=c+v
  421. float rate=n>0?float(c)/n:na
  422. string counts=n>=30?str.tostring(rate*100,"#.#")+"% / "+str.tostring((1-rate)*100,"#.#")+"% · "+str.tostring(n):"n="+str.tostring(n)+" · NEED 30"
  423. color tendencyInk=n<30?color.gray:c>v?contInk:v>c?revInk:textInk
  424. float centre=n>0?(rate+3.8416/(2*n))/(1+3.8416/n):na
  425. float margin=n>0?1.96*math.sqrt(rate*(1-rate)/n+3.8416/(4*n*n))/(1+3.8416/n):na
  426. string confidence=n>=30?" Continuation 95% Wilson interval "+str.tostring((centre-margin)*100,"#.#")+"–"+str.tostring((centre+margin)*100,"#.#")+"%.":" At least 30 earlier complete breakout sessions required."
  427. int direction=r.state==3?-r.side:r.side
  428. color ink=r.state==6?color.gray:direction==1?#138c52:direction==-1?#a43b45:textInk
  429. table.cell(panel,0,row,r.name+" "+f_zoneLabel(r.id),text_color=textInk,bgcolor=rowsInk,text_size=textSize,text_halign=text.align_left)
  430. table.cell(panel,1,row,f_state(r),text_color=ink,bgcolor=rowsInk,text_size=textSize,tooltip="Range "+str.format_time(r.start,"HH:mm",f_zone(r.id))+"–"+str.format_time(r.finish,"HH:mm",f_zone(r.id))+"; deadline "+str.format_time(r.deadline,"HH:mm",f_zone(r.id))+" "+f_zoneLabel(r.id)+". Strict wick break; equality is a touch. Both edges first broken within one minute = ambiguous. Continuation is confirmed only at the deadline. Missing minutes invalidate the session.")
  431. table.cell(panel,2,row,counts,text_color=tendencyInk,bgcolor=rowsInk,text_size=textSize,tooltip=r.historySource+" history · "+filterName+" · "+weekdayFilter+". "+str.tostring(c)+" continuation / "+str.tostring(v)+" reversal. Historical event frequency frozen before this range's first break; not a validated current-day probability or a trade win rate."+confidence+" Today's outcome never enters today's sample. Ambiguous/no-break/missing sessions excluded. Bands separately require 30 per outcome cohort.")
  432. string bandRead="WAIT RANGE"
  433. if not showBands
  434. bandRead:="OFF"
  435. else if r.state==6
  436. bandRead:="DATA GAP"
  437. else if r.state==5
  438. bandRead:="AMBIGUOUS"
  439. else if not na(r.counts)
  440. int cN=r.counts.get(r.side==-1?2:0)
  441. int rN=r.counts.get(r.side==-1?3:1)
  442. bandRead:=r.side==0?"↑ "+str.tostring(cN)+"/"+str.tostring(rN)+" · ↓ "+str.tostring(r.counts.get(2))+"/"+str.tostring(r.counts.get(3)):"C "+str.tostring(cN)+(cN>=30?" OK":previewBands and cN>=3?" LOW":" WAIT")+" / R "+str.tostring(rN)+(rN>=30?" OK":previewBands and rN>=3?" LOW":" WAIT")
  443. table.cell(panel,3,row,bandRead,text_color=color.gray,bgcolor=rowsInk,text_size=textSize,tooltip=r.historySource+" history · best available samples per cohort; overlapping sources are not added. Each P box has its own first-side/outcome cohort; percentages use combined outcome counts. Before an edge breaks, each first side is assessed separately. OK = at least30; LOW = exploratory3–29 when previews enabled; WAIT = insufficient sample. Before a break only continuation boxes are drawn, for each possible first side. Missing data and ambiguous first breaks always withhold boxes.")
  444. row+=1
  445. string status=not supported?"USE STANDARD 30s–1H":na(lastEnd)?"WAIT NATIVE MINUTES":"NY "+str.format_time(lastEnd,"HH:mm",NY)+" · UK "+str.format_time(lastEnd,"HH:mm",LONDON)+(sharedHistory?(not na(shared)?" · shared 1m · "+str.tostring(shared.minutes)+" bars":" · shared waiting"):" · chart history")
  446. table.cell(panel,0,9,status,text_color=color.gray,bgcolor=rowsInk,text_size=size.tiny,tooltip=(not na(shared)?"Shared native-minute coverage: "+str.format_time(shared.first,"yyyy-MM-dd HH:mm",NY)+" to "+str.format_time(shared.last,"yyyy-MM-dd HH:mm",NY)+" NY; "+str.tostring(shared.minutes)+" actual minutes. History is limited by TradingView and the feed; a larger request cannot create unavailable bars. ":"")+"Conditional historical bands are not entries or targets. TradingView's symbol/feed/history may differ from Desk. No synthesized missing candles.")
  447.  
Advertisement
Add Comment
Please, Sign In to add comment