Sessions
Session strings, time() with a session, the session.* values, and what a trading session means on 24/7 crypto markets.
Coin markets never close. There is no opening bell, no pre-market and no weekend gap, so ChartDeck treats every market as trading around the clock and calls the UTC day its session. The traditional sessions still matter to crypto traders, though: liquidity and volatility change when Asia, London and New York are at their desks. ChartScript lets you describe any window of the day as a session string and test whether a bar falls inside it.
#Session strings
A session string is "HHMM-HHMM", optionally followed by : and the days it applies to:
| String | Meaning |
|---|---|
"0800-1600" | from 08:00 up to (not including) 16:00, every day |
"2200-0600" | an overnight window: from 22:00 to 06:00 the next morning |
"0000-0000" | the whole day |
"1330-2000:23456" | 13:30 to 20:00, Monday to Friday only |
Days are digits from 1 (Sunday) to 7 (Saturday), the same numbering as dayofweek. "23456" is Monday to Friday; "17" is the weekend.
The start is inclusive and the end is exclusive, so "0800-1600" contains a bar opening at 15:59 but not one opening at 16:00. Times are in UTC unless you give a time zone (below).
#Testing a bar: time() with a session
time(timeframe, session, timezone) returns the bar's time when the bar is inside the session, and na when it is outside. So !na(time(…)) is the usual "is this bar in the session?" test:
const inLondon = !na(time("", "0800-1630", "Europe/London"))
bgcolor(inLondon ? color.new(color.accent, 90) : na, { title: "London session" })timeframe:""means the chart's timeframe. Give another one ("1D") and the result is the start of that timeframe's bar instead of the chart bar's time.session: the session string.""means no session filter.timezone: the zone the session's clock times are read in. Default"UTC". An IANA name such as"America/New_York"follows daylight saving, so a New York session stays at 09:30-16:00 local time all year while its UTC hours shift.
The test looks at the open time of each chart bar. On a 4-hour chart a bar opening at 12:00 counts as inside "1330-2000" only if it opens inside the window, which it does not. Sessions are most useful on charts of an hour or less.
time_close takes the same arguments and returns the bar's close time, or na outside the session.
#The session namespace on 24/7 markets
The session values exist so that scripts written for exchange-traded markets keep working. On coin markets their answers follow from "the session is the UTC day":
| Name | On ChartDeck |
|---|---|
session.ismarket | always true |
session.ispremarket, session.ispostmarket | always false |
session.isfirstbar (and _regular) | true on the first bar of each UTC day |
session.islastbar (and _regular) | true on the last bar of each UTC day |
session.regular, session.extended | accepted; they mean the same thing here |
session.isfirstbar is a quick way to reset something every day:
state dayHigh: float = na
dayHigh = session.isfirstbar ? high : math.max(dayHigh, high)
plot(dayHigh, "High of the UTC day", color.muted, { style: plot.style_stepline })#Session settings for the user
input.session gives the user a session string to edit, with optional choices. Combine it with a time-zone choice so people can work in their own clock:
const sess = input.session(
"0930-1600:23456",
"Session",
{ options: ["0930-1600:23456", "0800-1630:23456", "0000-0800"] }
)
const tz = input.string(
"America/New_York",
"Time zone",
{ options: ["UTC", "America/New_York", "Europe/London", "Asia/Tokyo"] }
)
bgcolor(!na(time("", sess, tz)) ? color.new(color.accent, 92) : na, { title: "Session" })#A whole example: session high and low
This indicator tracks the high and low of a chosen session, keeps them on the chart after the session ends, and marks the moment price breaks either one. The session high/low tutorial builds a similar script step by step.
//@chartscript 1
indicator("Session range", { overlay: true })
const sess = input.session("1330-2000:23456", "Session (UTC unless a zone is set)")
const tz = input.string("UTC", "Time zone", { options: ["UTC", "America/New_York", "Europe/London", "Asia/Tokyo"] })
const showBreaks = input.bool(true, "Mark breaks of the range")
const inSess = !na(time("", sess, tz))
const started = inSess && !inSess[1]
const ended = !inSess && inSess[1]
state sHigh: float = na
state sLow: float = na
state done: bool = false
if (started) {
sHigh = high
sLow = low
done = false
} else if (inSess) {
sHigh = math.max(sHigh, high)
sLow = math.min(sLow, low)
}
if (ended) {
done = true
}
plot(sHigh, "Session high", color.up, { style: plot.style_linebr })
plot(sLow, "Session low", color.down, { style: plot.style_linebr })
bgcolor(inSess ? color.new(color.accent, 93) : na, { title: "In session" })
const brokeUp = done && ta.crossover(close, sHigh)
const brokeDown = done && ta.crossunder(close, sLow)
plotshape(showBreaks && brokeUp && barstate.isconfirmed, "Break up", shape.triangleup, location.belowbar, color.up)
plotshape(
showBreaks && brokeDown && barstate.isconfirmed,
"Break down",
shape.triangledown,
location.abovebar,
color.down
)The break markers use barstate.isconfirmed, so they appear only once a bar has closed beyond the level and never flicker on the live bar. Repainting explains why that matters.