kestrel_chartkit/indicator/
mod.rs1pub mod adx;
2pub mod alligator;
3pub mod anchored_vwap;
4pub mod atr;
5pub mod bollinger;
6pub mod bop;
7pub mod bos_choch;
8pub mod buy_sell_pressure;
9pub mod candle_story;
10pub mod cci;
11pub mod chaikin_osc;
12pub mod chandelier_exit;
13pub mod chart_patterns;
14pub mod choppiness;
15pub mod connors_rsi;
16pub mod coppock;
17pub mod divergence;
18pub mod dpo;
19pub mod efficiency;
20pub mod elliott;
21pub mod envelope;
22pub mod eom;
23pub mod fisher_transform;
24pub mod kst;
25pub mod liquidity_fvg;
26pub mod liquidity_sweeps;
27pub mod lsma;
28pub mod macd;
29pub mod market_structure_breaks;
30pub mod mass_index;
31pub mod mcginley;
32pub mod mfi;
33pub mod midas;
34pub mod momentum_indicators;
35pub mod moving_averages;
36pub mod multi_factor;
37pub mod nvi_pvi;
38pub mod order_block;
39pub mod params;
40pub mod pivot_sets;
41pub mod pivots_structure;
42pub mod price_levels;
43pub mod registry;
44pub mod relative_strength;
45pub mod rsi;
46pub mod rvi;
47pub mod smart_money_structure;
48pub mod smoothing;
49pub mod source_mapped;
50pub mod stoch_rsi;
51pub mod swing_structure;
52pub mod tema;
53pub mod trend_quality;
54pub mod trend_relationship;
55pub mod trend_structural;
56pub mod tsi;
57pub mod vix_fix;
58pub mod volatility_indicators;
59pub mod volatility_regime;
60pub mod volume_flow;
61pub mod volume_flow_hires;
62pub mod volume_indicators;
63pub mod volume_profile;
64pub mod volume_profile_extended;
65pub mod volume_profile_persistent;
66pub mod vortex;
67pub mod vwap;
68pub mod wavetrend;
69pub mod williams_r;
70pub mod wyckoff;
71pub mod zigzag;
72pub mod zigzag_advanced;
73pub mod zscore;
74
75use std::collections::HashMap;
76use std::fmt;
77
78#[cfg(feature = "serde")]
79use serde::{Deserialize, Serialize};
80
81use crate::artifact::Artifact;
82use crate::model::{Bar, BarValidationError};
83
84#[derive(Debug, Clone, PartialEq)]
86#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87pub struct IndicatorOutput {
88 pub value: f64,
89 pub secondary: Option<f64>,
90 pub signal: Option<f64>,
91 pub extra: HashMap<String, f64>,
92 pub state: Option<String>,
95 pub reason: Option<String>,
97 pub artifacts: Vec<Artifact>,
99}
100
101impl IndicatorOutput {
102 pub fn new(value: f64) -> Self {
103 Self {
104 value,
105 secondary: None,
106 signal: None,
107 extra: HashMap::new(),
108 state: None,
109 reason: None,
110 artifacts: Vec::new(),
111 }
112 }
113
114 pub fn with_secondary(mut self, secondary: f64) -> Self {
115 self.secondary = Some(secondary);
116 self
117 }
118
119 pub fn with_signal(mut self, signal: f64) -> Self {
120 self.signal = Some(signal);
121 self
122 }
123
124 pub fn with_extra(value: f64, extra: HashMap<String, f64>) -> Self {
125 Self {
126 value,
127 secondary: None,
128 signal: None,
129 extra,
130 state: None,
131 reason: None,
132 artifacts: Vec::new(),
133 }
134 }
135
136 pub fn with_state(mut self, state: impl Into<String>) -> Self {
137 self.state = Some(state.into());
138 self
139 }
140
141 pub fn with_reason(mut self, reason: impl Into<String>) -> Self {
142 self.reason = Some(reason.into());
143 self
144 }
145
146 pub fn with_artifact(mut self, artifact: impl Into<Artifact>) -> Self {
147 self.artifacts.push(artifact.into());
148 self
149 }
150}
151
152#[derive(Debug, Clone, PartialEq)]
154#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
155pub struct IndicatorAlert {
156 pub kind: String,
157 pub note: String,
158 pub strength: f64,
159}
160
161impl IndicatorAlert {
162 pub fn new(kind: impl Into<String>, note: impl Into<String>, strength: f64) -> Self {
163 Self {
164 kind: kind.into(),
165 note: note.into(),
166 strength,
167 }
168 }
169}
170
171impl fmt::Display for IndicatorAlert {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 write!(f, "{} ({})", self.note, self.kind)
174 }
175}
176
177pub trait Indicator: Send + Sync {
179 fn name(&self) -> &str;
180 fn warmup_period(&self) -> usize {
181 0
182 }
183 fn reset(&mut self);
184 fn on_bar(&mut self, bar: &Bar) -> Option<IndicatorOutput>;
185 fn on_checked_bar(&mut self, bar: &Bar) -> Result<Option<IndicatorOutput>, BarValidationError> {
187 bar.validate()?;
188 Ok(self.on_bar(bar))
189 }
190 fn alerts(&self) -> Vec<IndicatorAlert> {
191 Vec::new()
192 }
193}
194
195impl<T: Indicator + ?Sized> Indicator for Box<T> {
199 fn name(&self) -> &str {
200 (**self).name()
201 }
202 fn warmup_period(&self) -> usize {
203 (**self).warmup_period()
204 }
205 fn reset(&mut self) {
206 (**self).reset()
207 }
208 fn on_bar(&mut self, bar: &Bar) -> Option<IndicatorOutput> {
209 (**self).on_bar(bar)
210 }
211 fn on_checked_bar(&mut self, bar: &Bar) -> Result<Option<IndicatorOutput>, BarValidationError> {
212 (**self).on_checked_bar(bar)
213 }
214 fn alerts(&self) -> Vec<IndicatorAlert> {
215 (**self).alerts()
216 }
217}