Using specific session times — the open, the overlap between markets, the close — to define when a strategy is allowed to trade. Session timing is one of the most underrated filters in systematic trading.
Session timing filters restrict when a strategy can open trades based on time of day. The idea is simple: markets behave very differently at different times. The first 30 minutes after the New York open are high-volatility, high-participation, and directionally decisive. The middle of the London lunch hour is often slow and choppy. The hour before the US close can see institutional repositioning that distorts intraday patterns.
Most intraday strategies are designed with a specific session window in mind, even if that window is never made explicit. Session timing makes it explicit, which lets you test whether the edge is actually tied to those hours or whether it is a coincidence of the data period you tested.
In Pine Script, session control is handled with the `time()` function and session strings in the format `"HHMM-HHMM"`. The function returns the bar's timestamp if the bar falls within the session, or `na` if it does not.
Many strategies that look unprofitable over the full 24-hour clock become consistently positive when restricted to their natural session window. The inverse is also instructive: a strategy that looks exceptional in a single 3-month test period may fall apart when you restrict it to realistic trading hours, because much of the edge was sitting in illiquid overnight moves that would never be executed in practice.
Session timing also prevents two common structural problems: holding positions through gaps (which can distort stop-loss assumptions significantly) and operating in sessions where spreads are wide and volume is thin, making the strategy's assumed fill prices impossible to achieve in reality.
VWAP resets at the session open, which is why session timing and VWAP-based strategies are closely linked — the VWAP anchor and the session window are the same construct viewed from different angles.
//@version=6
strategy("Session Timing Demo", overlay=true)
// input.session() creates a user-editable session string in the settings panel
sessionWindow = input.session("0930-1600", "Trade Window",
tooltip="Format: HHMM-HHMM. Uses the timezone specified below.")
sessionTZ = input.string("America/New_York", "Timezone",
options=["America/New_York", "Europe/London", "Asia/Tokyo", "UTC"])
// time() returns na outside the session — not na(time()) = inside session
inSession = not na(time(timeframe.period, sessionWindow, sessionTZ))
ema9 = ta.ema(close, 9)
ema21 = ta.ema(close, 21)
// Entry conditions only fire inside the session window
longCond = inSession and ta.crossover(ema9, ema21)
shortCond = inSession and ta.crossunder(ema9, ema21)
if longCond
strategy.entry("Long", strategy.long)
if shortCond
strategy.entry("Short", strategy.short)
// Close all open positions at the end of the session — no overnight holds
if not inSession and strategy.position_size != 0
strategy.close_all(comment="Session end")
// Blue background inside the active session
bgcolor(inSession ? color.new(color.blue, 94) : na, title="Active Session")
Key takeaway: `time()` returns `na` outside the specified session. The correct idiom for an in-session check is `not na(time(timeframe.period, sessionString, timezone))`. Always specify a timezone — omitting it means the function uses the chart's timezone, which may not match the exchange's trading hours and produces silent errors that are very hard to debug.