Skip to main content

Session Filtering

The session filter wraps a MarketDataFeed so history and realtime bars outside the included session states are dropped before they reach the chart. The built-in period-bar toggle covers the common regular-hours / extended-hours workflow, but the native filter is not limited to those two states. Any session window state emitted by your calendar can be included, such as opening-auction, lunch-break, cash-afternoon, overnight, or venue-specific auction phases.

Before you start

Session filtering requires a session calendar. Declare one first — see Session Schedules.

How a bar is included

Every history and realtime bar passes the same test. The calendar owns the boundaries; the filter only compares.

Filtering is strict: a bar is kept only when it falls inside a calendar window whose state is in include. Bars in time the calendar does not cover are dropped, so an incomplete calendar shows up immediately instead of silently passing extended-hours data through. The filter applies to both loadBars history and subscribeRealTimeBars streams; quotes, depth, and other feed methods pass through untouched.

The three configurations below are alternatives. Pick the one that matches the market phases your product exposes.

Regular hours only (default)

const feed = createSessionFilterDatafeed(cached); // defaults to include: ['regular']
  • Timezone: owned by the schedule spec (for US_EQUITIES_SESSION_SCHEDULE, America/New_York); the compiler emits epoch-ms boundaries, so DST is already handled.
  • Boundary ownership: the calendar's regular windows — 09:30–16:00 NY for US equities. The filter never invents or shifts boundaries.
  • Expected bars: on a 1m chart, the first kept bar of a normal day is 09:30 and the last is 15:59 NY time; pre/post-market bars never render.
  • Verification: the intraday chart starts at 09:30 with a session break line between days, and the period-bar toggle reads Regular Hours.

Extended hours

feed.setSessionMode('extended'); // include = EXTENDED_SESSION_STATES
  • Timezone: same calendar, same America/New_York spec — no separate configuration.
  • Boundary ownership: the calendar's pre-market, regular, and post-market windows (04:00–20:00 NY for the US equities preset).
  • Expected bars: bars appear from 04:00 through 19:59 NY. Flipping regular ⇄ extended re-renders from the cache without re-downloading when the filter wraps createCachingDatafeed.
  • Verification: toggling the period-bar control (or calling setSessionMode) refetches the visible series in place and pre/post-market shading appears on intraday resolutions.

3. Custom market phases

feed.setSessionVisibility({
include: ['opening-auction', 'cash-afternoon', 'closing-auction'],
});
  • Timezone: your custom schedule's IANA timezone; custom state ids mean whatever your calendar says they mean — the filter never reinterprets them.
  • Boundary ownership: the custom windows your calendar emits for those state ids.
  • Expected bars: only bars inside windows whose state is one of the three included ids; everything else, including uncovered time, is dropped.
  • Verification: feed.getSessionMode() returns 'custom', and the built-in regular/extended toggle is hidden so custom phases are never mislabeled as extended hours.

Wrapping a feed

import {
createCachingDatafeed,
createSessionFilterDatafeed,
createSessionCalendarProvider,
US_EQUITIES_SESSION_SCHEDULE,
} from '@tradescript/pro/sdk';

const rawFeed = createMyDatafeed(); // implements resolveSessionCalendar, or pass options.sessionCalendar
const cached = createCachingDatafeed(rawFeed, { policy: 'memory' });
const feed = createSessionFilterDatafeed(cached); // defaults to regular hours only

Compose the filter around createCachingDatafeed, in that order: the cache keeps the complete series and only the presentation is filtered, so flipping between regular and extended hours never re-downloads data.

export interface SessionFilterOptions {
include?: readonly SessionState[]; // custom window states are allowed; defaults to ['regular']
sessionCalendar?: SessionAggregationCalendar | SessionAggregationCalendarProvider;
enabled?: boolean; // start transparent when false; switchable at runtime
}

SessionState includes built-in values (pre-market, regular, post-market, closed, holiday, halted) and custom string ids. The filter does not reinterpret custom ids; your calendar owns their meaning.

Switching sessions at runtime

createSessionFilterDatafeed returns a SessionFilterDatafeed with an in-place switching surface:

export interface SessionFilterDatafeed extends MarketDataFeed {
getSessionVisibility(): SessionVisibility; // { enabled, include }
setSessionVisibility(patch: Partial<SessionVisibility>): void; // no-op patches do not notify
getSessionMode(): 'regular' | 'extended' | 'custom';
setSessionMode(mode: 'regular' | 'extended'): void;
subscribeSessionVisibility(cb: (v: SessionVisibility) => void): Unsubscribe;
}

setSessionMode('regular') filters down to ['regular']; setSessionMode('extended') shows the full trading day (EXTENDED_SESSION_STATES — pre-market, regular, post-market). For finer control, patch the include set directly:

feed.setSessionVisibility({ include: ['regular', 'post-market'] });
feed.setSessionVisibility({ include: ['opening-auction', 'cash-afternoon', 'closing-auction'] });
feed.setSessionVisibility({ enabled: false }); // fully transparent, re-enable later

