/** * Session segments, countdowns and multi-session helpers. * * The base MarketClock answers "open / pre-open / closed". These pure functions * add the richer model: distinct **segments** (pre-open · regular · post · * closed), the next segment change, half-day / early-close awareness, and the * next N trading sessions — all DST-correct via the same tz helpers. * * Every function is a pure function of `(spec, instant)` so results are fully * deterministic for a fixed instant, regardless of the host clock or timezone. */ /** A distinct trading-day segment. */ type Segment = "pre-open" | "regular" | "post" | "closed"; /** A single trading session (regular hours), half-day adjusted. */ interface SessionWindow { /** "YYYY-MM-DD" exchange-local date. */ date: string; /** Regular-session open instant. */ open: Date; /** Regular-session close instant (early on a half-day). */ close: Date; /** True when this date is an early-close / half-day session. */ halfDay: boolean; } /** The next segment boundary: the segment that begins at `at`. */ interface SegmentChange { segment: Segment; at: Date; } /** Is the date a full-day exchange holiday? */ declare function isHoliday(spec: ExchangeSpec, date?: Date): boolean; /** A day the exchange trades (not weekend, not a full-day holiday). Half-days count. */ declare function isTradingDay(spec: ExchangeSpec, date?: Date): boolean; /** Is the date an early-close / half-day trading session? */ declare function isHalfDay(spec: ExchangeSpec, date?: Date): boolean; /** The segment the market is in at `at`. */ declare function currentSegment(spec: ExchangeSpec, at?: Date): Segment; /** The next moment the current segment changes, strictly after `at`. */ declare function nextSegmentChange(spec: ExchangeSpec, at?: Date): SegmentChange; /** The next regular-session open instant strictly after `from` (half-day aware). */ declare function nextOpenAt(spec: ExchangeSpec, from?: Date): Date; /** The next regular-session close instant strictly after `from` (half-day aware). */ declare function nextCloseAt(spec: ExchangeSpec, from?: Date): Date; /** Milliseconds until the next regular open (always > 0). */ declare function timeUntilOpen(spec: ExchangeSpec, now?: Date): number; /** Milliseconds until the next regular close (always > 0; early on a half-day). */ declare function timeUntilClose(spec: ExchangeSpec, now?: Date): number; /** * The next `n` trading sessions at/after `now`, skipping weekends, holidays and * honouring half-day early closes. A session already underway (close still in * the future) is included as the first entry. */ declare function nextSessions(spec: ExchangeSpec, now?: Date, n?: number): SessionWindow[]; /** * All trading sessions whose open instant falls within `[a, b)`. Returns `[]` * when `b <= a`. */ declare function sessionsBetween(spec: ExchangeSpec, a: Date, b: Date): SessionWindow[]; /** * Built-in exchange presets. * * Ready-made `ExchangeSpec`s for common exchanges. No-DST exchanges (IST/JST/ * HKT/SGT) use an exact fixed `offsetMinutes`; DST exchanges (US/UK) use an IANA * `timeZone` so open/close stay correct across daylight-saving transitions. * * Bundled holiday lists are hand-maintained and cover 2025–2026 nationally-fixed * observances only — verify and extend from the official exchange circular: * `new MarketClock({ ...NYSE, holidays: [...NYSE.holidays, "2027-..."] })`. * * Lunch breaks (TSE, HKEX) are NOT modelled — the single regular window spans * the whole trading day. Use a custom spec if intraday breaks matter to you. */ /** New York Stock Exchange. Pre-market 04:00, regular 09:30–16:00, after 16:00–20:00 ET. */ declare const NYSE: ExchangeSpec; /** NASDAQ — same sessions and calendar as NYSE. */ declare const NASDAQ: ExchangeSpec; /** London Stock Exchange. Opening auction 07:50, regular 08:00–16:30 London time. */ declare const LSE: ExchangeSpec; /** * Tokyo Stock Exchange (JST, no DST — exact offset). Regular 09:00–15:00. * Note: the 11:30–12:30 lunch break is NOT modelled. */ declare const TSE: ExchangeSpec; /** * Hong Kong Exchange (HKT, no DST — exact offset). Regular 09:30–16:00. * Note: the 12:00–13:00 lunch break is NOT modelled. */ declare const HKEX: ExchangeSpec; /** Singapore Exchange (SGT, no DST — exact offset). Pre-open 08:30, regular 09:00–17:00. */ declare const SGX: ExchangeSpec; /** * Nepal Stock Exchange. Trades Sunday–Thursday (Friday and Saturday closed), * pre-open 10:30–10:45, regular 11:00–15:00 NPT (UTC+05:45, no DST). * * Holidays: Nepal's public holidays follow the Bikram Sambat / lunar calendar and are * announced by the government and NEPSE each year, so none are bundled. Add your * own list (e.g. loaded from your DB) with `withHolidays(NEPSE, ["2026-10-20", …])`. * @since 1.2.0 */ declare const NEPSE: ExchangeSpec; /** * A copy of `spec` with extra holidays (and optional half-days) merged in — for * exchanges whose calendar you maintain yourself. Dates are "YYYY-MM-DD" exchange-local. * @since 1.2.0 */ declare function withHolidays(spec: ExchangeSpec, holidays: string[], halfDays?: ExchangeSpec["halfDays"]): ExchangeSpec; /** * @lacspace/market-clock * Is the market open right now? When does it next open / close? * * A holiday-aware, timezone-correct trading clock for stock exchanges. Ships * with NSE / BSE (India) presets — India has no DST, so a fixed IST offset is * exact. Bring your own exchange spec or override the holiday list any time. * * Note: the bundled holiday lists are hand-maintained and only cover the years * listed. Extend them per year from the official exchange circular (e.g. * `new MarketClock({ ...NSE, holidays: [...NSE.holidays, "2027-..."] })`). * * Zero dependencies · isomorphic · fully typed. */ interface Session { /** "HH:MM" 24-hour, in exchange-local time. */ open: string; close: string; } /** An early-close / half-day override for a single date. */ interface HalfDay { /** "HH:MM" early close in exchange-local time (e.g. "13:00"). */ close: string; /** Optional early/late open; defaults to the regular open. */ open?: string; } interface ExchangeSpec { name: string; /** Minutes ahead of UTC (IST = +330). Exchanges without DST only. */ offsetMinutes: number; regular: Session; preOpen?: Session; /** * Post-market / after-hours session (optional). Enables the "post" segment. * @since 1.1.0 */ postClose?: Session; /** * IANA timezone (e.g. "America/New_York"). When set it is DST-correct via * `Intl` and takes precedence over `offsetMinutes`. Omit for no-DST exchanges. * @since 1.1.0 */ timeZone?: string; /** * Early-close / half-day overrides, keyed by "YYYY-MM-DD" exchange-local date. * @since 1.1.0 */ halfDays?: Record; /** Weekday numbers that are always closed (0 = Sunday … 6 = Saturday). */ weekend: number[]; /** Full-day holidays as "YYYY-MM-DD" in exchange-local dates. */ holidays: string[]; } type MarketStatus = "pre-open" | "open" | "closed"; declare class MarketClock { readonly spec: ExchangeSpec; private readonly regOpen; private readonly regClose; private readonly preOpen; private readonly preClose; constructor(spec: ExchangeSpec); /** Exchange-local calendar parts for an instant. */ private parts; /** UTC epoch millis for an exchange-local calendar day + minute-of-day. */ private utcFor; private isoDate; isWeekend(at?: Date): boolean; isHoliday(at?: Date): boolean; /** A day the exchange trades (not weekend, not a holiday). */ isTradingDay(at?: Date): boolean; isOpen(at?: Date): boolean; isPreOpen(at?: Date): boolean; status(at?: Date): MarketStatus; /** The next moment the regular session opens, strictly after `from`. */ nextOpen(from?: Date): Date; /** The next moment the regular session closes, strictly after `from`. */ nextClose(from?: Date): Date; /** Milliseconds until the session closes, or 0 if not currently open. */ msToClose(at?: Date): number; /** Milliseconds until the next open, or 0 if already open. */ msToOpen(at?: Date): number; /** Is `at` an early-close / half-day trading session? @since 1.1.0 */ isHalfDay(at?: Date): boolean; /** The distinct segment at `at`: pre-open · regular · post · closed. @since 1.1.0 */ currentSegment(at?: Date): Segment; /** The next segment boundary strictly after `at`. @since 1.1.0 */ nextSegmentChange(at?: Date): SegmentChange; /** Milliseconds until the next regular open (always > 0). @since 1.1.0 */ timeUntilOpen(now?: Date): number; /** Milliseconds until the next regular close (early on a half-day). @since 1.1.0 */ timeUntilClose(now?: Date): number; /** The next `n` trading sessions at/after `now` (skips weekends/holidays). @since 1.1.0 */ nextSessions(now?: Date, n?: number): SessionWindow[]; /** All trading sessions whose open falls within `[a, b)`. @since 1.1.0 */ sessionsBetween(a: Date, b: Date): SessionWindow[]; } declare function createClock(spec: ExchangeSpec): MarketClock; /** National Stock Exchange of India. Pre-open 09:00–09:15, regular 09:15–15:30 IST. */ declare const NSE: ExchangeSpec; /** Bombay Stock Exchange — same session timings and holiday calendar as NSE. */ declare const BSE: ExchangeSpec; /** All built-in exchange presets, keyed by name. @since 1.1.0 */ declare const PRESETS: { readonly NSE: ExchangeSpec; readonly BSE: ExchangeSpec; readonly NYSE: ExchangeSpec; readonly NASDAQ: ExchangeSpec; readonly LSE: ExchangeSpec; readonly TSE: ExchangeSpec; readonly HKEX: ExchangeSpec; readonly SGX: ExchangeSpec; readonly NEPSE: ExchangeSpec; }; /** Union of built-in preset keys. @since 1.1.0 */ type PresetName = keyof typeof PRESETS; export { BSE, type ExchangeSpec, HKEX, type HalfDay, LSE, MarketClock, type MarketStatus, NASDAQ, NEPSE, NSE, NYSE, PRESETS, type PresetName, SGX, type Segment, type SegmentChange, type Session, type SessionWindow, TSE, createClock, currentSegment, isHalfDay, isHoliday, isTradingDay, nextCloseAt, nextOpenAt, nextSegmentChange, nextSessions, sessionsBetween, timeUntilClose, timeUntilOpen, withHolidays };