1use crate::backtesting::strategy::StrategyContext;
2use crate::indicators::Indicator;
3
4use super::IndicatorRef;
5
6#[derive(Debug, Clone)]
8pub struct RsiRef {
9 pub period: usize,
10 key: String,
11}
12
13impl IndicatorRef for RsiRef {
14 fn key(&self) -> &str {
15 &self.key
16 }
17
18 fn required_indicators(&self) -> Vec<(String, Indicator)> {
19 vec![(self.key.clone(), Indicator::Rsi(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#[inline]
43pub fn rsi(period: usize) -> RsiRef {
44 RsiRef {
45 period,
46 key: format!("rsi_{period}"),
47 }
48}
49
50#[derive(Debug, Clone)]
52pub struct CciRef {
53 pub period: usize,
54 key: String,
55}
56
57impl IndicatorRef for CciRef {
58 fn key(&self) -> &str {
59 &self.key
60 }
61
62 fn required_indicators(&self) -> Vec<(String, Indicator)> {
63 vec![(self.key.clone(), Indicator::Cci(self.period))]
64 }
65
66 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
67 ctx.indicator(self.key())
68 }
69
70 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
71 ctx.indicator_prev(self.key())
72 }
73}
74
75#[inline]
77pub fn cci(period: usize) -> CciRef {
78 CciRef {
79 period,
80 key: format!("cci_{period}"),
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct WilliamsRRef {
87 pub period: usize,
88 key: String,
89}
90
91impl IndicatorRef for WilliamsRRef {
92 fn key(&self) -> &str {
93 &self.key
94 }
95
96 fn required_indicators(&self) -> Vec<(String, Indicator)> {
97 vec![(self.key.clone(), Indicator::WilliamsR(self.period))]
98 }
99
100 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
101 ctx.indicator(self.key())
102 }
103
104 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
105 ctx.indicator_prev(self.key())
106 }
107}
108
109#[inline]
111pub fn williams_r(period: usize) -> WilliamsRRef {
112 WilliamsRRef {
113 period,
114 key: format!("williams_r_{period}"),
115 }
116}
117
118#[derive(Debug, Clone)]
120pub struct CmoRef {
121 pub period: usize,
122 key: String,
123}
124
125impl IndicatorRef for CmoRef {
126 fn key(&self) -> &str {
127 &self.key
128 }
129
130 fn required_indicators(&self) -> Vec<(String, Indicator)> {
131 vec![(self.key.clone(), Indicator::Cmo(self.period))]
132 }
133
134 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
135 ctx.indicator(self.key())
136 }
137
138 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
139 ctx.indicator_prev(self.key())
140 }
141}
142
143#[inline]
145pub fn cmo(period: usize) -> CmoRef {
146 CmoRef {
147 period,
148 key: format!("cmo_{period}"),
149 }
150}
151
152#[derive(Debug, Clone)]
154pub struct MomentumRef {
155 pub period: usize,
156 key: String,
157}
158
159impl IndicatorRef for MomentumRef {
160 fn key(&self) -> &str {
161 &self.key
162 }
163
164 fn required_indicators(&self) -> Vec<(String, Indicator)> {
165 vec![(self.key.clone(), Indicator::Momentum(self.period))]
166 }
167
168 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
169 ctx.indicator(self.key())
170 }
171
172 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
173 ctx.indicator_prev(self.key())
174 }
175}
176
177#[inline]
179pub fn momentum(period: usize) -> MomentumRef {
180 MomentumRef {
181 period,
182 key: format!("momentum_{period}"),
183 }
184}
185
186#[derive(Debug, Clone)]
188pub struct RocRef {
189 pub period: usize,
190 key: String,
191}
192
193impl IndicatorRef for RocRef {
194 fn key(&self) -> &str {
195 &self.key
196 }
197
198 fn required_indicators(&self) -> Vec<(String, Indicator)> {
199 vec![(self.key.clone(), Indicator::Roc(self.period))]
200 }
201
202 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
203 ctx.indicator(self.key())
204 }
205
206 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
207 ctx.indicator_prev(self.key())
208 }
209}
210
211#[inline]
213pub fn roc(period: usize) -> RocRef {
214 RocRef {
215 period,
216 key: format!("roc_{period}"),
217 }
218}
219
220#[derive(Debug, Clone, Copy)]
222pub struct StochasticConfig {
223 pub k_period: usize,
224 pub k_slow: usize,
225 pub d_period: usize,
226}
227
228impl StochasticConfig {
229 pub fn k(&self) -> StochasticKRef {
231 StochasticKRef::new(self.k_period, self.k_slow, self.d_period)
232 }
233
234 pub fn d(&self) -> StochasticDRef {
236 StochasticDRef::new(self.k_period, self.k_slow, self.d_period)
237 }
238}
239
240#[inline]
242pub fn stochastic(k_period: usize, k_slow: usize, d_period: usize) -> StochasticConfig {
243 StochasticConfig {
244 k_period,
245 k_slow,
246 d_period,
247 }
248}
249
250#[derive(Debug, Clone)]
252pub struct StochasticKRef {
253 pub k_period: usize,
254 pub k_slow: usize,
255 pub d_period: usize,
256 key: String,
257}
258
259impl StochasticKRef {
260 fn new(k_period: usize, k_slow: usize, d_period: usize) -> Self {
261 Self {
262 k_period,
263 k_slow,
264 d_period,
265 key: format!("stochastic_k_{k_period}_{k_slow}_{d_period}"),
266 }
267 }
268}
269
270impl IndicatorRef for StochasticKRef {
271 fn key(&self) -> &str {
272 &self.key
273 }
274
275 fn required_indicators(&self) -> Vec<(String, Indicator)> {
276 vec![(
277 self.key.clone(),
278 Indicator::Stochastic {
279 k_period: self.k_period,
280 k_slow: self.k_slow,
281 d_period: self.d_period,
282 },
283 )]
284 }
285
286 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
287 ctx.indicator(self.key())
288 }
289
290 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
291 ctx.indicator_prev(self.key())
292 }
293}
294
295#[derive(Debug, Clone)]
297pub struct StochasticDRef {
298 pub k_period: usize,
299 pub k_slow: usize,
300 pub d_period: usize,
301 key: String,
302}
303
304impl StochasticDRef {
305 fn new(k_period: usize, k_slow: usize, d_period: usize) -> Self {
306 Self {
307 k_period,
308 k_slow,
309 d_period,
310 key: format!("stochastic_d_{k_period}_{k_slow}_{d_period}"),
311 }
312 }
313}
314
315impl IndicatorRef for StochasticDRef {
316 fn key(&self) -> &str {
317 &self.key
318 }
319
320 fn required_indicators(&self) -> Vec<(String, Indicator)> {
321 vec![(
322 self.key.clone(),
323 Indicator::Stochastic {
324 k_period: self.k_period,
325 k_slow: self.k_slow,
326 d_period: self.d_period,
327 },
328 )]
329 }
330
331 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
332 ctx.indicator(self.key())
333 }
334
335 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
336 ctx.indicator_prev(self.key())
337 }
338}
339
340#[derive(Debug, Clone, Copy)]
358pub struct StochasticRsiConfig {
359 pub rsi_period: usize,
360 pub stoch_period: usize,
361 pub k_period: usize,
362 pub d_period: usize,
363}
364
365impl StochasticRsiConfig {
366 pub fn k(&self) -> StochasticRsiRef {
368 StochasticRsiRef::new(
369 self.rsi_period,
370 self.stoch_period,
371 self.k_period,
372 self.d_period,
373 )
374 }
375
376 pub fn d(&self) -> StochasticRsiDRef {
378 StochasticRsiDRef::new(
379 self.rsi_period,
380 self.stoch_period,
381 self.k_period,
382 self.d_period,
383 )
384 }
385}
386
387#[inline]
394pub fn stochastic_rsi(
395 rsi_period: usize,
396 stoch_period: usize,
397 k_period: usize,
398 d_period: usize,
399) -> StochasticRsiConfig {
400 StochasticRsiConfig {
401 rsi_period,
402 stoch_period,
403 k_period,
404 d_period,
405 }
406}
407
408#[derive(Debug, Clone)]
410pub struct StochasticRsiRef {
411 pub rsi_period: usize,
412 pub stoch_period: usize,
413 pub k_period: usize,
414 pub d_period: usize,
415 key: String,
416}
417
418impl StochasticRsiRef {
419 fn new(rsi_period: usize, stoch_period: usize, k_period: usize, d_period: usize) -> Self {
420 Self {
421 rsi_period,
422 stoch_period,
423 k_period,
424 d_period,
425 key: format!("stoch_rsi_k_{rsi_period}_{stoch_period}_{k_period}_{d_period}"),
426 }
427 }
428}
429
430impl IndicatorRef for StochasticRsiRef {
431 fn key(&self) -> &str {
432 &self.key
433 }
434
435 fn required_indicators(&self) -> Vec<(String, Indicator)> {
436 vec![(
437 self.key.clone(),
438 Indicator::StochasticRsi {
439 rsi_period: self.rsi_period,
440 stoch_period: self.stoch_period,
441 k_period: self.k_period,
442 d_period: self.d_period,
443 },
444 )]
445 }
446
447 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
448 ctx.indicator(self.key())
449 }
450
451 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
452 ctx.indicator_prev(self.key())
453 }
454}
455
456#[derive(Debug, Clone)]
458pub struct StochasticRsiDRef {
459 pub rsi_period: usize,
460 pub stoch_period: usize,
461 pub k_period: usize,
462 pub d_period: usize,
463 key: String,
464}
465
466impl StochasticRsiDRef {
467 fn new(rsi_period: usize, stoch_period: usize, k_period: usize, d_period: usize) -> Self {
468 Self {
469 rsi_period,
470 stoch_period,
471 k_period,
472 d_period,
473 key: format!("stoch_rsi_d_{rsi_period}_{stoch_period}_{k_period}_{d_period}"),
474 }
475 }
476}
477
478impl IndicatorRef for StochasticRsiDRef {
479 fn key(&self) -> &str {
480 &self.key
481 }
482
483 fn required_indicators(&self) -> Vec<(String, Indicator)> {
484 let k_key = format!(
487 "stoch_rsi_k_{}_{}_{}_{}",
488 self.rsi_period, self.stoch_period, self.k_period, self.d_period
489 );
490 vec![(
491 k_key,
492 Indicator::StochasticRsi {
493 rsi_period: self.rsi_period,
494 stoch_period: self.stoch_period,
495 k_period: self.k_period,
496 d_period: self.d_period,
497 },
498 )]
499 }
500
501 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
502 ctx.indicator(self.key())
503 }
504
505 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
506 ctx.indicator_prev(self.key())
507 }
508}
509
510#[derive(Debug, Clone)]
512pub struct AwesomeOscillatorRef {
513 pub fast: usize,
514 pub slow: usize,
515 key: String,
516}
517
518#[inline]
520pub fn awesome_oscillator(fast: usize, slow: usize) -> AwesomeOscillatorRef {
521 AwesomeOscillatorRef {
522 fast,
523 slow,
524 key: format!("ao_{fast}_{slow}"),
525 }
526}
527
528impl IndicatorRef for AwesomeOscillatorRef {
529 fn key(&self) -> &str {
530 &self.key
531 }
532
533 fn required_indicators(&self) -> Vec<(String, Indicator)> {
534 vec![(
535 self.key.clone(),
536 Indicator::AwesomeOscillator {
537 fast: self.fast,
538 slow: self.slow,
539 },
540 )]
541 }
542
543 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
544 ctx.indicator(self.key())
545 }
546
547 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
548 ctx.indicator_prev(self.key())
549 }
550}
551
552#[derive(Debug, Clone)]
554pub struct CoppockCurveRef {
555 pub wma_period: usize,
556 pub long_roc: usize,
557 pub short_roc: usize,
558 key: String,
559}
560
561#[inline]
563pub fn coppock_curve(wma_period: usize, long_roc: usize, short_roc: usize) -> CoppockCurveRef {
564 CoppockCurveRef {
565 wma_period,
566 long_roc,
567 short_roc,
568 key: format!("coppock_{wma_period}_{long_roc}_{short_roc}"),
569 }
570}
571
572impl IndicatorRef for CoppockCurveRef {
573 fn key(&self) -> &str {
574 &self.key
575 }
576
577 fn required_indicators(&self) -> Vec<(String, Indicator)> {
578 vec![(
579 self.key.clone(),
580 Indicator::CoppockCurve {
581 wma_period: self.wma_period,
582 long_roc: self.long_roc,
583 short_roc: self.short_roc,
584 },
585 )]
586 }
587
588 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
589 ctx.indicator(self.key())
590 }
591
592 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
593 ctx.indicator_prev(self.key())
594 }
595}
596
597#[derive(Debug, Clone)]
599pub struct MfiRef {
600 pub period: usize,
601 key: String,
602}
603
604impl IndicatorRef for MfiRef {
605 fn key(&self) -> &str {
606 &self.key
607 }
608
609 fn required_indicators(&self) -> Vec<(String, Indicator)> {
610 vec![(self.key.clone(), Indicator::Mfi(self.period))]
611 }
612
613 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
614 ctx.indicator(self.key())
615 }
616
617 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
618 ctx.indicator_prev(self.key())
619 }
620}
621
622#[inline]
624pub fn mfi(period: usize) -> MfiRef {
625 MfiRef {
626 period,
627 key: format!("mfi_{period}"),
628 }
629}
630
631#[derive(Debug, Clone, Copy)]
633pub struct ChaikinOscillatorRef;
634
635#[inline]
637pub fn chaikin_oscillator() -> ChaikinOscillatorRef {
638 ChaikinOscillatorRef
639}
640
641impl IndicatorRef for ChaikinOscillatorRef {
642 fn key(&self) -> &str {
643 "chaikin_osc"
644 }
645
646 fn required_indicators(&self) -> Vec<(String, Indicator)> {
647 vec![("chaikin_osc".to_string(), Indicator::ChaikinOscillator)]
648 }
649
650 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
651 ctx.indicator(self.key())
652 }
653
654 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
655 ctx.indicator_prev(self.key())
656 }
657}
658
659#[derive(Debug, Clone)]
661pub struct BalanceOfPowerRef {
662 pub period: Option<usize>,
663 key: String,
664}
665
666#[inline]
668pub fn balance_of_power(period: Option<usize>) -> BalanceOfPowerRef {
669 let key = match period {
670 Some(p) => format!("bop_{p}"),
671 None => "bop".to_string(),
672 };
673 BalanceOfPowerRef { period, key }
674}
675
676impl IndicatorRef for BalanceOfPowerRef {
677 fn key(&self) -> &str {
678 &self.key
679 }
680
681 fn required_indicators(&self) -> Vec<(String, Indicator)> {
682 vec![(self.key.clone(), Indicator::BalanceOfPower(self.period))]
683 }
684
685 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
686 ctx.indicator(self.key())
687 }
688
689 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
690 ctx.indicator_prev(self.key())
691 }
692}
693
694#[cfg(test)]
695mod tests {
696 use super::*;
697 use crate::backtesting::refs::choppiness_index;
698
699 #[test]
700 fn test_oscillator_keys() {
701 assert_eq!(rsi(14).key(), "rsi_14");
702 assert_eq!(cci(20).key(), "cci_20");
703 assert_eq!(williams_r(14).key(), "williams_r_14");
704 assert_eq!(cmo(14).key(), "cmo_14");
705 assert_eq!(
707 stochastic_rsi(14, 14, 3, 3).k().key(),
708 "stoch_rsi_k_14_14_3_3"
709 );
710 assert_eq!(
711 stochastic_rsi(14, 14, 3, 3).d().key(),
712 "stoch_rsi_d_14_14_3_3"
713 );
714 assert_eq!(awesome_oscillator(5, 34).key(), "ao_5_34");
715 assert_eq!(choppiness_index(14).key(), "chop_14");
716 }
717
718 #[test]
719 fn test_stochastic_keys() {
720 let stoch = stochastic(14, 3, 3);
721 assert_eq!(stoch.k().key(), "stochastic_k_14_3_3");
722 assert_eq!(stoch.d().key(), "stochastic_d_14_3_3");
723 }
724}