SPB Git

spb/wp40_uqo

Public MIT
5.3 KB · 98 lines cpp
1#include "raid/data/bar_series.hpp"2#include "raid/core/error.hpp"3#include <algorithm>4#include <numeric>5#include <cmath>67namespace raid {89nlohmann::json QualityReport::to_json() const {10  return {{"symbol", symbol}, {"n_bars", n_bars}, {"n_sessions", n_sessions}, {"ohlc_inconsistent", ohlc_inconsistent},11          {"nonpositive_price", nonpositive_price}, {"negative_volume", negative_volume}, {"zero_volume", zero_volume},12          {"duplicates", duplicates}, {"off_interval", off_interval}, {"outside_session", outside_session},13          {"non_trading_day", non_trading_day}, {"unsorted", unsorted}, {"missing_regular_bars", missing_regular_bars},14          {"price_jumps", price_jumps}, {"coverage", coverage}, {"per_session_missing", per_session_missing}, {"notes", notes}, {"has_errors", has_errors()}};15}1617BarSeries::NormalizeStats BarSeries::normalize() {18  const usize n = size();19  usize reordered = 0; bool dup = false;20  for (usize i = 1; i < n; ++i) { if (t_open[i] < t_open[i - 1]) ++reordered; else if (t_open[i] == t_open[i - 1]) dup = true; }21  if (reordered == 0 && !dup) { index_sessions(); return {0, 0}; }   // fast path: no copy22  std::vector<usize> idx(n); std::iota(idx.begin(), idx.end(), 0);23  if (reordered) std::stable_sort(idx.begin(), idx.end(), [&](usize a, usize b) { return t_open[a] < t_open[b]; });24  BarSeries out; out.symbol = symbol; out.instrument_id = instrument_id; out.interval = interval; out.adjustment = adjustment; out.reserve(n);25  usize dups = 0;26  for (usize k = 0; k < n; ++k) {27    const usize i = idx[k];28    if (!out.empty() && out.t_open.back() == t_open[i]) { ++dups; continue; }29    out.t_open.push_back(t_open[i]); out.session.push_back(session[i]); out.open.push_back(open[i]); out.high.push_back(high[i]);30    out.low.push_back(low[i]); out.close.push_back(close[i]); out.volume.push_back(volume[i]); out.flags.push_back(flags[i]);31  }32  *this = std::move(out);33  index_sessions();34  return {dups, reordered};35}3637void BarSeries::index_sessions() {38  session_offsets.clear(); session_dates.clear();39  for (usize i = 0; i < size(); ++i) {40    if (i == 0 || session[i] != session[i - 1]) { session_offsets.push_back(static_cast<i64>(i)); session_dates.push_back(session[i]); }41  }42  session_offsets.push_back(static_cast<i64>(size()));43  if (size() == 0) session_offsets = {0};44}4546QualityReport BarSeries::validate(const MarketCalendar& cal, SessionPolicy policy, f64 jump_threshold) const {47  QualityReport r; r.symbol = symbol; r.n_bars = size(); r.n_sessions = n_sessions();48  const i64 step = to_duration(interval).us;49  for (usize i = 0; i < size(); ++i) {50    if (high[i] < low[i] || high[i] < std::max(open[i], close[i]) || low[i] > std::min(open[i], close[i])) ++r.ohlc_inconsistent;51    if (!(open[i] > 0 && high[i] > 0 && low[i] > 0 && close[i] > 0)) ++r.nonpositive_price;52    if (volume[i] < 0) ++r.negative_volume;53    if (volume[i] == 0) ++r.zero_volume;54    if (i > 0 && t_open[i] <= t_open[i - 1]) ++r.unsorted;55    if (interval != Interval::d1 && (t_open[i].us % step) != 0) ++r.off_interval;56  }57  usize expected_total = 0, present_total = 0;58  for (usize k = 0; k < n_sessions(); ++k) {59    const Date d = session_dates[k];60    if (!cal.is_trading_day(d)) { r.non_trading_day += static_cast<usize>(session_offsets[k + 1] - session_offsets[k]); continue; }61    const auto sb = cal.session(d);62    usize present = 0;63    f64 prev_close = -1;64    for (i64 i = session_offsets[k]; i < session_offsets[k + 1]; ++i) {65      const auto t = t_open[static_cast<usize>(i)];66      const bool regular = t >= sb.open_utc && t <= sb.close_utc;67      const bool extended = t >= sb.ext_open_utc && t < sb.ext_close_utc;68      if (policy == SessionPolicy::regular ? !regular : !extended) ++r.outside_session;69      if (regular) ++present;70      if (prev_close > 0 && std::abs(close[static_cast<usize>(i)] / prev_close - 1.0) > jump_threshold) ++r.price_jumps;71      prev_close = close[static_cast<usize>(i)];72    }73    const usize expected = cal.expected_regular_bars(d, interval);74    expected_total += expected; present_total += std::min(present, expected);75    if (present < expected) { r.missing_regular_bars += expected - present; r.per_session_missing[d.iso()] = expected - present; }76  }77  r.coverage = expected_total ? static_cast<f64>(present_total) / static_cast<f64>(expected_total) : 1.0;78  return r;79}8081BarSeries BarSeries::filter_session(const MarketCalendar& cal, SessionPolicy policy) const {82  BarSeries out; out.symbol = symbol; out.instrument_id = instrument_id; out.interval = interval; out.adjustment = adjustment; out.reserve(size());83  for (usize k = 0; k < n_sessions(); ++k) {84    const Date d = session_dates[k];85    if (!cal.is_trading_day(d)) continue;86    const auto sb = cal.session(d);87    for (i64 i = session_offsets[k]; i < session_offsets[k + 1]; ++i) {88      const usize j = static_cast<usize>(i); const auto t = t_open[j];89      const bool keep = policy == SessionPolicy::regular ? (t >= sb.open_utc && t <= sb.close_utc) : (t >= sb.ext_open_utc && t < sb.ext_close_utc);90      if (keep) { out.t_open.push_back(t); out.session.push_back(session[j]); out.open.push_back(open[j]); out.high.push_back(high[j]); out.low.push_back(low[j]); out.close.push_back(close[j]); out.volume.push_back(volume[j]); out.flags.push_back(flags[j]); }91    }92  }93  out.index_sessions();94  return out;95}9697}  // namespace raid98
Files · v0.1.0-wp40
Menu

Theme