30namespace rolling_detail {
34 std::size_t count_{0};
41 result.count_ =
static_cast<std::size_t
>(parts.present_.segment(first, length).sum());
42 result.sum_ = parts.values_.segment(first, length).sum();
48 bool reported_{
false};
49 std::size_t count_{0};
69inline Dispersion dispersion(
70 const math::Observed& parts,
76 const auto reduced = reduce(parts, first, length);
77 result.count_ = reduced.count_;
78 if (reduced.count_ < needed || reduced.count_ < 2) {
81 result.mean_ = reduced.sum_ /
static_cast<Scalar>(reduced.count_);
82 const Scalar squared = (parts.values_.segment(first, length) -
83 result.mean_ * parts.present_.segment(first, length)).squaredNorm();
84 result.deviation_ = std::sqrt(squared /
static_cast<Scalar>(reduced.count_ - 1));
85 result.reported_ =
true;
96inline void check(std::size_t window, std::size_t min_observed) {
98 throw std::invalid_argument(
"rolling window must be at least one row");
100 if (min_observed == 0) {
101 throw std::invalid_argument(
"a window must require at least one observation");
103 if (min_observed > window) {
104 throw std::invalid_argument(
105 "rolling window of " + std::to_string(window) +
" rows cannot hold " +
106 std::to_string(min_observed) +
" observations"
113 const auto span =
static_cast<math::Index>(window);
114 return row + 1 >= span ? row + 1 - span :
math::Index{0};
131 std::size_t min_observed
133 rolling_detail::check(window, min_observed);
136 for (
math::Index row = 0; row < values.size(); ++row) {
137 const math::Index first = rolling_detail::window_start(row, window);
138 const auto reduced = rolling_detail::reduce(parts, first, row - first + 1);
139 if (reduced.count_ >= min_observed) {
140 result[row] = reduced.sum_;
172 std::size_t min_observed
174 rolling_detail::check(window, min_observed);
177 for (
math::Index row = 0; row < values.size(); ++row) {
178 const math::Index first = rolling_detail::window_start(row, window);
179 const auto reduced = rolling_detail::reduce(parts, first, row - first + 1);
180 if (reduced.count_ >= min_observed) {
181 result[row] = reduced.sum_ /
static_cast<Scalar>(reduced.count_);
214 std::size_t min_observed
216 rolling_detail::check(window, min_observed);
219 for (
math::Index row = 0; row < values.size(); ++row) {
220 const math::Index first = rolling_detail::window_start(row, window);
222 rolling_detail::dispersion(parts, first, row - first + 1, min_observed);
223 if (spread.reported_) {
224 result[row] = spread.deviation_;
255 std::size_t min_observed
257 rolling_detail::check(window, min_observed);
264 for (
math::Index row = 0; row < values.size(); ++row) {
265 const math::Index first = rolling_detail::window_start(row, window);
267 if (parts.present_.segment(first, length).sum() >=
static_cast<Scalar>(min_observed)) {
268 result[row] = ceiling.segment(first, length).minCoeff();
298 std::size_t min_observed
300 rolling_detail::check(window, min_observed);
305 for (
math::Index row = 0; row < values.size(); ++row) {
306 const math::Index first = rolling_detail::window_start(row, window);
308 if (parts.present_.segment(first, length).sum() >=
static_cast<Scalar>(min_observed)) {
309 result[row] = floor.segment(first, length).maxCoeff();
367 std::size_t min_observed
369 rolling_detail::check(window, min_observed);
372 for (
math::Index at = 0; at < weights.size(); ++at) {
373 weights[at] =
static_cast<Scalar>(at + 1);
377 for (
math::Index row = 0; row < values.size(); ++row) {
378 const math::Index first = rolling_detail::window_start(row, window);
380 if (parts.present_.segment(first, length).sum() <
static_cast<Scalar>(min_observed)) {
383 const auto used = weights.head(length);
384 const Scalar divisor = parts.present_.segment(first, length).dot(used);
385 if (divisor >
Scalar{0}) {
386 result[row] = parts.values_.segment(first, length).dot(used) / divisor;
401 return wma(values, window, window);
417 throw std::invalid_argument(
"an ema span must be at least one row");
422namespace rolling_detail {
425inline void check_alpha(
Scalar alpha) {
427 throw std::invalid_argument(
"an ema smoothing factor must be in (0, 1]");
451 rolling_detail::check_alpha(alpha);
455 return observed(level) ? level + alpha * (value - level) : value;
485 rolling_detail::check_alpha(alpha);
486 if (min_observed == 0) {
487 throw std::invalid_argument(
"ema must require at least one observation");
491 std::size_t count = 0;
492 for (
math::Index row = 0; row < values.size(); ++row) {
493 const Scalar value = values[row];
499 level = count == 0 ? value : level + alpha * (value - level);
501 if (count >= min_observed) {
Returns, rolling statistics, indicators and performance metrics over numeric series.
math::Vector wma(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the linearly weighted moving average.
math::Vector rolling_mean(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the trailing mean of the observed values.
bool observed(Scalar value)
Tests whether a value is an observation; see math::observed.
math::Vector rolling_min(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the trailing minimum of the observed values.
Scalar alpha_from_span(std::size_t span)
Converts an EMA span to its smoothing factor, 2 / (span + 1).
math::Vector rolling_stdev(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the trailing sample standard deviation (divisor count - 1).
math::Vector sma(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the simple moving average; identical to rolling_mean.
math::Vector ema(math::SeriesView values, Scalar alpha, std::size_t min_observed=1)
Computes the exponentially weighted moving average of a series.
math::Vector rolling_max(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the trailing maximum of the observed values.
Scalar ema_step(Scalar level, Scalar value, Scalar alpha)
Advances an exponential moving average by one value.
math::Vector rolling_sum(math::SeriesView values, std::size_t window, std::size_t min_observed)
Computes the trailing sum of the observed values.
Observed observed_parts(SeriesView values)
Splits a series into zero-filled values and a presence mask.
double Scalar
The floating-point type the analytics and math layers compute in (double).
Eigen::Index Index
The signed index type of rows and columns.
Vector unobserved(std::size_t count)
Makes a vector filled with missing().
Vector observed_or(SeriesView values, Scalar filler)
Replaces every unobserved entry of a series.
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > Vector
A dense column vector of Scalar.
Eigen::Ref< const Vector > SeriesView
A read-only reference to one series.
The library: broker-neutral types (core), and the modules below.
Re-exports math::Scalar, math::missing and math::observed into analytics.