// Aroon indicator (Tushar Chande): recency of the highest high and lowest
// low within the lookback window.
///|
/// Aroon decomposition: the down and up lines, both of input length.
pub struct AroonResult {
down : Array[Double]
up : Array[Double]
}
///|
/// Number of leading NaN values produced by `aroon` for the given period.
pub fn aroon_lookback(period : Int32) -> Int32 {
period
}
///|
/// Aroon up/down.
///
/// For each bar the window spans the `period` bars before it plus itself
/// (TA-Lib convention, `period + 1` data points). `up` is
/// `100 * (period - bars_since_highest_high) / period` and `down` mirrors it
/// with the lowest low; when several bars share the extreme, the most recent
/// occurrence wins. A window containing NaN yields NaN for that position.
/// Computed in O(n) via the base rolling argmax/argmin.
pub fn aroon(
candles : @base.Candles,
period : Int32,
) -> AroonResult raise @base.TaError {
@base.validate_candles(candles)
if period <= 0 {
raise @base.InvalidPeriod("period must be positive, got \{period}")
}
let n = candles.close.length()
if period + 1 > n {
raise @base.NotEnoughData("period \{period} exceeds input length \{n}")
}
let hh_idx = @base.rolling_argmax(candles.high, period + 1)
let ll_idx = @base.rolling_argmin(candles.low, period + 1)
let pd = period.to_double()
let down : Array[Double] = []
let up : Array[Double] = []
for i in 0.. Int32 {
period
}
///|
/// Aroon Oscillator: `up - down`. Ranges from -100 (downtrend) to +100
/// (uptrend) with the same window rules as `aroon`.
pub fn aroonosc(
candles : @base.Candles,
period : Int32,
) -> Array[Double] raise @base.TaError {
let r = aroon(candles, period)
let n = candles.close.length()
let out : Array[Double] = []
for i in 0..