mylittleindicators 0.1.8

Multi-stream financial indicators library — 556 bar indicators + 21 event primitives across 35 categories. Consumes 27 stream kinds from digdigdig3 exchange connectors: OHLCV bars, ticks, orderbook (snapshot/delta/L3), funding/predicted funding/funding settlement, mark price, index price, open interest, liquidations, ticker, agg trades, long/short ratio, option greeks, volatility index, historical volatility, basis (derived), composite index, settlement events, block trades, insurance fund, risk limit, market warning, and three kline-family variants. Live-verified on 12 exchanges (89% pass-rate on a 150s BTC slice).
Documentation
//! Operator class axis — describes the type of event/comparison.

/// What kind of comparison or event the signal evaluates.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OperatorClass {
    /// Two values cross each other (crossover / crossunder).
    Cross,
    /// One value crosses a threshold level.
    ThresholdCompare,
    /// Value enters a zone defined by lo/hi bounds.
    ZoneEnter,
    /// Value exits a zone defined by lo/hi bounds.
    ZoneExit,
    /// Value sets an N-bar extreme (highest/lowest over window).
    NBarExtreme,
    /// Pivot high or pivot low detected via left/right lookback.
    Pivot,
    /// Directional movement signal (slope, above/below).
    Direction,
    /// Divergence between indicator and price action.
    Divergence,
    /// Candle pattern detected (no operands).
    CandlePattern,
    /// Regime gate — filter based on trend/volatility indicator.
    RegimeGate,
    /// Sequential event: A followed by B within N bars.
    ///
    /// Requires stateful arming: slot0 arms the machine, slot1 fires the signal.
    Sequence,
    /// Volatility regime shift — z-score / percentile-based transition between
    /// vol regimes (Squeeze / Breakout / Extreme / Shift).
    VolatilityRegime,
    /// Volume event — Spike / Climax / Delta shift relative to average / history.
    VolumeEvent,
}

/// How the condition must hold over time.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Strictness {
    /// Trigger exactly at the crossing bar (edge).
    OnEdge,
    /// Condition must hold persistently (every bar).
    Persistent,
    /// Trigger only the first bar the condition becomes true.
    FirstTime,
    /// Condition must be confirmed for N consecutive bars.
    NBarsConfirmed(usize),
}

/// Returns the default strictness for an operator class.
///
/// This mapping is canonical: codegen uses it to emit the correct
/// condition-check pattern without the user having to specify strictness
/// explicitly on each event.
pub fn strictness_for(op: OperatorClass) -> Strictness {
    match op {
        OperatorClass::Cross => Strictness::OnEdge,
        OperatorClass::ThresholdCompare => Strictness::Persistent,
        OperatorClass::ZoneEnter => Strictness::FirstTime,
        OperatorClass::ZoneExit => Strictness::FirstTime,
        OperatorClass::NBarExtreme => Strictness::OnEdge,
        OperatorClass::Pivot => Strictness::OnEdge,
        OperatorClass::Direction => Strictness::NBarsConfirmed(1),
        OperatorClass::Divergence => Strictness::OnEdge,
        OperatorClass::CandlePattern => Strictness::OnEdge,
        OperatorClass::RegimeGate => Strictness::Persistent,
        OperatorClass::Sequence => Strictness::OnEdge,
        OperatorClass::VolatilityRegime => Strictness::FirstTime,
        OperatorClass::VolumeEvent => Strictness::OnEdge,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cross_strictness_is_on_edge() {
        assert_eq!(strictness_for(OperatorClass::Cross), Strictness::OnEdge);
    }

    #[test]
    fn threshold_strictness_is_persistent() {
        assert_eq!(strictness_for(OperatorClass::ThresholdCompare), Strictness::Persistent);
    }

    #[test]
    fn zone_enter_strictness_is_first_time() {
        assert_eq!(strictness_for(OperatorClass::ZoneEnter), Strictness::FirstTime);
    }

    #[test]
    fn direction_strictness_is_nbar_confirmed() {
        assert!(matches!(strictness_for(OperatorClass::Direction), Strictness::NBarsConfirmed(1)));
    }
}