// BarSeries — OHLCV bars for one instrument (columnar), with session structure derived from the MarketCalendar. #pragma once #include #include #include #include "raid/core/types.hpp" #include "raid/data/calendar.hpp" #include "raid/data/quality.hpp" namespace raid { struct BarSeries { std::string symbol; std::string instrument_id; Interval interval{Interval::m1}; std::string adjustment{"raw"}; std::vector t_open; // bar OPEN, UTC std::vector session; // exchange-local session date std::vector open, high, low, close, volume; std::vector flags; // bitmask (see QualityFlag) // Session index: session_offsets[k]..session_offsets[k+1] are the bars of session k (built by index_sessions()). std::vector session_offsets; std::vector session_dates; usize size() const { return close.size(); } bool empty() const { return close.empty(); } void reserve(usize n) { t_open.reserve(n); session.reserve(n); open.reserve(n); high.reserve(n); low.reserve(n); close.reserve(n); volume.reserve(n); flags.reserve(n); } void push_back(Timestamp t, f64 o, f64 h, f64 l, f64 c, f64 v, u32 f = 0) { t_open.push_back(t); session.push_back(MarketCalendar::session_of(t)); open.push_back(o); high.push_back(h); low.push_back(l); close.push_back(c); volume.push_back(v); flags.push_back(f); } usize n_sessions() const { return session_dates.size(); } std::span session_closes(usize k) const { return std::span(close).subspan(static_cast(session_offsets[k]), static_cast(session_offsets[k + 1] - session_offsets[k])); } std::span session_times(usize k) const { return std::span(t_open).subspan(static_cast(session_offsets[k]), static_cast(session_offsets[k + 1] - session_offsets[k])); } /// Sorts by time, drops exact duplicate timestamps (keeps the first), rebuilds the session index. Returns counts. struct NormalizeStats { usize duplicates_removed; usize reordered; }; NormalizeStats normalize(); void index_sessions(); /// Validates OHLCV, interval grid, session membership and coverage; does not modify data. QualityReport validate(const MarketCalendar& cal, SessionPolicy policy = SessionPolicy::regular, f64 jump_threshold = 0.25) const; /// Keeps only bars of the requested session policy (regular: 09:30 ≤ open ≤ close time, i.e. includes the 16:00 print). BarSeries filter_session(const MarketCalendar& cal, SessionPolicy policy) const; }; enum QualityFlag : u32 { kFlagOhlcInconsistent = 1u << 0, kFlagNonpositivePrice = 1u << 1, kFlagNegativeVolume = 1u << 2, kFlagZeroVolume = 1u << 3, kFlagOffInterval = 1u << 4, kFlagOutsideSession = 1u << 5, kFlagNonTradingDay = 1u << 6, kFlagPriceJump = 1u << 7, kFlagVendorFlag = 1u << 8, }; } // namespace raid