本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © Zeiierman {
//@version=6
indicator('True Close – Institutional Trading Sessions (Zeiierman)', overlay = true, max_boxes_count = 1000, max_lines_count = 500)
//~~}
// ~~ Tooltips {
var string t1 = "Defines the current time zone you want the session schedule to follow (e.g. UTC+2 for Central European Summer Time)."
var string t2 = "Toggle visibility of each session (Sydney, Tokyo, London, New York)."
var string t3 = "Defines the session time interval (e.g. 0900-1700). Must match the format 'HHMM-HHMM'."
var string t4 = "Background fill color for each session. Only applies when 'Show Session Background' is enabled."
var string t5 = "Border color for the first-hour true close line that appears after the first session hour completes."
var string t6 = "Color used to fill the first-hour box in each session."
var string t7 = "If checked, the background for each session box is drawn."
var string t8 = "Draws a dashed border around each session box if enabled."
var string t9 = "Draws a background highlight for the first hour of each session."
var string t10 = "Draws a border around the first-hour box when enabled."
var string t11 = "When enabled, plots a horizontal line at the true close of the first hour of the session."
var string t12 = "Adds a label at the end of each session showing the price where the true close line was formed."
var string t13 = "Shows a label under each session at its opening bar stating the execution hour."
var string t14 = "Controls the thickness of the outer border for the full session box."
var string t15 = "Controls the border width of the first-hour range box."
var string t16 = "Sets the width of the true close line plotted after the first hour."
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ Inputs {
utc = input.string('UTC+2', 'UTC', tooltip=t1)
show = array.from(
input.bool(true, 'Sydney', group = 'Sydney', inline = 'sy', tooltip=t2),
input.bool(true, 'Tokyo', group = 'Tokyo', inline = 'to', tooltip=t2),
input.bool(true, 'London', group = 'London', inline = 'lo', tooltip=t2),
input.bool(true, 'New York', group = 'New York', inline = 'ny', tooltip=t2))
times = array.from(
input.session('0100-0900', '', group = 'Sydney', inline = 'sy', tooltip=t3),
input.session('0000-0600', '', group = 'Tokyo', inline = 'to', tooltip=t3),
input.session('0900-1730', '', group = 'London', inline = 'lo', tooltip=t3),
input.session('1530-2200', '', group = 'New York', inline = 'ny', tooltip=t3))
colors = array.from(
input.color(color.red, '', group = 'Sydney', inline = 'sy', tooltip=t4),
input.color(color.yellow, '', group = 'Tokyo', inline = 'to', tooltip=t4),
input.color(#06e3ff, '', group = 'London', inline = 'lo', tooltip=t4),
input.color(color.lime, '', group = 'New York', inline = 'ny', tooltip=t4))
lineColors = array.from(
input.color(color.new(color.red, 0), '', group = 'Sydney', inline = 'sy', tooltip=t5),
input.color(color.new(color.yellow, 0), '', group = 'Tokyo', inline = 'to', tooltip=t5),
input.color(color.new(#06e3ff, 0), '', group = 'London', inline = 'lo', tooltip=t5),
input.color(color.new(color.lime, 0), '', group = 'New York', inline = 'ny', tooltip=t5))
firstHourColors = array.from(
input.color(color.new(color.white, 0), '', group = 'Sydney', inline = 'sy', tooltip=t6),
input.color(color.new(color.white, 0), '', group = 'Tokyo', inline = 'to', tooltip=t6),
input.color(color.new(color.white, 0), '', group = 'London', inline = 'lo', tooltip=t6),
input.color(color.new(color.white, 0), '', group = 'New York', inline = 'ny', tooltip=t6))
showSessionBg = input.bool(false, 'Show Session Background', group = 'Display Options', tooltip=t7)
showSessionBrdr = input.bool(true, 'Show Session Border', group = 'Display Options', tooltip=t8)
showFirstHourBg = input.bool(true, 'Show First Hour Background', group = 'Display Options', tooltip=t9)
showFirstHourBrd = input.bool(true, 'Show First Hour Border', group = 'Display Options', tooltip=t10)
showLine = input.bool(true, 'Show True Close Line', group = 'Display Options', tooltip=t11)
showTrueClose = input.bool(true, 'Show True Close label', group = 'Display Options', tooltip=t12)
showExHour = input.bool(true, 'Show Execution Hour label', group = 'Display Options', tooltip=t13)
sessionBorderWidth = input.int(1, 'Session Border Width', minval = 0, maxval = 5, group = 'Display Options', tooltip=t14)
firstHourBorderWidth = input.int(2, 'First Hour Border Width', minval = 0, maxval = 5, group = 'Display Options', tooltip=t15)
lineWidth = input.int(2, 'Line Width', minval = 1, maxval = 10, group = 'Display Options', tooltip=t16)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ type {
type Sessions
array<box> bo
array<box> fbo
array<line> flo
array<label> flabel
array<label> endLabel
string str
int leftBar
float st
float o
float h
float l
float c
int lineStartBar
float linePrice
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ session instances {
var a1 = Sessions.new(array.new<box>(), array.new<box>(), array.new<line>(), array.new<label>(), array.new<label>(), 'Sydney', na, 0.0, 0.0, 0.0, 0.0, na, na)
var a2 = Sessions.new(array.new<box>(), array.new<box>(), array.new<line>(), array.new<label>(), array.new<label>(), 'Tokyo', na, 0.0, 0.0, 0.0, 0.0, na, na)
var a3 = Sessions.new(array.new<box>(), array.new<box>(), array.new<line>(), array.new<label>(), array.new<label>(), 'London', na, 0.0, 0.0, 0.0, 0.0, na, na)
var a4 = Sessions.new(array.new<box>(), array.new<box>(), array.new<line>(), array.new<label>(), array.new<label>(), 'New York', na, 0.0, 0.0, 0.0, 0.0, na, na)
sessionNames = array.from('Sydney', 'Tokyo', 'London', 'New York')
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ constants {
const int ONE_HOUR_MS = 60 * 60 * 1000
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ helpers {
formatSession(rangeStr) =>
start = str.substring(rangeStr, 0, 4)
stop = str.substring(rangeStr, 5, 9)
str.format("{0}:{1}-{2}:{3}",
str.substring(start, 0, 2), str.substring(start, 2, 4),
str.substring(stop, 0, 2), str.substring(stop, 2, 4))
inSession(sessStr) =>
not na(time(timeframe.period, sessStr, utc))
inFirstHour(sessStart) =>
bar_index - sessStart < math.round(60/timeframe.multiplier)
belowBox(_high, _low, percent) => _low - (_high - _low) * percent
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ session logic {
method RunSessions(Sessions x, int i, bool session) =>
if show.get(i)
if session and not session[1]
x.leftBar := bar_index
x.st := time
x.o := open
x.h := high
x.l := low
x.c := close
if array.size(x.flo) > 0
line.delete(x.flo.get(0))
x.flo.clear()
fullBox = box.new(bar_index, high, bar_index, low,
border_color = showSessionBrdr ? colors.get(i) : color.new(color.black, 100),
border_style= line.style_dashed,
bgcolor = showSessionBg ? color.new(colors.get(i), 80) : color.new(color.black, 100),
border_width = sessionBorderWidth,
extend = extend.none)
if array.size(x.bo) > 0
box.delete(x.bo.get(0))
x.bo.set(0, fullBox)
else
x.bo.unshift(fullBox)
hourBox = box.new(bar_index, high, bar_index, low,
border_color = showFirstHourBrd ? color.new(firstHourColors.get(i), 0) : color.new(color.black, 100),
bgcolor = showFirstHourBg ? color.new(firstHourColors.get(i), 80) : color.new(color.black, 100),
border_width = firstHourBorderWidth,
extend = extend.none)
if array.size(x.fbo) > 0
box.delete(x.fbo.get(0))
x.fbo.set(0, hourBox)
else
x.fbo.unshift(hourBox)
midXx = x.leftBar
labelY = belowBox(x.h, x.l, 0.03)
infoText = array.get(sessionNames, i) + '\nExecution Hour'
lbl = label.new(midXx, labelY,
text = infoText,
style = label.style_label_lower_left,
textcolor = showExHour ? chart.fg_color : na,
color = na,
size = size.small,
textalign = text.align_left,
tooltip = "Institutional view: True Close ≠ Official Close.\nMost funds treat the first hour of the next day as the real close — where final flows, rebalancing, and execution dust settles."
)
if array.size(x.flabel) > 0
label.delete(x.flabel.get(0))
x.flabel.clear()
x.flabel.unshift(lbl)
if session
x.h := math.max(high, x.h)
x.l := math.min(low, x.l)
x.c := close
fb = x.bo.get(0)
box.set_rightbottom(fb, bar_index, x.l)
box.set_top(fb, x.h)
if not na(x.st) and time - x.st < ONE_HOUR_MS
fh = x.fbo.get(0)
box.set_rightbottom(fh, bar_index, x.l)
box.set_top(fh, x.h)
if array.size(x.flabel) > 0
newY = belowBox(x.h, x.l, 0.03)
label.set_y(x.flabel.get(0), newY)
if not na(x.st) and time - x.st >= ONE_HOUR_MS and array.size(x.flo) == 0 and showLine
x.lineStartBar := bar_index
x.linePrice := close
l = line.new(
x1 = x.lineStartBar, y1 = x.linePrice,
x2 = bar_index, y2 = x.linePrice,
xloc = xloc.bar_index,
extend = extend.none,
color = lineColors.get(i),
width = lineWidth,
style = line.style_solid)
x.flo.unshift(l)
if array.size(x.endLabel) > 0
label.delete(x.endLabel.get(0))
x.endLabel.clear()
txt = str.format("{0} – {1}", array.get(sessionNames, i), str.tostring(x.linePrice))
lb = label.new(
x = bar_index + 10,
y = x.linePrice,
text = txt,
xloc = xloc.bar_index,
style = label.style_label_left,
color = color.new(color.black, 100),
textcolor = showTrueClose?chart.fg_color:na,
size = size.small,
tooltip = "Institutions often treat this level — the close of the first hour — as the true close of the prior day.")
x.endLabel.unshift(lb)
if array.size(x.flo) > 0
line.set_xy2(x.flo.get(0), bar_index + 10, x.linePrice)
if array.size(x.endLabel) > 0
label.set_x(x.endLabel.get(0), bar_index + 10)
label.set_y(x.endLabel.get(0), x.linePrice)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ session flags {
syd = not na(time(timeframe.period, times.get(0), utc))
tok = not na(time(timeframe.period, times.get(1), utc))
lon = not na(time(timeframe.period, times.get(2), utc))
nyc = not na(time(timeframe.period, times.get(3), utc))
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ run sessions {
a1.RunSessions(0, syd)
a2.RunSessions(1, tok)
a3.RunSessions(2, lon)
a4.RunSessions(3, nyc)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
// ~~ dashboard table {
if barstate.islast
var table dash = table.new(position.top_right, 6, 6,
bgcolor = color.new(chart.bg_color, 0),
border_color = chart.fg_color,
frame_color = color.new(chart.fg_color, 0),
frame_width = 2,
border_width = 2)
table.cell(dash, 0, 0, "Session",
text_color = chart.fg_color,
text_halign = text.align_left,
tooltip = "Regional trading block (Sydney, Tokyo, London, NY). Each desk\nhas unique flow & news sensitivity.")
table.cell(dash, 1, 0, "Time",
text_color = chart.fg_color,
tooltip = "Official exchange session in the UTC offset you set above.")
table.cell(dash, 2, 0, "In Sess",
text_color = chart.fg_color,
tooltip = "Is the session **live right now**? Green •Yes means that desk\nis currently executing flow; red •— means it is closed.")
table.cell(dash, 3, 0, "1st Hr",
text_color = chart.fg_color,
tooltip = "Are we inside the *first* 60 min of the session?\nInstitutions finish yesterday’s business here ➜ ‘true close’.")
table.cell(dash, 4, 0, "True Close",
text_color = chart.fg_color,
tooltip = "First-hour closing price. Risk desks treat this as the real daily\nreference after all spill-over orders are cleared.")
sessArr = array.from(a1, a2, a3, a4)
rangeArr = times
nameArr = sessionNames
visibleRow = 1
for idx = 0 to 3
if show.get(idx)
s = sessArr.get(idx)
rng = rangeArr.get(idx)
nm = nameArr.get(idx)
clr = colors.get(idx)
sessNow = inSession(rng)
hrNow = sessNow and inFirstHour(s.leftBar)
txtSess = sessNow ? "Yes" : "—"
txtHr = hrNow ? "Yes" : "—"
txtLvl = showLine and not na(s.linePrice) ? str.tostring(s.linePrice) : "—"
// Session name cell ➜ tooltip explains region-specific colour
table.cell(dash, 0, visibleRow, nm,
text_color = chart.fg_color,
bgcolor = color.new(clr, 90),
text_halign = text.align_left,
tooltip = str.format(
"{0} session. Coloured box & line use this hue\nso you can visually link dashboard ⇒ chart.", nm))
// Time range cell ➜ show formatted range
table.cell(dash, 1, visibleRow, formatSession(rng),
text_color = chart.fg_color,
bgcolor = color.new(clr, 90),
tooltip = str.format(
"{0} official window (exchange clock).\nFlows tend to concentrate at open/close.", nm))
// “In Sess” cell with live indicator
table.cell(dash, 2, visibleRow, txtSess,
text_color = sessNow ? color.lime : color.red,
bgcolor = color.new(clr, 95),
tooltip = sessNow
? "Desk currently active → expect authentic\ninstitutional flow & liquidity."
: "Desk closed → any prints now are typically\npassive or cross-session arbitrage.")
// “1st Hr” cell
table.cell(dash, 3, visibleRow, txtHr,
text_color = hrNow ? color.lime : color.red,
bgcolor = color.new(clr, 95),
tooltip = hrNow
? "We are **inside** the first hour → ‘true close’ being\nfinalised (VWAP/TWAP spillovers, compliance lags)."
: "Outside first hour. Market has largely processed\nyesterday’s unfinished flows.")
// True-close price cell
table.cell(dash, 4, visibleRow, txtLvl,
text_color = chart.fg_color,
bgcolor = color.new(clr, 90),
tooltip = na(txtLvl)
? "True-close price appears once the first-hour bar\nhas completed."
: str.format(
"{0} ‘true close’ = {1}\nInstitutions anchor risk & overnight P/L to this level.",
nm, txtLvl))
visibleRow += 1
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}