// MACD: fast EMA minus slow EMA, with an EMA signal line and histogram.
///|
/// MACD decomposition: the MACD line, its signal line and the histogram
/// (MACD minus signal). All three arrays have the input length.
pub struct Macd {
macd : Array[Double]
signal : Array[Double]
hist : Array[Double]
}
///|
/// Number of leading NaN values: `(slow - 1) + (signal - 1)`.
pub fn macd_lookback(slow_period : Int32, signal_period : Int32) -> Int32 {
slow_period - 1 + (signal_period - 1)
}
///|
/// Moving Average Convergence/Divergence.
///
/// The MACD line is `EMA(fast) - EMA(slow)` and becomes valid at index
/// `slow_period - 1`. The signal line is an EMA of the MACD line seeded with
/// the SMA of the first `signal_period` MACD values, valid at index
/// `slow_period + signal_period - 2`. Uses the SMA-seeded EMA of `overlap`
/// (TA-Lib convention), so a NaN input poisons the chain from that point on.
pub fn macd(
data : Array[Double],
fast_period : Int32,
slow_period : Int32,
signal_period : Int32,
) -> Macd raise @base.TaError {
@base.validate_series(data, slow_period)
if fast_period <= 0 || slow_period <= 0 || signal_period <= 0 {
raise @base.InvalidPeriod("all periods must be positive")
}
if fast_period >= slow_period {
raise @base.InvalidPeriod("fast_period must be smaller than slow_period")
}
let n = data.length()
let ema_fast = @overlap.ema_from(data, fast_period, 0)
let ema_slow = @overlap.ema_from(data, slow_period, 0)
let line : Array[Double] = []
for i in 0..