1use crate::backtesting::strategy::StrategyContext;
2use crate::indicators::Indicator;
3
4use super::IndicatorRef;
5
6#[derive(Debug, Clone)]
8pub struct AdxRef {
9 pub period: usize,
10 key: String,
11}
12
13impl IndicatorRef for AdxRef {
14 fn key(&self) -> &str {
15 &self.key
16 }
17
18 fn required_indicators(&self) -> Vec<(String, Indicator)> {
19 vec![(self.key.clone(), Indicator::Adx(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]
42pub fn adx(period: usize) -> AdxRef {
43 AdxRef {
44 period,
45 key: format!("adx_{period}"),
46 }
47}
48
49#[derive(Debug, Clone, Copy)]
51pub struct MacdConfig {
52 pub fast: usize,
54 pub slow: usize,
56 pub signal: usize,
58}
59
60impl MacdConfig {
61 pub fn line(&self) -> MacdLineRef {
63 MacdLineRef::new(self.fast, self.slow, self.signal)
64 }
65
66 pub fn signal_line(&self) -> MacdSignalRef {
68 MacdSignalRef::new(self.fast, self.slow, self.signal)
69 }
70
71 pub fn histogram(&self) -> MacdHistogramRef {
73 MacdHistogramRef::new(self.fast, self.slow, self.signal)
74 }
75}
76
77#[inline]
89pub fn macd(fast: usize, slow: usize, signal: usize) -> MacdConfig {
90 MacdConfig { fast, slow, signal }
91}
92
93#[derive(Debug, Clone)]
95pub struct MacdLineRef {
96 pub fast: usize,
98 pub slow: usize,
100 pub signal: usize,
102 key: String,
103}
104
105impl MacdLineRef {
106 fn new(fast: usize, slow: usize, signal: usize) -> Self {
107 Self {
108 fast,
109 slow,
110 signal,
111 key: format!("macd_line_{fast}_{slow}_{signal}"),
112 }
113 }
114}
115
116impl IndicatorRef for MacdLineRef {
117 fn key(&self) -> &str {
118 &self.key
119 }
120
121 fn required_indicators(&self) -> Vec<(String, Indicator)> {
122 vec![(
123 self.key.clone(),
124 Indicator::Macd {
125 fast: self.fast,
126 slow: self.slow,
127 signal: self.signal,
128 },
129 )]
130 }
131
132 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
133 ctx.indicator(self.key())
134 }
135
136 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
137 ctx.indicator_prev(self.key())
138 }
139}
140
141#[derive(Debug, Clone)]
143pub struct MacdSignalRef {
144 pub fast: usize,
146 pub slow: usize,
148 pub signal: usize,
150 key: String,
151}
152
153impl MacdSignalRef {
154 fn new(fast: usize, slow: usize, signal: usize) -> Self {
155 Self {
156 fast,
157 slow,
158 signal,
159 key: format!("macd_signal_{fast}_{slow}_{signal}"),
160 }
161 }
162}
163
164impl IndicatorRef for MacdSignalRef {
165 fn key(&self) -> &str {
166 &self.key
167 }
168
169 fn required_indicators(&self) -> Vec<(String, Indicator)> {
170 vec![(
171 self.key.clone(),
172 Indicator::Macd {
173 fast: self.fast,
174 slow: self.slow,
175 signal: self.signal,
176 },
177 )]
178 }
179
180 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
181 ctx.indicator(self.key())
182 }
183
184 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
185 ctx.indicator_prev(self.key())
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct MacdHistogramRef {
192 pub fast: usize,
194 pub slow: usize,
196 pub signal: usize,
198 key: String,
199}
200
201impl MacdHistogramRef {
202 fn new(fast: usize, slow: usize, signal: usize) -> Self {
203 Self {
204 fast,
205 slow,
206 signal,
207 key: format!("macd_histogram_{fast}_{slow}_{signal}"),
208 }
209 }
210}
211
212impl IndicatorRef for MacdHistogramRef {
213 fn key(&self) -> &str {
214 &self.key
215 }
216
217 fn required_indicators(&self) -> Vec<(String, Indicator)> {
218 vec![(
219 self.key.clone(),
220 Indicator::Macd {
221 fast: self.fast,
222 slow: self.slow,
223 signal: self.signal,
224 },
225 )]
226 }
227
228 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
229 ctx.indicator(self.key())
230 }
231
232 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
233 ctx.indicator_prev(self.key())
234 }
235}
236
237#[derive(Debug, Clone, Copy)]
239pub struct SupertrendConfig {
240 pub period: usize,
241 pub multiplier: f64,
242}
243
244impl SupertrendConfig {
245 pub fn value(&self) -> SupertrendValueRef {
247 SupertrendValueRef::new(self.period, self.multiplier)
248 }
249
250 pub fn uptrend(&self) -> SupertrendUptrendRef {
252 SupertrendUptrendRef::new(self.period, self.multiplier)
253 }
254}
255
256#[inline]
258pub fn supertrend(period: usize, multiplier: f64) -> SupertrendConfig {
259 SupertrendConfig { period, multiplier }
260}
261
262#[derive(Debug, Clone)]
264pub struct SupertrendValueRef {
265 pub period: usize,
266 pub multiplier: f64,
267 key: String,
268}
269
270impl SupertrendValueRef {
271 fn new(period: usize, multiplier: f64) -> Self {
272 Self {
273 period,
274 multiplier,
275 key: format!("supertrend_value_{period}_{multiplier}"),
276 }
277 }
278}
279
280impl IndicatorRef for SupertrendValueRef {
281 fn key(&self) -> &str {
282 &self.key
283 }
284
285 fn required_indicators(&self) -> Vec<(String, Indicator)> {
286 vec![(
287 self.key.clone(),
288 Indicator::Supertrend {
289 period: self.period,
290 multiplier: self.multiplier,
291 },
292 )]
293 }
294
295 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
296 ctx.indicator(self.key())
297 }
298
299 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
300 ctx.indicator_prev(self.key())
301 }
302}
303
304#[derive(Debug, Clone)]
307pub struct SupertrendUptrendRef {
308 pub period: usize,
309 pub multiplier: f64,
310 key: String,
311}
312
313impl SupertrendUptrendRef {
314 fn new(period: usize, multiplier: f64) -> Self {
315 Self {
316 period,
317 multiplier,
318 key: format!("supertrend_uptrend_{period}_{multiplier}"),
319 }
320 }
321}
322
323impl IndicatorRef for SupertrendUptrendRef {
324 fn key(&self) -> &str {
325 &self.key
326 }
327
328 fn required_indicators(&self) -> Vec<(String, Indicator)> {
329 vec![(
330 self.key.clone(),
331 Indicator::Supertrend {
332 period: self.period,
333 multiplier: self.multiplier,
334 },
335 )]
336 }
337
338 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
339 ctx.indicator(self.key())
340 }
341
342 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
343 ctx.indicator_prev(self.key())
344 }
345}
346
347#[derive(Debug, Clone, Copy)]
349pub struct AroonConfig {
350 pub period: usize,
351}
352
353impl AroonConfig {
354 pub fn up(&self) -> AroonUpRef {
356 AroonUpRef::new(self.period)
357 }
358
359 pub fn down(&self) -> AroonDownRef {
361 AroonDownRef::new(self.period)
362 }
363}
364
365#[inline]
367pub fn aroon(period: usize) -> AroonConfig {
368 AroonConfig { period }
369}
370
371#[derive(Debug, Clone)]
373pub struct AroonUpRef {
374 pub period: usize,
375 key: String,
376}
377
378impl AroonUpRef {
379 fn new(period: usize) -> Self {
380 Self {
381 period,
382 key: format!("aroon_up_{period}"),
383 }
384 }
385}
386
387impl IndicatorRef for AroonUpRef {
388 fn key(&self) -> &str {
389 &self.key
390 }
391
392 fn required_indicators(&self) -> Vec<(String, Indicator)> {
393 vec![(self.key.clone(), Indicator::Aroon(self.period))]
394 }
395
396 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
397 ctx.indicator(self.key())
398 }
399
400 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
401 ctx.indicator_prev(self.key())
402 }
403}
404
405#[derive(Debug, Clone)]
407pub struct AroonDownRef {
408 pub period: usize,
409 key: String,
410}
411
412impl AroonDownRef {
413 fn new(period: usize) -> Self {
414 Self {
415 period,
416 key: format!("aroon_down_{period}"),
417 }
418 }
419}
420
421impl IndicatorRef for AroonDownRef {
422 fn key(&self) -> &str {
423 &self.key
424 }
425
426 fn required_indicators(&self) -> Vec<(String, Indicator)> {
427 vec![(self.key.clone(), Indicator::Aroon(self.period))]
428 }
429
430 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
431 ctx.indicator(self.key())
432 }
433
434 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
435 ctx.indicator_prev(self.key())
436 }
437}
438
439#[derive(Debug, Clone, Copy)]
441pub struct ParabolicSarConfig {
442 pub step: f64,
443 pub max: f64,
444}
445
446#[inline]
448pub fn parabolic_sar(step: f64, max: f64) -> ParabolicSarRef {
449 ParabolicSarRef::new(step, max)
450}
451
452#[derive(Debug, Clone)]
454pub struct ParabolicSarRef {
455 pub step: f64,
456 pub max: f64,
457 key: String,
458}
459
460impl ParabolicSarRef {
461 fn new(step: f64, max: f64) -> Self {
462 Self {
463 step,
464 max,
465 key: format!("psar_{step}_{max}"),
466 }
467 }
468}
469
470impl IndicatorRef for ParabolicSarRef {
471 fn key(&self) -> &str {
472 &self.key
473 }
474
475 fn required_indicators(&self) -> Vec<(String, Indicator)> {
476 vec![(
477 self.key.clone(),
478 Indicator::ParabolicSar {
479 step: self.step,
480 max: self.max,
481 },
482 )]
483 }
484
485 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
486 ctx.indicator(self.key())
487 }
488
489 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
490 ctx.indicator_prev(self.key())
491 }
492}
493
494#[derive(Debug, Clone)]
496pub struct ChoppinessIndexRef {
497 pub period: usize,
498 key: String,
499}
500
501#[inline]
503pub fn choppiness_index(period: usize) -> ChoppinessIndexRef {
504 ChoppinessIndexRef {
505 period,
506 key: format!("chop_{period}"),
507 }
508}
509
510impl IndicatorRef for ChoppinessIndexRef {
511 fn key(&self) -> &str {
512 &self.key
513 }
514
515 fn required_indicators(&self) -> Vec<(String, Indicator)> {
516 vec![(self.key.clone(), Indicator::ChoppinessIndex(self.period))]
517 }
518
519 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
520 ctx.indicator(self.key())
521 }
522
523 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
524 ctx.indicator_prev(self.key())
525 }
526}
527
528#[cfg(test)]
529mod tests {
530 use super::*;
531 use crate::backtesting::refs::{coppock_curve, true_range};
532
533 #[test]
534 fn test_macd_keys() {
535 let m = macd(12, 26, 9);
536 assert_eq!(m.line().key(), "macd_line_12_26_9");
537 assert_eq!(m.signal_line().key(), "macd_signal_12_26_9");
538 assert_eq!(m.histogram().key(), "macd_histogram_12_26_9");
539 }
540
541 #[test]
542 fn test_supertrend_keys() {
543 let st = supertrend(10, 3.0);
544 assert_eq!(st.value().key(), "supertrend_value_10_3");
545 assert_eq!(st.uptrend().key(), "supertrend_uptrend_10_3");
546 }
547
548 #[test]
549 fn test_aroon_keys() {
550 let ar = aroon(25);
551 assert_eq!(ar.up().key(), "aroon_up_25");
552 assert_eq!(ar.down().key(), "aroon_down_25");
553 }
554
555 #[test]
556 fn test_other_keys() {
557 assert_eq!(parabolic_sar(0.02, 0.2).key(), "psar_0.02_0.2");
558 assert_eq!(true_range().key(), "true_range");
559 assert_eq!(coppock_curve(10, 14, 11).key(), "coppock_10_14_11");
560 }
561}