Skip to main content

finance_query/indicators/
mod.rs

1//! Technical analysis indicators for financial data.
2//!
3//! This module provides common technical indicators used by traders and analysts.
4//! All indicators work with time series price data from OHLCV candles.
5//!
6//! # Available Indicators
7//!
8//! ## Moving Averages
9//! - [`sma`] - Simple Moving Average
10//! - [`ema`] - Exponential Moving Average
11//!
12//! ## Momentum Oscillators
13//! - [`rsi`] - Relative Strength Index
14//!
15//! ## Trend Indicators
16//! - [`macd`] - Moving Average Convergence Divergence
17//!
18//! ## Volatility Indicators
19//! - [`bollinger_bands`] - Bollinger Bands
20//! - [`atr`] - Average True Range
21//!
22//! # Example
23//!
24//! ```no_run
25//! use finance_query::{Ticker, Interval, TimeRange};
26//!
27//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
28//! let ticker = Ticker::new("AAPL").await?;
29//! let chart = ticker.chart(Interval::OneDay, TimeRange::ThreeMonths).await?;
30//!
31//! // Use Chart extension methods (requires "indicators" feature)
32//! let sma_20 = chart.sma(20);
33//! let rsi_14 = chart.rsi(14)?;
34//! let atr_14 = chart.atr(14)?;
35//!
36//! // Or call indicators directly
37//! let closes: Vec<f64> = chart.candles.iter().map(|c| c.close).collect();
38//! let ema_12 = finance_query::indicators::ema(&closes, 12);
39//! # Ok(())
40//! # }
41//! ```
42
43mod accumulation_distribution;
44mod adx;
45mod alma;
46mod aroon;
47mod atr;
48mod awesome_oscillator;
49mod balance_of_power;
50mod bollinger;
51mod bull_bear_power;
52mod cci;
53mod chaikin_oscillator;
54mod choppiness_index;
55mod cmf;
56mod cmo;
57mod coppock_curve;
58mod dema;
59mod donchian_channels;
60mod elder_ray;
61mod ema;
62mod hma;
63mod ichimoku;
64mod keltner_channels;
65mod macd;
66mod mcginley_dynamic;
67mod mfi;
68mod momentum;
69mod obv;
70mod parabolic_sar;
71mod patterns;
72mod roc;
73mod rsi;
74mod sma;
75mod stochastic;
76mod stochastic_rsi;
77mod supertrend;
78mod tema;
79mod true_range;
80mod vwap;
81mod vwma;
82mod williams_r;
83mod wma;
84
85// Summary module for batch indicator calculations
86pub mod summary;
87
88// Re-export all indicators and patterns
89pub use accumulation_distribution::accumulation_distribution;
90pub use adx::adx;
91pub use alma::alma;
92pub use aroon::{AroonResult, aroon};
93pub use atr::atr;
94pub use awesome_oscillator::awesome_oscillator;
95pub use balance_of_power::balance_of_power;
96pub use bollinger::{BollingerBands, bollinger_bands};
97pub use bull_bear_power::{BullBearPowerResult, bull_bear_power};
98pub use cci::cci;
99pub use chaikin_oscillator::chaikin_oscillator;
100pub use choppiness_index::choppiness_index;
101pub use cmf::cmf;
102pub use cmo::cmo;
103pub use coppock_curve::coppock_curve;
104pub use dema::dema;
105pub use donchian_channels::{DonchianChannelsResult, donchian_channels};
106pub use elder_ray::{ElderRayResult, elder_ray};
107pub use ema::ema;
108pub use hma::hma;
109pub use ichimoku::{IchimokuResult, ichimoku};
110pub use keltner_channels::{KeltnerChannelsResult, keltner_channels};
111pub use macd::{MacdResult, macd};
112pub use mcginley_dynamic::mcginley_dynamic;
113pub use mfi::mfi;
114pub use momentum::momentum;
115pub use obv::obv;
116pub use parabolic_sar::parabolic_sar;
117pub use patterns::{CandlePattern, PatternSentiment, patterns};
118pub use roc::roc;
119pub use rsi::rsi;
120pub use sma::sma;
121pub use stochastic::{StochasticResult, stochastic};
122pub use stochastic_rsi::stochastic_rsi;
123pub use supertrend::{SuperTrendResult, supertrend};
124pub use tema::tema;
125pub use true_range::true_range;
126pub use vwap::vwap;
127pub use vwma::vwma;
128pub use williams_r::williams_r;
129pub use wma::wma;
130
131// Re-export summary types
132pub use summary::{
133    AroonData, BollingerBandsData, BullBearPowerData, DonchianChannelsData, ElderRayData,
134    IchimokuData, IndicatorsSummary, KeltnerChannelsData, MacdData, StochasticData, SuperTrendData,
135};
136
137// Re-export Indicator enum for easy access
138pub use Indicator as IndicatorType;
139
140/// Error type for indicator calculations
141#[derive(Debug, thiserror::Error)]
142pub enum IndicatorError {
143    /// Not enough data points to calculate the indicator
144    #[error("Insufficient data: need at least {need} data points, got {got}")]
145    InsufficientData {
146        /// Minimum number of data points required
147        need: usize,
148        /// Actual number of data points provided
149        got: usize,
150    },
151
152    /// Invalid period parameter provided
153    #[error("Invalid period: {0}")]
154    InvalidPeriod(String),
155}
156
157/// Result type for indicator calculations
158pub type Result<T> = std::result::Result<T, IndicatorError>;
159
160/// Result of an indicator calculation
161///
162/// Different indicators return different types of data:
163/// - Simple indicators (SMA, EMA, RSI, ATR) return a time series of values
164/// - Complex indicators (MACD, Bollinger Bands) return multiple series
165#[derive(Debug, Clone, PartialEq)]
166#[non_exhaustive]
167pub enum IndicatorResult {
168    /// Single value time series (SMA, EMA, RSI, ATR, OBV, VWAP)
169    Series(Vec<Option<f64>>),
170    /// MACD result with three series
171    Macd(MacdResult),
172    /// Bollinger Bands with upper, middle, lower bands
173    Bollinger(BollingerBands),
174    /// Stochastic Oscillator result
175    Stochastic(StochasticResult),
176    /// Aroon result
177    Aroon(AroonResult),
178    /// SuperTrend result
179    SuperTrend(SuperTrendResult),
180    /// Ichimoku Cloud result
181    Ichimoku(IchimokuResult),
182    /// Bull/Bear Power result
183    BullBearPower(BullBearPowerResult),
184    /// Elder Ray Index result
185    ElderRay(ElderRayResult),
186    /// Keltner Channels result
187    Keltner(KeltnerChannelsResult),
188    /// Donchian Channels result
189    Donchian(DonchianChannelsResult),
190}
191
192/// Enum representing all available technical indicators.
193///
194/// This enum is used with `Ticker::indicator()` to calculate specific indicators
195/// over a given interval and time range.
196#[derive(Debug, Clone, Copy, PartialEq)]
197#[non_exhaustive]
198pub enum Indicator {
199    /// Simple Moving Average with custom period
200    Sma(usize),
201    /// Exponential Moving Average with custom period
202    Ema(usize),
203    /// Relative Strength Index with custom period
204    Rsi(usize),
205    /// Moving Average Convergence Divergence (fast, slow, signal periods)
206    Macd {
207        /// Fast EMA period
208        fast: usize,
209        /// Slow EMA period
210        slow: usize,
211        /// Signal line EMA period
212        signal: usize,
213    },
214    /// Bollinger Bands (period, standard deviation multiplier)
215    Bollinger {
216        /// SMA period
217        period: usize,
218        /// Standard deviation multiplier
219        std_dev: f64,
220    },
221    /// Average True Range with custom period
222    Atr(usize),
223    /// On-Balance Volume
224    Obv,
225    /// Volume Weighted Average Price
226    Vwap,
227    /// Weighted Moving Average
228    Wma(usize),
229    /// Double Exponential Moving Average
230    Dema(usize),
231    /// Triple Exponential Moving Average
232    Tema(usize),
233    /// Hull Moving Average
234    Hma(usize),
235    /// Volume Weighted Moving Average
236    Vwma(usize),
237    /// Arnaud Legoux Moving Average
238    Alma {
239        /// Window period
240        period: usize,
241        /// Offset (typically 0.85)
242        offset: f64,
243        /// Sigma (typically 6.0)
244        sigma: f64,
245    },
246    /// McGinley Dynamic
247    McginleyDynamic(usize),
248    /// Stochastic Oscillator
249    Stochastic {
250        /// %K period
251        k_period: usize,
252        /// %K slowing period
253        k_slow: usize,
254        /// %D period (SMA of %K)
255        d_period: usize,
256    },
257    /// Stochastic RSI
258    StochasticRsi {
259        /// RSI period
260        rsi_period: usize,
261        /// Stochastic period applied to RSI
262        stoch_period: usize,
263        /// %K smoothing period
264        k_period: usize,
265        /// %D smoothing period
266        d_period: usize,
267    },
268    /// Commodity Channel Index
269    Cci(usize),
270    /// Williams %R
271    WilliamsR(usize),
272    /// Rate of Change
273    Roc(usize),
274    /// Momentum
275    Momentum(usize),
276    /// Chande Momentum Oscillator
277    Cmo(usize),
278    /// Awesome Oscillator
279    AwesomeOscillator {
280        /// Fast SMA period
281        fast: usize,
282        /// Slow SMA period
283        slow: usize,
284    },
285    /// Coppock Curve
286    CoppockCurve {
287        /// WMA smoothing period
288        wma_period: usize,
289        /// Long ROC period
290        long_roc: usize,
291        /// Short ROC period
292        short_roc: usize,
293    },
294    /// Average Directional Index
295    Adx(usize),
296    /// Aroon
297    Aroon(usize),
298    /// SuperTrend
299    Supertrend {
300        /// ATR period
301        period: usize,
302        /// ATR multiplier
303        multiplier: f64,
304    },
305    /// Ichimoku Cloud
306    Ichimoku {
307        /// Conversion line period (Tenkan-sen)
308        conversion: usize,
309        /// Base line period (Kijun-sen)
310        base: usize,
311        /// Lagging span period (Chikou Span)
312        lagging: usize,
313        /// Displacement for leading spans
314        displacement: usize,
315    },
316    /// Parabolic SAR
317    ParabolicSar {
318        /// Acceleration factor step
319        step: f64,
320        /// Maximum acceleration factor
321        max: f64,
322    },
323    /// Bull/Bear Power
324    BullBearPower(usize),
325    /// Elder Ray Index
326    ElderRay(usize),
327    /// Keltner Channels
328    KeltnerChannels {
329        /// EMA period for middle line
330        period: usize,
331        /// ATR multiplier for bands
332        multiplier: f64,
333        /// ATR period
334        atr_period: usize,
335    },
336    /// Donchian Channels
337    DonchianChannels(usize),
338    /// True Range
339    TrueRange,
340    /// Choppiness Index
341    ChoppinessIndex(usize),
342    /// Money Flow Index
343    Mfi(usize),
344    /// Chaikin Money Flow
345    Cmf(usize),
346    /// Chaikin Oscillator
347    ChaikinOscillator,
348    /// Accumulation/Distribution
349    AccumulationDistribution,
350    /// Balance of Power
351    BalanceOfPower(Option<usize>),
352}
353
354impl Indicator {
355    /// Get a default instance with standard parameters
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use finance_query::indicators::Indicator;
361    ///
362    /// let rsi = Indicator::Rsi(14);  // 14-period RSI
363    /// let macd = Indicator::Macd { fast: 12, slow: 26, signal: 9 };
364    /// ```
365    pub fn with_defaults(self) -> Self {
366        match self {
367            Indicator::Sma(_) => Indicator::Sma(20),
368            Indicator::Ema(_) => Indicator::Ema(12),
369            Indicator::Rsi(_) => Indicator::Rsi(14),
370            Indicator::Macd { .. } => Indicator::Macd {
371                fast: 12,
372                slow: 26,
373                signal: 9,
374            },
375            Indicator::Bollinger { .. } => Indicator::Bollinger {
376                period: 20,
377                std_dev: 2.0,
378            },
379            Indicator::Atr(_) => Indicator::Atr(14),
380            ind => ind,
381        }
382    }
383
384    /// Get the human-readable name of the indicator
385    pub fn name(&self) -> &'static str {
386        match self {
387            Indicator::Sma(_) => "Simple Moving Average",
388            Indicator::Ema(_) => "Exponential Moving Average",
389            Indicator::Rsi(_) => "Relative Strength Index",
390            Indicator::Macd { .. } => "MACD",
391            Indicator::Bollinger { .. } => "Bollinger Bands",
392            Indicator::Atr(_) => "Average True Range",
393            Indicator::Obv => "On-Balance Volume",
394            Indicator::Vwap => "VWAP",
395            Indicator::Wma(_) => "Weighted Moving Average",
396            Indicator::Dema(_) => "Double Exponential Moving Average",
397            Indicator::Tema(_) => "Triple Exponential Moving Average",
398            Indicator::Hma(_) => "Hull Moving Average",
399            Indicator::Vwma(_) => "Volume Weighted Moving Average",
400            Indicator::Alma { .. } => "Arnaud Legoux Moving Average",
401            Indicator::McginleyDynamic(_) => "McGinley Dynamic",
402            Indicator::Stochastic { .. } => "Stochastic Oscillator",
403            Indicator::StochasticRsi { .. } => "Stochastic RSI",
404            Indicator::Cci(_) => "Commodity Channel Index",
405            Indicator::WilliamsR(_) => "Williams %R",
406            Indicator::Roc(_) => "Rate of Change",
407            Indicator::Momentum(_) => "Momentum",
408            Indicator::Cmo(_) => "Chande Momentum Oscillator",
409            Indicator::AwesomeOscillator { .. } => "Awesome Oscillator",
410            Indicator::CoppockCurve { .. } => "Coppock Curve",
411            Indicator::Adx(_) => "Average Directional Index",
412            Indicator::Aroon(_) => "Aroon",
413            Indicator::Supertrend { .. } => "SuperTrend",
414            Indicator::Ichimoku { .. } => "Ichimoku Cloud",
415            Indicator::ParabolicSar { .. } => "Parabolic SAR",
416            Indicator::BullBearPower(_) => "Bull/Bear Power",
417            Indicator::ElderRay(_) => "Elder Ray Index",
418            Indicator::KeltnerChannels { .. } => "Keltner Channels",
419            Indicator::DonchianChannels(_) => "Donchian Channels",
420            Indicator::TrueRange => "True Range",
421            Indicator::ChoppinessIndex(_) => "Choppiness Index",
422            Indicator::Mfi(_) => "Money Flow Index",
423            Indicator::Cmf(_) => "Chaikin Money Flow",
424            Indicator::ChaikinOscillator => "Chaikin Oscillator",
425            Indicator::AccumulationDistribution => "Accumulation/Distribution",
426            Indicator::BalanceOfPower(_) => "Balance of Power",
427        }
428    }
429}
430
431/// Helper function to extract the last non-None value from a vector.
432///
433/// Useful for converting historical indicator values to latest value only.
434///
435/// # Example
436///
437/// ```
438/// use finance_query::indicators::last_value;
439///
440/// let values = vec![None, None, Some(10.0), Some(20.0)];
441/// assert_eq!(last_value(&values), Some(20.0));
442/// ```
443pub fn last_value(values: &[Option<f64>]) -> Option<f64> {
444    values.iter().rev().find_map(|&v| v)
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450
451    #[test]
452    fn test_last_value() {
453        assert_eq!(last_value(&[None, None, Some(1.0), Some(2.0)]), Some(2.0));
454        assert_eq!(last_value(&[None, None, Some(1.0), None]), Some(1.0));
455        assert_eq!(last_value(&[None, None, None]), None);
456        assert_eq!(last_value(&[]), None);
457    }
458}