1// MarketCalendar — XNYS (NYSE/Nasdaq) trading days, early closes, regular-session bounds and America/New_York DST.2// Rules are computed (no external data): NYSE holiday rules since 2000, special closures listed explicitly,3// US DST rules (2007+: 2nd Sunday March → 1st Sunday November; 1987–2006: 1st Sunday April → last Sunday October).4// Validation: tests/reference/calendar_vs_exchange_calendars.cpp compares against the Python exchange_calendars fixture.5#pragma once6#include <vector>7#include <string>8#include <optional>9#include "raid/core/types.hpp"1011namespace raid {1213struct SessionBounds {14 Date session;15 Timestamp open_utc; // 09:30 ET16 Timestamp close_utc; // 16:00 ET (13:00 on early closes) — the close bar OPENS at this instant (closing print)17 Timestamp ext_open_utc; // 04:00 ET18 Timestamp ext_close_utc; // 20:00 ET (bars open until 19:59). On early-close days the vendor stops at 17:00.19 bool early_close{false};20 i64 utc_offset_seconds{0}; // ET offset that day at the open (−18000 EST / −14400 EDT)21};2223class MarketCalendar {24 public:25 enum class Market { XNYS };26 explicit MarketCalendar(Market m = Market::XNYS) : market_(m) {}27 Market market() const { return market_; }2829 bool is_trading_day(Date d) const;30 bool is_early_close(Date d) const;31 std::optional<std::string> holiday_name(Date d) const;32 /// Session bounds for a trading day (throws if not a trading day).33 SessionBounds session(Date d) const;34 /// Regular-hours bars expected for one session at the given interval (1m: 391 normal, 211 early close).35 usize expected_regular_bars(Date d, Interval iv) const;36 /// Trading sessions in [start, end] inclusive.37 std::vector<Date> sessions(Date start, Date end) const;38 /// Next / previous trading day strictly after / before d.39 Date next_session(Date d) const;40 Date previous_session(Date d) const;41 /// America/New_York offset (seconds east of UTC) at a UTC instant.42 static i64 new_york_offset(Timestamp utc);43 /// Local New York civil date and minute-of-day of a UTC instant.44 struct Local { Date date; int minute_of_day; i64 offset_seconds; };45 static Local to_new_york(Timestamp utc);46 /// UTC instant of a New York wall-clock time (assumes the time exists; gap hour maps to post-transition).47 static Timestamp from_new_york(Date d, int minute_of_day);48 /// Session date of a bar-open timestamp under the US equity convention (04:00–20:00 ET same civil day).49 static Date session_of(Timestamp bar_open_utc) { return to_new_york(bar_open_utc).date; }5051 private:52 Market market_;53};5455/// Convenience: trading-day distance between two sessions (number of sessions strictly between + 1).56usize trading_days_between(const MarketCalendar& cal, Date a, Date b);5758} // namespace raid59