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 chrono::Timelike;
use rust_decimal_macros::dec;

#[test]
fn sma_basic() {
    let candles: Vec<Candle> = vec![
        make_candle(dec!(100), ts(0)),
        make_candle(dec!(102), ts(1)),
        make_candle(dec!(104), ts(2)),
        make_candle(dec!(103), ts(3)),
        make_candle(dec!(105), ts(4)),
    ];

    let sma = Sma::new(3).expect("valid SMA period");
    let series = sma.compute(&candles).expect("sufficient data for SMA");

    assert_eq!(series.len(), 3);

    let values = series.decimal_values();
    // (100+102+104)/3 = 102
    assert_eq!(values[0], dec!(102));
    // (102+104+103)/3 = 103
    assert_eq!(values[1], dec!(103));
    // (104+103+105)/3 = 104
    assert_eq!(values[2], dec!(104));
}

#[test]
fn sma_period_1() {
    let candles: Vec<Candle> = vec![
        make_candle(dec!(100), ts(0)),
        make_candle(dec!(105), ts(1)),
        make_candle(dec!(95), ts(2)),
    ];

    let sma = Sma::new(1).expect("valid SMA period");
    let series = sma.compute(&candles).expect("sufficient data for SMA");

    assert_eq!(series.len(), 3);
    let values = series.decimal_values();
    assert_eq!(values, vec![dec!(100), dec!(105), dec!(95)]);
}

#[test]
fn sma_insufficient_data() {
    let candles: Vec<Candle> = vec![make_candle(dec!(100), ts(0)), make_candle(dec!(102), ts(1))];

    let sma = Sma::new(3).expect("valid SMA period");
    let result = sma.compute(&candles);

    assert!(matches!(
        result,
        Err(IndicatorError::InsufficientData {
            required: 3,
            actual: 2
        })
    ));
}

#[test]
fn sma_period_zero() {
    let result = Sma::new(0);
    assert!(matches!(
        result,
        Err(IndicatorError::InvalidParameter { .. })
    ));
}

#[test]
fn sma_name() {
    let sma = Sma::new(20).expect("valid SMA period");
    assert_eq!(sma.name(), "SMA(20)");
}

#[test]
fn sma_warmup_period() {
    let sma = Sma::new(14).expect("valid SMA period");
    assert_eq!(sma.warmup_period(), 14);
}

#[test]
fn sma_timestamps_from_last_candle_in_window() {
    let candles: Vec<Candle> = vec![
        make_candle(dec!(100), ts(0)),
        make_candle(dec!(100), ts(1)),
        make_candle(dec!(100), ts(2)),
    ];

    let sma = Sma::new(2).expect("valid SMA period");
    let series = sma.compute(&candles).expect("sufficient data for SMA");

    // First value should have timestamp of candle at index 1
    let (ts, _) = series.get(0).expect("series value exists");
    assert_eq!(ts.hour(), 1);

    // Second value should have timestamp of candle at index 2
    let (ts, _) = series.get(1).expect("series value exists");
    assert_eq!(ts.hour(), 2);
}