quant-indicators 0.7.0

Pure indicator math library for trading — MA, RSI, Bollinger, MACD, ATR, HRP
Documentation
use super::*;
use crate::test_helpers::helpers::{make_candle, ts};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;

#[test]
fn macd_uptrend_positive() {
    // Strong uptrend should give positive MACD
    let candles: Vec<Candle> = (0..50)
        .map(|i| make_candle(Decimal::from(100 + i * 2), ts(i)))
        .collect();

    let macd = Macd::standard().expect("valid MACD standard params");
    let series = macd.compute(&candles).expect("sufficient data for MACD");

    // Later values should be positive (fast > slow in uptrend)
    let last_values: Vec<_> = series.decimal_values().into_iter().rev().take(5).collect();
    for v in last_values {
        assert!(
            v > Decimal::ZERO,
            "MACD {} should be positive in uptrend",
            v
        );
    }
}

#[test]
fn macd_downtrend_negative() {
    // Strong downtrend should give negative MACD
    let candles: Vec<Candle> = (0..50)
        .map(|i| make_candle(Decimal::from(200 - i * 2), ts(i)))
        .collect();

    let macd = Macd::standard().expect("valid MACD standard params");
    let series = macd.compute(&candles).expect("sufficient data for MACD");

    // Later values should be negative (fast < slow in downtrend)
    let last_values: Vec<_> = series.decimal_values().into_iter().rev().take(5).collect();
    for v in last_values {
        assert!(
            v < Decimal::ZERO,
            "MACD {} should be negative in downtrend",
            v
        );
    }
}

#[test]
fn macd_flat_near_zero() {
    // Flat price should give MACD near zero
    let candles: Vec<Candle> = (0..50).map(|i| make_candle(dec!(100), ts(i))).collect();

    let macd = Macd::standard().expect("valid MACD standard params");
    let series = macd.compute(&candles).expect("sufficient data for MACD");

    for (_, v) in series.values() {
        assert!(
            v.abs() < dec!(1),
            "MACD {} should be near zero for flat prices",
            v
        );
    }
}

#[test]
fn macd_invalid_params() {
    // fast >= slow
    assert!(Macd::new(26, 12).is_err());
    assert!(Macd::new(12, 12).is_err());

    // Zero periods
    assert!(Macd::new(0, 26).is_err());
    assert!(Macd::new(12, 0).is_err());
}

#[test]
fn macd_name() {
    let macd = Macd::new(12, 26).expect("valid MACD params");
    assert_eq!(macd.name(), "MACD(12,26)");
}

#[test]
fn macd_warmup() {
    let macd = Macd::standard().expect("valid MACD standard params");
    assert_eq!(macd.warmup_period(), 26);
}