1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//! Core indicator trait definitions.
//!
//! These are domain abstractions: pure computation contracts with no I/O.
//! Concrete implementations live alongside these traits in `quant-indicators`.
use quant_primitives::Candle;
use crate::{IndicatorError, Series};
/// A technical indicator that computes a continuous numeric time series.
///
/// All indicators are pure functions - no I/O, no async, no side effects.
/// This makes them easy to test, compose, and potentially compile to WASM.
///
/// For discrete classification outputs (e.g., `VolumeAnomaly`), use
/// [`ClassificationIndicator<T>`] instead.
pub trait Indicator: Send + Sync {
/// The name of this indicator (e.g., "SMA(20)").
#[must_use]
fn name(&self) -> &str;
/// Minimum number of candles required before output is valid.
#[must_use]
fn warmup_period(&self) -> usize;
/// Compute the indicator values from candle data.
fn compute(&self, candles: &[Candle]) -> Result<Series, IndicatorError>;
}
/// A classification indicator that maps each candle to a typed domain outcome.
///
/// Unlike [`Indicator`] (which produces a continuous `Decimal` series),
/// `ClassificationIndicator<T>` produces rich domain types (enums, structs).
///
/// Returns `None` for candles within the warmup window, and `Some(T)` once
/// sufficient history is available.
pub trait ClassificationIndicator<T>: Send + Sync {
/// Number of prior candles consumed before first `Some` result is emitted.
#[must_use]
fn lookback(&self) -> usize;
/// Classify each candle. Returns one `Option<T>` per input candle.
fn compute(&self, candles: &[Candle]) -> Result<Vec<Option<T>>, IndicatorError>;
}