Skip to main content

finance_query/backtesting/refs/
volume.rs

1use crate::backtesting::strategy::StrategyContext;
2use crate::indicators::Indicator;
3
4use super::IndicatorRef;
5
6/// On-Balance Volume reference.
7#[derive(Debug, Clone, Copy)]
8pub struct ObvRef;
9
10impl IndicatorRef for ObvRef {
11    fn key(&self) -> &str {
12        "obv"
13    }
14
15    fn required_indicators(&self) -> Vec<(String, Indicator)> {
16        vec![("obv".to_string(), Indicator::Obv)]
17    }
18
19    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
20        ctx.indicator(self.key())
21    }
22
23    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
24        ctx.indicator_prev(self.key())
25    }
26}
27
28/// Create an On-Balance Volume reference.
29#[inline]
30pub fn obv() -> ObvRef {
31    ObvRef
32}
33
34/// Volume Weighted Average Price reference.
35#[derive(Debug, Clone, Copy)]
36pub struct VwapRef;
37
38impl IndicatorRef for VwapRef {
39    fn key(&self) -> &str {
40        "vwap"
41    }
42
43    fn required_indicators(&self) -> Vec<(String, Indicator)> {
44        vec![("vwap".to_string(), Indicator::Vwap)]
45    }
46
47    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
48        ctx.indicator(self.key())
49    }
50
51    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
52        ctx.indicator_prev(self.key())
53    }
54}
55
56/// Create a Volume Weighted Average Price reference.
57#[inline]
58pub fn vwap() -> VwapRef {
59    VwapRef
60}
61
62/// Chaikin Money Flow reference.
63#[derive(Debug, Clone)]
64pub struct CmfRef {
65    pub period: usize,
66    key: String,
67}
68
69impl IndicatorRef for CmfRef {
70    fn key(&self) -> &str {
71        &self.key
72    }
73
74    fn required_indicators(&self) -> Vec<(String, Indicator)> {
75        vec![(self.key.clone(), Indicator::Cmf(self.period))]
76    }
77
78    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
79        ctx.indicator(self.key())
80    }
81
82    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
83        ctx.indicator_prev(self.key())
84    }
85}
86
87/// Create a Chaikin Money Flow reference.
88#[inline]
89pub fn cmf(period: usize) -> CmfRef {
90    CmfRef {
91        period,
92        key: format!("cmf_{period}"),
93    }
94}
95
96/// Accumulation/Distribution reference.
97#[derive(Debug, Clone, Copy)]
98pub struct AccumulationDistributionRef;
99
100/// Create an Accumulation/Distribution reference.
101#[inline]
102pub fn accumulation_distribution() -> AccumulationDistributionRef {
103    AccumulationDistributionRef
104}
105
106impl IndicatorRef for AccumulationDistributionRef {
107    fn key(&self) -> &str {
108        "ad"
109    }
110
111    fn required_indicators(&self) -> Vec<(String, Indicator)> {
112        vec![("ad".to_string(), Indicator::AccumulationDistribution)]
113    }
114
115    fn value(&self, ctx: &StrategyContext) -> Option<f64> {
116        ctx.indicator(self.key())
117    }
118
119    fn prev_value(&self, ctx: &StrategyContext) -> Option<f64> {
120        ctx.indicator_prev(self.key())
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127    use crate::backtesting::refs::{balance_of_power, chaikin_oscillator, mfi};
128
129    #[test]
130    fn test_volume_keys() {
131        assert_eq!(obv().key(), "obv");
132        assert_eq!(vwap().key(), "vwap");
133        assert_eq!(mfi(14).key(), "mfi_14");
134        assert_eq!(cmf(20).key(), "cmf_20");
135        assert_eq!(chaikin_oscillator().key(), "chaikin_osc");
136        assert_eq!(accumulation_distribution().key(), "ad");
137        assert_eq!(balance_of_power(Some(14)).key(), "bop_14");
138        assert_eq!(balance_of_power(None).key(), "bop");
139    }
140}