/// @module std::finance::indicators::moving_averages
/// Moving Averages - Optimized with Vector Intrinsics
/// High-performance moving average implementations using SIMD vector operations
from std::core::utils::rolling use { rolling_mean, rolling_sum, linear_recurrence }
/// Compute the simple moving average over `period`.
///
/// @see std::core::utils::rolling::rolling_mean
pub @warmup(period) fn sma(series, period) {
rolling_mean(series, period)
}
/// Compute the exponential moving average over `period`.
///
/// Implemented as the linear recurrence
/// `EMA[t] = (1 - alpha) * EMA[t-1] + alpha * series[t]`.
///
/// @see std::core::utils::rolling::linear_recurrence
pub @warmup(period * 3) fn ema(series, period) {
let alpha = 2.0 / (period + 1);
let decay = 1.0 - alpha;
// Scale input by alpha
let input = __intrinsic_vec_mul(series, alpha);
// Use first value of series as initial value for recurrence
let init = series[0];
linear_recurrence(input, decay, init)
}
/// Compute the double exponential moving average.
///
/// @see std::finance::indicators::moving_averages::ema
pub @warmup(period * 3) fn dema(series, period) {
let ema1 = ema(series, period);
let ema2 = ema(ema1, period);
2 * ema1 - ema2
}
/// Compute the triple exponential moving average.
///
/// @see std::finance::indicators::moving_averages::ema
pub @warmup(period * 3) fn tema(series, period) {
let ema1 = ema(series, period);
let ema2 = ema(ema1, period);
let ema3 = ema(ema2, period);
3 * ema1 - 3 * ema2 + ema3
}
/// Compute the linearly weighted moving average over `period`.
pub @warmup(period) fn wma(series, period) {
let len = series.length();
let result = [];
let denom = period * (period + 1) / 2;
// Loop implementation for correctness
for i in 0..len {
if i < period - 1 {
result.push(NaN);
} else {
let sum = 0.0;
for j in 0..period {
// Weight: period, period-1, ... 1
let weight = period - j;
let val = series[i - j];
sum = sum + val * weight;
}
result.push(sum / denom);
}
}
result
}
/// Compute the volume-weighted moving average.
pub @warmup(period) fn vwma(price, volume, period) {
let pv = price * volume;
let pv_sum = rolling_sum(pv, period);
let v_sum = rolling_sum(volume, period);
pv_sum / v_sum
}
/// Compute the Hull moving average.
///
/// @see std::finance::indicators::moving_averages::wma
pub @warmup(period) fn hma(series, period) {
let half_period = floor(period / 2);
let sqrt_period = floor(sqrt(period));
let wma_half = wma(series, half_period);
let wma_full = wma(series, period);
let raw_hma = 2 * wma_half - wma_full;
wma(raw_hma, sqrt_period)
}
/// Compute MACD, signal, and histogram series.
///
/// @see std::finance::indicators::moving_averages::ema
pub @warmup(slow_period + signal_period) fn macd(series, fast_period = 12, slow_period = 26, signal_period = 9) {
let fast_ema = ema(series, fast_period);
let slow_ema = ema(series, slow_period);
let macd_line = fast_ema - slow_ema;
let signal_line = ema(macd_line, signal_period);
let histogram = macd_line - signal_line;
{
macd: macd_line,
signal: signal_line,
histogram: histogram
}
}