Changes apply immediately to subsequent history loads and to live realtime subscriptions — no resubscribe, no feed swap. Every effective change notifies subscribeSessionVisibility listeners. getSessionMode() returns custom whenever the include set is not exactly one of the built-in presets, including transparent mode.

isSessionFilterDatafeed(feed) type-guards any MarketDataFeed back to the switching surface.

What the chart surface does automatically

When the datafeed passed to TradeScriptChartSurface (or the widgets built on it) is a session filter feed:

  • A session toggle appears in the period bar — Regular Hours ⇄ Extended Hours — wired to setSessionMode.
  • On any visibility change (from the toggle or from your own setSessionMode call), the chart refetches the visible series in place.
  • Symbol resolution receives SymbolResolveContext.sessionVisibility on every session refetch. When the active visibility is a single exact state, such as opening-auction, the same value is also sent as sessionId so session-scoped feeds can route without decoding a multi-state policy object.
  • While the chart shows regular hours only, the extended-hours price line tracks the live pre/post-market quote (see below).

Set an initial display preset through native chart state when the chart should mount directly into extended hours:

initialState: {
displaySettings: {
sessionVisibilityMode: 'extended',
},
}

This setting applies only when the active feed is a SessionFilterDatafeed. It calls the same native setSessionMode path as the built-in toggle, so session-scoped feeds can re-resolve and reload through their normal feed contract.

For custom markets, pass exact native visibility instead:

initialState: {
displaySettings: {
sessionVisibility: {
enabled: true,
include: ['opening-auction', 'cash-afternoon', 'closing-auction'],
},
},
}

The built-in regular/extended toggle is shown only when the filter is in a regular or extended preset. Custom visibility remains host-controlled through setSessionVisibility(...), so the chart does not mislabel custom market phases as extended hours.

Both behaviors are controlled by the sessions chart feature:

features: {
sessions: {
modeSelector: true, // period-bar toggle; default true
extendedHoursPriceLine: true, // quote line while extended hours are hidden; default true
},
}
// or sessions: false to disable both

Extended-hours price line

A filtered session still has a price, and hiding its bars should not hide that price. When the filter conceals a tradable state and the quote timestamp falls inside that hidden window, the surface subscribes to the feed's quotes — getQuotes and subscribeQuotes both bypass the filter — and renders the hidden-session price as a dashed horizontal line. Built-in labels look like Pre-market 187.23 / Post-market 187.23; custom native states derive readable labels such as Opening Auction 187.23 without reclassifying the state. The line prefers extendedLast, falls back to last, updates with each quote, and disappears when the quote moves into a visible session, a closed/holiday/halted window, or a quote with no finite extended/last price. Set ChartDisplaySettings.showPrePostMarketPriceLabel: false to keep the line while hiding that right-side label.

The line requires the feed to implement getQuotes or subscribeQuotes; without quote support the feature is inert.

Session background shading

Independent of filtering, charts with a session calendar shade intraday charts by session window and draw break lines at schedule gaps. The colors are user-configurable in the chart settings dialog and default to:

  • sessionBackground.show — toggle, default on
  • sessionBackground.premarket.color
  • sessionBackground.premarket.opacity
  • sessionBackground.regular.color
  • sessionBackground.regular.opacity
  • sessionBackground.afterhours.color
  • sessionBackground.afterhours.opacity
  • sessionBackground.stateColors.<state>.color — optional per-state override for any built-in or custom calendar state id
  • sessionBackground.stateColors.<state>.opacity — optional per-state fill opacity from 0 to 1

SDK display settings expose the same broader native capability as ChartDisplaySettings.sessionStateBackgroundColors, a state-id to color map:

chart.setDisplaySettings({
sessionStateBackgroundColors: {
'opening-auction': 'rgba(234, 179, 8, 0.14)',
'cash-afternoon': 'rgba(14, 165, 233, 0.10)',
halted: 'rgba(239, 68, 68, 0.12)',
},
});

Explicit state colors override the built-in pre-market / regular / after-hours buckets for matching ids. Custom or inactive states without an explicit color are left unshaded; they are never reclassified into another session bucket.

Use chart.customization().applyOverrides({ sessions: ... }) when you need separate color and opacity controls per native session state. ChartDisplaySettings.sessionStateBackgroundColors remains the compact color-only display setting for hosts that already encode alpha in CSS color strings.

Shading only renders on second/minute resolutions up to 30 minutes, where session boundaries are meaningful at bar scale.

Putting it together

const feed = createSessionFilterDatafeed(
createCachingDatafeed(rawFeed, { policy: 'memory' }),
{ include: ['regular'] } // start in regular hours
);

<TradeScriptWidget datafeed={feed} /* ... */ />

// Programmatic switch — the chart refetches on its own:
feed.setSessionMode('extended');
feed.setSessionVisibility({ include: ['opening-auction', 'cash-afternoon'] });

Next steps