Pine Script sessions: shade market hours and mark the opening range
Markets have busy hours and quiet ones. A session script shades the hours you care about and marks the high and low of the first 30 minutes. One setting, the time zone, decides if it's right.
What a session is
A session is a stretch of time in the trading day. For example, the US stock market's regular hours: 9:30 am to 4:00 pm Eastern time.
Why code it? Because the same chart behaves differently at different hours. The first half hour after the open is often fast. Lunchtime is often quiet. Shading those hours helps you see it.
New to Pine Script? Start with Pine Script for beginners.
How Pine Script writes a session
A session is a short piece of text:
- "0930-1600" means 9:30 to 16:00, using a 24-hour clock.
- "0930-1600:23456" adds the days. 1 is Sunday, 2 is Monday… 7 is Saturday. So 23456 is Monday to Friday.
The key tool is time(). Given a session, it tells you if a candle is inside it. Outside, it gives na (nothing).
Example 1: shade the hours you trade
//@version=6
indicator("Session shading", overlay=true)
sess = input.session("0930-1600", "Session")
tz = input.string("America/New_York", "Time zone")
inSession = not na(time(timeframe.period, sess, tz))
bgcolor(inSession ? color.new(color.blue, 92) : na)
Line by line:
- Line 1 says this is Pine Script version 6.
- Line 2 names the script and puts it on the price chart.
- Line 3 makes the session a setting. input.session gives you a start and end time box.
- Line 4 makes the time zone a setting. America/New_York is US Eastern time.
- Line 5 asks: is this candle inside the session, in that time zone? not na(…) turns "a time or nothing" into true or false.
- Line 6 shades the background a faint blue when it's true. 92 means 92% see-through.
Use it on a 5-minute or 15-minute chart. On a daily chart, each candle is a whole day, so there's nothing to shade.
Why the time zone matters
Without a time zone, time() uses the exchange's time zone. For a US stock, that's New York anyway. For a forex pair or a crypto coin, it might not be.
Giving the time zone yourself removes the guesswork. And named zones like America/New_York follow daylight saving time by themselves. A fixed one like "GMT-5" doesn't, so it drifts an hour for part of the year.
| Market | Hours (Eastern time) | Note |
|---|---|---|
| US stocks, regular hours | 9:30 am – 4:00 pm | Mon–Fri |
| Forex | Sun ~5 pm – Fri 5 pm | Busiest when London and New York overlap |
| Equity index futures | Sun–Fri, 6 pm – 5 pm | With a daily 1-hour break |
Check our market hours tool for the current open and close times where you live.
Example 2: the opening range
The opening range is the high and low of the first few minutes after the open. Many traders watch it as the day's first Support and Resistance. This script marks the first 30 minutes:
//@version=6
indicator("Opening range", overlay=true)
orSess = input.session("0930-1000", "Opening range")
tz = input.string("America/New_York", "Time zone")
inOR = not na(time(timeframe.period, orSess, tz))
startOR = inOR and not inOR[1]
var float orHigh = na
var float orLow = na
if startOR
orHigh := high
orLow := low
else if inOR
orHigh := math.max(orHigh, high)
orLow := math.min(orLow, low)
plot(inOR ? na : orHigh, "OR high", color=color.green, style=plot.style_linebr, linewidth=2)
plot(inOR ? na : orLow, "OR low", color=color.red, style=plot.style_linebr, linewidth=2)
Every line, in plain words
- Line 3 sets the range to 9:30–10:00.
- Line 5 is true on candles inside those 30 minutes.
- Line 6 is true only on the first candle of the range: inside now, but not on the candle before. inOR[1] means "was the last candle inside?"
- Lines 7 and 8 make 2 boxes that keep their values from candle to candle. var does that.
- Lines 9 to 11 start fresh each morning: the first candle's high and low.
- Lines 12 to 14 stretch them while the range is still open. math.max keeps the higher of the 2 values; math.min the lower.
- Lines 15 and 16 draw the high in green and the low in red, but only after the range has finished. plot.style_linebr leaves a gap where the value is na, so each day's lines start clean.
Use a chart timeframe that fits inside 30 minutes, like 5 minutes. On a 1-hour chart, one candle already covers the whole range and more.
The repaint question
Good news: Example 2 doesn't peek ahead. The lines only appear once the 30 minutes are over, and they never change after that.
During the range itself, the high and low are still growing. That's why line 15 hides them until the range ends. If you showed them early, they'd move on the live chart, and history would look tidier than it felt.
Ideas to build on
- Mark lunchtime. Add a second session, "1130-1330", and shade it gray.
- London and New York overlap. For forex, shade "0800-1200" in New York time. See best time to trade forex.
- An alert at the break. Use ta.crossover(close, orHigh) with alert(). See Pine Script alerts.
- Labels with the range size. See Pine Script labels and lines.
A range is a level, not a signal. Price closing past the opening range high is information. Whether it's a trade still depends on the bigger chart, a body close past the line, your stop and your size. Plenty of breaks fail. See opening range breakout.
Try it today
- Paste Example 2 into the Pine Editor on a computer. Save and add it to a 5-minute chart of a US stock or ETF.
- Scroll back 10 days. For each day, note if price later closed above the high, below the low, or stayed inside.
- Step through a few mornings with bar replay, so you can't see the rest of the day.
- Log what you see. No trades yet. Just counts.
Daylight saving trap. Europe and the US change clocks on different weekends. For a few weeks a year, London and New York are 4 hours apart instead of 5. Named time zones handle this. Fixed offsets don't.
Learning from a real script
Our course includes the full source code of the StructureX chart tool to learn from and customize, for example adding session shading to it. It's source code, not a ready-made trading bot.
Common mistakes
- No time zone. The session lands in the exchange's zone, which may not be yours.
- Fixed offsets like GMT-5. They ignore daylight saving.
- Daily charts. Sessions inside a day need an intraday chart.
- Too-big candles. A 1-hour candle can't show a 30-minute range.
- Showing the range before it ends. The lines move until the range closes.
Questions
How do I check if a candle is in a session in Pine Script?
Use not na(time(timeframe.period, "0930-1600", "America/New_York")). It's true inside the session and false outside.
How do I mark the opening range in Pine Script?
Track the high and low with var variables during the first minutes after the open, reset them on the first candle, and plot them once the range ends.
What time zone does Pine Script use?
By default, time() uses the exchange's time zone. Pass a named zone like "America/New_York" to be sure, and it will follow daylight saving time.
Why is my session shading an hour off?
Usually a fixed offset like "GMT-5" was used, which ignores daylight saving. Use a named zone like "America/New_York".
Want the next step? We'll walk you through it.
Four free lessons by email, one every few days — each with a 10-minute exercise on a real chart.
Send Me the Free Lessons 4 short emails · No spam · Unsubscribe anytimeOr see the whole method, step by step:
See What’s Inside the Course Try everything free first. Decide when you're ready. · Open the free chart tool (works in the TradingView phone app)One chart idea a day, in plain English. Follow along: