Core Concepts

Time and Sessions

Read the current bar's clock and trading session with hour(), dayOfMonth(), isAsianSession(), and friends. All UTC, all functions.

Core Concept 5 min read

Introduction

Every bar happens at a moment in time, and that moment is often a signal in itself. London opening, the Asian session winding down, a fresh day, a weekend gap. kScript exposes the current bar's clock and its trading session as a small family of functions you can read anywhere in the per-bar body.

Two things to keep in mind:

  • They are functions. Call them with parentheses: hour(), not hour. Each returns the value for the current bar.
  • Times are UTC. Every clock value and every session boundary is in UTC. There is no local-timezone surprise, but it does mean you compare against UTC hours when you write a rule.

Lead example: highlight the session

This script tints each candle by the trading session it falls in, and prints a small clock readout on the last bar so you can see the raw values.

scripts/probes/concepts/session_highlighter.ks
//@version=2
define(title="Session Highlighter", position="onchart", axis=false)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)

// Tint each candle by the trading session it falls in (UTC).
if (isAsianSession())    { barcolor(opacity("#3b82f6", 12)) }
if (isEuropeanSession()) { barcolor(opacity("#f59e0b", 12)) }
if (isAmericanSession()) { barcolor(opacity("#22c55e", 12)) }

// A live readout of the current bar's clock on the last bar.
if (isLastBar) {
  plotTable(
    data=[["Clock", ""], ["Hour (UTC)", "".concat(hour())], ["Day of month", "".concat(dayOfMonth())], ["Month", "".concat(month())]],
    position="top_right", headerRow=true, backgroundColor="#0d1117", textColor="#e6edf3", fontSize=11
  )
}

Each session predicate is a plain boolean for the current bar, so it drops straight into an if. The candles pick up a blue, amber, or green tint depending on which session the bar opened in, and the table in the corner shows the live hour(), dayOfMonth(), and month() so you can sanity-check the clock against the chart. Note that barcolor and plotTable are annotations, not series, so they do not take label or desc.

Function reference

Every function below is called with parentheses and returns the value for the current bar.

Clock

FunctionReturns
hour()Hour of the bar, 023 (UTC).
minute()Minute of the bar, 059.
second()Second of the bar, 059.
dayOfWeek()Day of the week. Currently returns na: prefer the session predicates or dayOfMonth() for time gating.
dayOfMonth()Day of the month, starting at 1.
month()Month of the year.
year()Four-digit year of the bar.

Timestamps

FunctionReturns
time()The current bar's timestamp, in milliseconds since the Unix epoch (UTC).
timenow()The current wall-clock time, in milliseconds since the epoch. Same on every bar of a given run.

time() is the bar; timenow() is "right now." The gap between them tells you how far the current bar is from the live edge.

Sessions

FunctionReturns
isAsianSession()true when the current bar falls in the Asian trading session (UTC).
isEuropeanSession()true when the current bar falls in the European session.
isAmericanSession()true when the current bar falls in the American session.
currentSession()The session the current bar belongs to, as a value you can compare or display.

The three is...Session() predicates are the easy way to gate logic; currentSession() gives you the session itself when you want to label it, switch on it, or put it in a table.

Common patterns

Only signal during a session. Wrap your trigger in a session predicate so it can only fire when the market you care about is active:

//@version=2
define(title="London-only breakout", position="overlay", axis=true)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)
var brokeOut = d.close > d.high[1] && isEuropeanSession()
var marker = brokeOut ? d.high : na

plotShape(value=marker, shape="triangleUp", colors=["#16a34a"], label=["London break"], desc=["close above prior high, European session only"])

Gate by session instead of weekday. dayOfWeek() currently returns na, so reach for the session predicates when you want to restrict signals to a part of the day. They are the reliable way to say "only during European hours" or "skip the quiet Asian session":

//@version=2
define(title="Session-gated signal", position="onchart", axis=false)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)
var active = isEuropeanSession() || isAmericanSession()
var signal = active && d.close > ema(source=d.close, period=50)
plotShape(value=signal ? d.low : na, shape="triangleup", colors=["#16a34a"], label=["Active-session signal"], desc=["only fires during European or American hours"])

Once-per-day reset. Detect a new day by watching dayOfMonth() change from the previous bar, then reset whatever daily accumulator you keep:

//@version=2
define(title="New-day marker", position="offchart", axis=true)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)
timeseries dom = dayOfMonth()
var newDay = barIndex > 0 && dom != dom[1] ? 1 : 0

plotLine(value=newDay, colors=["#7c3aed"], width=2, label=["New day"], desc=["1 on the first bar of each calendar day"])

The same idea works for a new month (month() changes) or a new year (year() changes). Hold the clock value in a timeseries so you can index one bar back and compare.

See also

  • Execution Model for barIndex, isLastBar, and how history indexing lets you compare this bar's clock to the last one.
  • Plotting for plotTable, plotShape, and barcolor.