finance_query/backtesting/refs/
moving_averages.rs1use crate::backtesting::strategy::StrategyContext;
2use crate::indicators::Indicator;
3
4use super::IndicatorRef;
5
6#[derive(Debug, Clone)]
8pub struct SmaRef {
9 pub period: usize,
10 key: String,
11}
12
13impl IndicatorRef for SmaRef {
14 fn key(&self) -> &str {
15 &self.key
16 }
17
18 fn required_indicators(&self) -> Vec<(String, Indicator)> {
19 vec![(self.key.clone(), Indicator::Sma(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 sma(period: usize) -> SmaRef {
43 SmaRef {
44 period,
45 key: format!("sma_{period}"),
46 }
47}
48
49#[derive(Debug, Clone)]
51pub struct EmaRef {
52 pub period: usize,
53 key: String,
54}
55
56impl IndicatorRef for EmaRef {
57 fn key(&self) -> &str {
58 &self.key
59 }
60
61 fn required_indicators(&self) -> Vec<(String, Indicator)> {
62 vec![(self.key.clone(), Indicator::Ema(self.period))]
63 }
64
65 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
66 ctx.indicator(self.key())
67 }
68
69 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
70 ctx.indicator_prev(self.key())
71 }
72}
73
74#[inline]
76pub fn ema(period: usize) -> EmaRef {
77 EmaRef {
78 period,
79 key: format!("ema_{period}"),
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct WmaRef {
86 pub period: usize,
87 key: String,
88}
89
90impl IndicatorRef for WmaRef {
91 fn key(&self) -> &str {
92 &self.key
93 }
94
95 fn required_indicators(&self) -> Vec<(String, Indicator)> {
96 vec![(self.key.clone(), Indicator::Wma(self.period))]
97 }
98
99 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
100 ctx.indicator(self.key())
101 }
102
103 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
104 ctx.indicator_prev(self.key())
105 }
106}
107
108#[inline]
110pub fn wma(period: usize) -> WmaRef {
111 WmaRef {
112 period,
113 key: format!("wma_{period}"),
114 }
115}
116
117#[derive(Debug, Clone)]
119pub struct DemaRef {
120 pub period: usize,
121 key: String,
122}
123
124impl IndicatorRef for DemaRef {
125 fn key(&self) -> &str {
126 &self.key
127 }
128
129 fn required_indicators(&self) -> Vec<(String, Indicator)> {
130 vec![(self.key.clone(), Indicator::Dema(self.period))]
131 }
132
133 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
134 ctx.indicator(self.key())
135 }
136
137 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
138 ctx.indicator_prev(self.key())
139 }
140}
141
142#[inline]
144pub fn dema(period: usize) -> DemaRef {
145 DemaRef {
146 period,
147 key: format!("dema_{period}"),
148 }
149}
150
151#[derive(Debug, Clone)]
153pub struct TemaRef {
154 pub period: usize,
155 key: String,
156}
157
158impl IndicatorRef for TemaRef {
159 fn key(&self) -> &str {
160 &self.key
161 }
162
163 fn required_indicators(&self) -> Vec<(String, Indicator)> {
164 vec![(self.key.clone(), Indicator::Tema(self.period))]
165 }
166
167 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
168 ctx.indicator(self.key())
169 }
170
171 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
172 ctx.indicator_prev(self.key())
173 }
174}
175
176#[inline]
178pub fn tema(period: usize) -> TemaRef {
179 TemaRef {
180 period,
181 key: format!("tema_{period}"),
182 }
183}
184
185#[derive(Debug, Clone)]
187pub struct HmaRef {
188 pub period: usize,
189 key: String,
190}
191
192impl IndicatorRef for HmaRef {
193 fn key(&self) -> &str {
194 &self.key
195 }
196
197 fn required_indicators(&self) -> Vec<(String, Indicator)> {
198 vec![(self.key.clone(), Indicator::Hma(self.period))]
199 }
200
201 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
202 ctx.indicator(self.key())
203 }
204
205 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
206 ctx.indicator_prev(self.key())
207 }
208}
209
210#[inline]
212pub fn hma(period: usize) -> HmaRef {
213 HmaRef {
214 period,
215 key: format!("hma_{period}"),
216 }
217}
218
219#[derive(Debug, Clone)]
221pub struct VwmaRef {
222 pub period: usize,
223 key: String,
224}
225
226impl IndicatorRef for VwmaRef {
227 fn key(&self) -> &str {
228 &self.key
229 }
230
231 fn required_indicators(&self) -> Vec<(String, Indicator)> {
232 vec![(self.key.clone(), Indicator::Vwma(self.period))]
233 }
234
235 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
236 ctx.indicator(self.key())
237 }
238
239 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
240 ctx.indicator_prev(self.key())
241 }
242}
243
244#[inline]
246pub fn vwma(period: usize) -> VwmaRef {
247 VwmaRef {
248 period,
249 key: format!("vwma_{period}"),
250 }
251}
252
253#[derive(Debug, Clone)]
255pub struct McginleyDynamicRef {
256 pub period: usize,
257 key: String,
258}
259
260impl IndicatorRef for McginleyDynamicRef {
261 fn key(&self) -> &str {
262 &self.key
263 }
264
265 fn required_indicators(&self) -> Vec<(String, Indicator)> {
266 vec![(self.key.clone(), Indicator::McginleyDynamic(self.period))]
267 }
268
269 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
270 ctx.indicator(self.key())
271 }
272
273 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
274 ctx.indicator_prev(self.key())
275 }
276}
277
278#[inline]
280pub fn mcginley(period: usize) -> McginleyDynamicRef {
281 McginleyDynamicRef {
282 period,
283 key: format!("mcginley_{period}"),
284 }
285}
286
287#[derive(Debug, Clone, Copy)]
289pub struct AlmaConfig {
290 pub period: usize,
291 pub offset: f64,
292 pub sigma: f64,
293}
294
295#[inline]
297pub fn alma(period: usize, offset: f64, sigma: f64) -> AlmaRef {
298 AlmaRef::new(period, offset, sigma)
299}
300
301#[derive(Debug, Clone)]
303pub struct AlmaRef {
304 pub period: usize,
305 pub offset: f64,
306 pub sigma: f64,
307 key: String,
308}
309
310impl AlmaRef {
311 fn new(period: usize, offset: f64, sigma: f64) -> Self {
312 Self {
313 period,
314 offset,
315 sigma,
316 key: format!("alma_{period}_{offset}_{sigma}"),
317 }
318 }
319}
320
321impl IndicatorRef for AlmaRef {
322 fn key(&self) -> &str {
323 &self.key
324 }
325
326 fn required_indicators(&self) -> Vec<(String, Indicator)> {
327 vec![(
328 self.key.clone(),
329 Indicator::Alma {
330 period: self.period,
331 offset: self.offset,
332 sigma: self.sigma,
333 },
334 )]
335 }
336
337 fn value(&self, ctx: &StrategyContext) -> Option<f64> {
338 ctx.indicator(self.key())
339 }
340
341 fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
342 ctx.indicator_prev(self.key())
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn test_moving_average_keys() {
352 assert_eq!(sma(20).key(), "sma_20");
353 assert_eq!(ema(12).key(), "ema_12");
354 assert_eq!(wma(14).key(), "wma_14");
355 assert_eq!(dema(21).key(), "dema_21");
356 assert_eq!(tema(21).key(), "tema_21");
357 assert_eq!(hma(9).key(), "hma_9");
358 assert_eq!(vwma(20).key(), "vwma_20");
359 assert_eq!(mcginley(14).key(), "mcginley_14");
360 assert_eq!(alma(9, 0.85, 6.0).key(), "alma_9_0.85_6");
361 }
362
363 #[test]
364 fn test_required_indicators() {
365 let sma_ref = sma(20);
366 let indicators = sma_ref.required_indicators();
367 assert_eq!(indicators.len(), 1);
368 assert_eq!(indicators[0].0, "sma_20");
369 assert!(matches!(indicators[0].1, Indicator::Sma(20)));
370 }
371}