1mod 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
85pub mod summary;
87
88pub 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
131pub use summary::{
133 AroonData, BollingerBandsData, BullBearPowerData, DonchianChannelsData, ElderRayData,
134 IchimokuData, IndicatorsSummary, KeltnerChannelsData, MacdData, StochasticData, SuperTrendData,
135};
136
137pub use Indicator as IndicatorType;
139
140#[derive(Debug, thiserror::Error)]
142pub enum IndicatorError {
143 #[error("Insufficient data: need at least {need} data points, got {got}")]
145 InsufficientData {
146 need: usize,
148 got: usize,
150 },
151
152 #[error("Invalid period: {0}")]
154 InvalidPeriod(String),
155}
156
157pub type Result<T> = std::result::Result<T, IndicatorError>;
159
160#[derive(Debug, Clone, PartialEq)]
166#[non_exhaustive]
167pub enum IndicatorResult {
168 Series(Vec<Option<f64>>),
170 Macd(MacdResult),
172 Bollinger(BollingerBands),
174 Stochastic(StochasticResult),
176 Aroon(AroonResult),
178 SuperTrend(SuperTrendResult),
180 Ichimoku(IchimokuResult),
182 BullBearPower(BullBearPowerResult),
184 ElderRay(ElderRayResult),
186 Keltner(KeltnerChannelsResult),
188 Donchian(DonchianChannelsResult),
190}
191
192#[derive(Debug, Clone, Copy, PartialEq)]
197#[non_exhaustive]
198pub enum Indicator {
199 Sma(usize),
201 Ema(usize),
203 Rsi(usize),
205 Macd {
207 fast: usize,
209 slow: usize,
211 signal: usize,
213 },
214 Bollinger {
216 period: usize,
218 std_dev: f64,
220 },
221 Atr(usize),
223 Obv,
225 Vwap,
227 Wma(usize),
229 Dema(usize),
231 Tema(usize),
233 Hma(usize),
235 Vwma(usize),
237 Alma {
239 period: usize,
241 offset: f64,
243 sigma: f64,
245 },
246 McginleyDynamic(usize),
248 Stochastic {
250 k_period: usize,
252 k_slow: usize,
254 d_period: usize,
256 },
257 StochasticRsi {
259 rsi_period: usize,
261 stoch_period: usize,
263 k_period: usize,
265 d_period: usize,
267 },
268 Cci(usize),
270 WilliamsR(usize),
272 Roc(usize),
274 Momentum(usize),
276 Cmo(usize),
278 AwesomeOscillator {
280 fast: usize,
282 slow: usize,
284 },
285 CoppockCurve {
287 wma_period: usize,
289 long_roc: usize,
291 short_roc: usize,
293 },
294 Adx(usize),
296 Aroon(usize),
298 Supertrend {
300 period: usize,
302 multiplier: f64,
304 },
305 Ichimoku {
307 conversion: usize,
309 base: usize,
311 lagging: usize,
313 displacement: usize,
315 },
316 ParabolicSar {
318 step: f64,
320 max: f64,
322 },
323 BullBearPower(usize),
325 ElderRay(usize),
327 KeltnerChannels {
329 period: usize,
331 multiplier: f64,
333 atr_period: usize,
335 },
336 DonchianChannels(usize),
338 TrueRange,
340 ChoppinessIndex(usize),
342 Mfi(usize),
344 Cmf(usize),
346 ChaikinOscillator,
348 AccumulationDistribution,
350 BalanceOfPower(Option<usize>),
352}
353
354impl Indicator {
355 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 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
431pub 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}