73 throw std::invalid_argument(
74 "CoordinateNormalizer: window must be >= 2, got " +
90 const double old_val = buf_[pos_];
92 pos_ = (pos_ + 1u) % window_;
94 if (count_ < window_) {
97 const double delta = close - mean_;
98 mean_ += delta /
static_cast<double>(count_);
99 const double delta2 = close - mean_;
100 m2_ += delta * delta2;
103 const double old_mean = mean_;
104 mean_ += (close - old_val) /
static_cast<double>(window_);
105 m2_ += (close - old_val) * (close - mean_ + old_val - old_mean);
107 if (m2_ < 0.0) m2_ = 0.0;
120 [[nodiscard]]
double normalise(
double close)
const noexcept {
121 if (count_ < window_)
return 0.0;
122 const double variance = m2_ /
static_cast<double>(window_ - 1);
123 const double sigma = std::sqrt(variance);
124 if (
sigma < 1e-15)
return 0.0;
125 return (close - mean_) /
sigma;
131 [[nodiscard]]
double mean() const noexcept {
return mean_; }
134 [[nodiscard]]
double sigma() const noexcept {
135 if (count_ < window_)
return 0.0;
136 const double v = m2_ /
static_cast<double>(window_ - 1);
137 return v < 0.0 ? 0.0 : std::sqrt(v);
141 [[nodiscard]] std::size_t
count() const noexcept {
return count_; }
144 [[nodiscard]]
bool warmed_up() const noexcept {
return count_ >= window_; }
147 [[nodiscard]] std::size_t
window() const noexcept {
return window_; }
157 std::fill(buf_.begin(), buf_.end(), 0.0);
166 std::vector<double> buf_;
168 std::size_t count_{0};
Rolling z-score normaliser using Welford's online algorithm.
double mean() const noexcept
Rolling mean of the window. 0.0 if window not yet full.
std::size_t window() const noexcept
Configured window size.
std::size_t count() const noexcept
Number of ticks seen so far (saturates at window size).
bool warmed_up() const noexcept
Whether the window has been filled at least once.
double sigma() const noexcept
Rolling sample standard deviation. 0.0 if window not yet full.
void reset() noexcept
Reset all state as if no ticks have been seen.
CoordinateNormalizer(std::size_t window)
Construct with a given rolling window size.
double normalise(double close) const noexcept
Return the z-score of value relative to the current window.
void update(double close) noexcept
Ingest one new close price into the rolling window.