Skip to main content

finance_query/backtesting/refs/
volatility.rs

1use crate::backtesting::strategy::StrategyContext;
2use crate::indicators::Indicator;
3
4use super::IndicatorRef;
5
6/// Average True Range reference.
7#[derive(Debug, Clone)]
8pub struct AtrRef {
9    pub period: usize,
10    key: String,
11}
12
13impl IndicatorRef for AtrRef {
14    fn key(&self) -> &str {
15        &self.key
16    }
17
18    fn required_indicators(&self) -> Vec<(String, Indicator)> {
19        vec![(self.key.clone(), Indicator::Atr(self.period))]
20    }
21
22    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
23        ctx.indicator(self.key())
24    }
25
26    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
27        ctx.indicator_prev(self.key())
28    }
29}
30
31/// Create an Average True Range reference.
32#[inline]
33pub fn atr(period: usize) -> AtrRef {
34    AtrRef {
35        period,
36        key: format!("atr_{period}"),
37    }
38}
39
40/// True Range reference.
41#[derive(Debug, Clone, Copy)]
42pub struct TrueRangeRef;
43
44/// Create a True Range reference.
45#[inline]
46pub fn true_range() -> TrueRangeRef {
47    TrueRangeRef
48}
49
50impl IndicatorRef for TrueRangeRef {
51    fn key(&self) -> &str {
52        "true_range"
53    }
54
55    fn required_indicators(&self) -> Vec<(String, Indicator)> {
56        vec![("true_range".to_string(), Indicator::TrueRange)]
57    }
58
59    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
60        ctx.indicator(self.key())
61    }
62
63    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
64        ctx.indicator_prev(self.key())
65    }
66}
67
68/// Bollinger Bands configuration.
69#[derive(Debug, Clone, Copy)]
70pub struct BollingerConfig {
71    /// SMA period
72    pub period: usize,
73    /// Standard deviation multiplier
74    pub std_dev: f64,
75}
76
77impl BollingerConfig {
78    /// Get the upper band reference.
79    pub fn upper(&self) -> BollingerUpperRef {
80        BollingerUpperRef::new(self.period, self.std_dev)
81    }
82
83    /// Get the middle band (SMA) reference.
84    pub fn middle(&self) -> BollingerMiddleRef {
85        BollingerMiddleRef::new(self.period, self.std_dev)
86    }
87
88    /// Get the lower band reference.
89    pub fn lower(&self) -> BollingerLowerRef {
90        BollingerLowerRef::new(self.period, self.std_dev)
91    }
92}
93
94/// Create a Bollinger Bands configuration.
95///
96/// # Example
97///
98/// ```ignore
99/// use finance_query::backtesting::refs::*;
100///
101/// let bb = bollinger(20, 2.0);
102/// let at_lower_band = price().below_ref(bb.lower());
103/// let at_upper_band = price().above_ref(bb.upper());
104/// ```
105#[inline]
106pub fn bollinger(period: usize, std_dev: f64) -> BollingerConfig {
107    BollingerConfig { period, std_dev }
108}
109
110/// Bollinger upper band reference.
111#[derive(Debug, Clone)]
112pub struct BollingerUpperRef {
113    /// Moving average period.
114    pub period: usize,
115    /// Standard deviation multiplier.
116    pub std_dev: f64,
117    key: String,
118}
119
120impl BollingerUpperRef {
121    fn new(period: usize, std_dev: f64) -> Self {
122        Self {
123            period,
124            std_dev,
125            key: format!("bollinger_upper_{period}_{std_dev}"),
126        }
127    }
128}
129
130impl IndicatorRef for BollingerUpperRef {
131    fn key(&self) -> &str {
132        &self.key
133    }
134
135    fn required_indicators(&self) -> Vec<(String, Indicator)> {
136        vec![(
137            self.key.clone(),
138            Indicator::Bollinger {
139                period: self.period,
140                std_dev: self.std_dev,
141            },
142        )]
143    }
144
145    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
146        ctx.indicator(self.key())
147    }
148
149    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
150        ctx.indicator_prev(self.key())
151    }
152}
153
154/// Bollinger middle band reference.
155#[derive(Debug, Clone)]
156pub struct BollingerMiddleRef {
157    /// Moving average period.
158    pub period: usize,
159    /// Standard deviation multiplier.
160    pub std_dev: f64,
161    key: String,
162}
163
164impl BollingerMiddleRef {
165    fn new(period: usize, std_dev: f64) -> Self {
166        Self {
167            period,
168            std_dev,
169            key: format!("bollinger_middle_{period}_{std_dev}"),
170        }
171    }
172}
173
174impl IndicatorRef for BollingerMiddleRef {
175    fn key(&self) -> &str {
176        &self.key
177    }
178
179    fn required_indicators(&self) -> Vec<(String, Indicator)> {
180        vec![(
181            self.key.clone(),
182            Indicator::Bollinger {
183                period: self.period,
184                std_dev: self.std_dev,
185            },
186        )]
187    }
188
189    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
190        ctx.indicator(self.key())
191    }
192
193    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
194        ctx.indicator_prev(self.key())
195    }
196}
197
198/// Bollinger lower band reference.
199#[derive(Debug, Clone)]
200pub struct BollingerLowerRef {
201    /// Moving average period.
202    pub period: usize,
203    /// Standard deviation multiplier.
204    pub std_dev: f64,
205    key: String,
206}
207
208impl BollingerLowerRef {
209    fn new(period: usize, std_dev: f64) -> Self {
210        Self {
211            period,
212            std_dev,
213            key: format!("bollinger_lower_{period}_{std_dev}"),
214        }
215    }
216}
217
218impl IndicatorRef for BollingerLowerRef {
219    fn key(&self) -> &str {
220        &self.key
221    }
222
223    fn required_indicators(&self) -> Vec<(String, Indicator)> {
224        vec![(
225            self.key.clone(),
226            Indicator::Bollinger {
227                period: self.period,
228                std_dev: self.std_dev,
229            },
230        )]
231    }
232
233    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
234        ctx.indicator(self.key())
235    }
236
237    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
238        ctx.indicator_prev(self.key())
239    }
240}
241
242/// Donchian Channels configuration.
243#[derive(Debug, Clone, Copy)]
244pub struct DonchianConfig {
245    pub period: usize,
246}
247
248impl DonchianConfig {
249    /// Get the upper channel reference.
250    pub fn upper(&self) -> DonchianUpperRef {
251        DonchianUpperRef::new(self.period)
252    }
253
254    /// Get the middle channel reference.
255    pub fn middle(&self) -> DonchianMiddleRef {
256        DonchianMiddleRef::new(self.period)
257    }
258
259    /// Get the lower channel reference.
260    pub fn lower(&self) -> DonchianLowerRef {
261        DonchianLowerRef::new(self.period)
262    }
263}
264
265/// Create a Donchian Channels configuration.
266#[inline]
267pub fn donchian(period: usize) -> DonchianConfig {
268    DonchianConfig { period }
269}
270
271/// Donchian upper channel reference.
272#[derive(Debug, Clone)]
273pub struct DonchianUpperRef {
274    pub period: usize,
275    key: String,
276}
277
278impl DonchianUpperRef {
279    fn new(period: usize) -> Self {
280        Self {
281            period,
282            key: format!("donchian_upper_{period}"),
283        }
284    }
285}
286
287impl IndicatorRef for DonchianUpperRef {
288    fn key(&self) -> &str {
289        &self.key
290    }
291
292    fn required_indicators(&self) -> Vec<(String, Indicator)> {
293        vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
294    }
295
296    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
297        ctx.indicator(self.key())
298    }
299
300    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
301        ctx.indicator_prev(self.key())
302    }
303}
304
305/// Donchian middle channel reference.
306#[derive(Debug, Clone)]
307pub struct DonchianMiddleRef {
308    pub period: usize,
309    key: String,
310}
311
312impl DonchianMiddleRef {
313    fn new(period: usize) -> Self {
314        Self {
315            period,
316            key: format!("donchian_middle_{period}"),
317        }
318    }
319}
320
321impl IndicatorRef for DonchianMiddleRef {
322    fn key(&self) -> &str {
323        &self.key
324    }
325
326    fn required_indicators(&self) -> Vec<(String, Indicator)> {
327        vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
328    }
329
330    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
331        ctx.indicator(self.key())
332    }
333
334    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
335        ctx.indicator_prev(self.key())
336    }
337}
338
339/// Donchian lower channel reference.
340#[derive(Debug, Clone)]
341pub struct DonchianLowerRef {
342    pub period: usize,
343    key: String,
344}
345
346impl DonchianLowerRef {
347    fn new(period: usize) -> Self {
348        Self {
349            period,
350            key: format!("donchian_lower_{period}"),
351        }
352    }
353}
354
355impl IndicatorRef for DonchianLowerRef {
356    fn key(&self) -> &str {
357        &self.key
358    }
359
360    fn required_indicators(&self) -> Vec<(String, Indicator)> {
361        vec![(self.key.clone(), Indicator::DonchianChannels(self.period))]
362    }
363
364    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
365        ctx.indicator(self.key())
366    }
367
368    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
369        ctx.indicator_prev(self.key())
370    }
371}
372
373/// Keltner Channels configuration.
374#[derive(Debug, Clone, Copy)]
375pub struct KeltnerConfig {
376    pub period: usize,
377    pub multiplier: f64,
378    pub atr_period: usize,
379}
380
381impl KeltnerConfig {
382    /// Get the upper channel reference.
383    pub fn upper(&self) -> KeltnerUpperRef {
384        KeltnerUpperRef::new(self.period, self.multiplier, self.atr_period)
385    }
386
387    /// Get the middle channel (EMA) reference.
388    pub fn middle(&self) -> KeltnerMiddleRef {
389        KeltnerMiddleRef::new(self.period, self.multiplier, self.atr_period)
390    }
391
392    /// Get the lower channel reference.
393    pub fn lower(&self) -> KeltnerLowerRef {
394        KeltnerLowerRef::new(self.period, self.multiplier, self.atr_period)
395    }
396}
397
398/// Create a Keltner Channels configuration.
399#[inline]
400pub fn keltner(period: usize, multiplier: f64, atr_period: usize) -> KeltnerConfig {
401    KeltnerConfig {
402        period,
403        multiplier,
404        atr_period,
405    }
406}
407
408/// Keltner upper channel reference.
409#[derive(Debug, Clone)]
410pub struct KeltnerUpperRef {
411    pub period: usize,
412    pub multiplier: f64,
413    pub atr_period: usize,
414    key: String,
415}
416
417impl KeltnerUpperRef {
418    fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
419        Self {
420            period,
421            multiplier,
422            atr_period,
423            key: format!("keltner_upper_{period}_{multiplier}_{atr_period}"),
424        }
425    }
426}
427
428impl IndicatorRef for KeltnerUpperRef {
429    fn key(&self) -> &str {
430        &self.key
431    }
432
433    fn required_indicators(&self) -> Vec<(String, Indicator)> {
434        vec![(
435            self.key.clone(),
436            Indicator::KeltnerChannels {
437                period: self.period,
438                multiplier: self.multiplier,
439                atr_period: self.atr_period,
440            },
441        )]
442    }
443
444    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
445        ctx.indicator(self.key())
446    }
447
448    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
449        ctx.indicator_prev(self.key())
450    }
451}
452
453/// Keltner middle channel reference.
454#[derive(Debug, Clone)]
455pub struct KeltnerMiddleRef {
456    pub period: usize,
457    pub multiplier: f64,
458    pub atr_period: usize,
459    key: String,
460}
461
462impl KeltnerMiddleRef {
463    fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
464        Self {
465            period,
466            multiplier,
467            atr_period,
468            key: format!("keltner_middle_{period}_{multiplier}_{atr_period}"),
469        }
470    }
471}
472
473impl IndicatorRef for KeltnerMiddleRef {
474    fn key(&self) -> &str {
475        &self.key
476    }
477
478    fn required_indicators(&self) -> Vec<(String, Indicator)> {
479        vec![(
480            self.key.clone(),
481            Indicator::KeltnerChannels {
482                period: self.period,
483                multiplier: self.multiplier,
484                atr_period: self.atr_period,
485            },
486        )]
487    }
488
489    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
490        ctx.indicator(self.key())
491    }
492
493    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
494        ctx.indicator_prev(self.key())
495    }
496}
497
498/// Keltner lower channel reference.
499#[derive(Debug, Clone)]
500pub struct KeltnerLowerRef {
501    pub period: usize,
502    pub multiplier: f64,
503    pub atr_period: usize,
504    key: String,
505}
506
507impl KeltnerLowerRef {
508    fn new(period: usize, multiplier: f64, atr_period: usize) -> Self {
509        Self {
510            period,
511            multiplier,
512            atr_period,
513            key: format!("keltner_lower_{period}_{multiplier}_{atr_period}"),
514        }
515    }
516}
517
518impl IndicatorRef for KeltnerLowerRef {
519    fn key(&self) -> &str {
520        &self.key
521    }
522
523    fn required_indicators(&self) -> Vec<(String, Indicator)> {
524        vec![(
525            self.key.clone(),
526            Indicator::KeltnerChannels {
527                period: self.period,
528                multiplier: self.multiplier,
529                atr_period: self.atr_period,
530            },
531        )]
532    }
533
534    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
535        ctx.indicator(self.key())
536    }
537
538    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
539        ctx.indicator_prev(self.key())
540    }
541}
542
543#[cfg(test)]
544mod tests {
545    use super::*;
546
547    #[test]
548    fn test_bollinger_keys() {
549        let bb = bollinger(20, 2.0);
550        assert_eq!(bb.upper().key(), "bollinger_upper_20_2");
551        assert_eq!(bb.middle().key(), "bollinger_middle_20_2");
552        assert_eq!(bb.lower().key(), "bollinger_lower_20_2");
553    }
554
555    #[test]
556    fn test_donchian_keys() {
557        let dc = donchian(20);
558        assert_eq!(dc.upper().key(), "donchian_upper_20");
559        assert_eq!(dc.middle().key(), "donchian_middle_20");
560        assert_eq!(dc.lower().key(), "donchian_lower_20");
561    }
562
563    #[test]
564    fn test_keltner_keys() {
565        let kc = keltner(20, 2.0, 10);
566        assert_eq!(kc.upper().key(), "keltner_upper_20_2_10");
567        assert_eq!(kc.middle().key(), "keltner_middle_20_2_10");
568        assert_eq!(kc.lower().key(), "keltner_lower_20_2_10");
569    }
570}