Skip to main content

mantis_ta/indicators/support_resistance/
pivot_points.rs

1use crate::indicators::Indicator;
2use crate::types::{Candle, PivotOutput};
3
4/// Classic floor-trader pivot points calculated from a single candle's OHLC.
5///
6/// # Examples
7/// ```rust
8/// use mantis_ta::indicators::{Indicator, PivotPoints};
9/// use mantis_ta::types::Candle;
10///
11/// let candles: Vec<Candle> = vec![
12///     (1.0, 0.5, 0.8),
13///     (2.0, 0.5, 1.5),
14///     (3.0, 1.0, 2.5),
15/// ]
16/// .into_iter()
17/// .enumerate()
18/// .map(|(i, (h, l, c))| Candle {
19///     timestamp: i as i64,
20///     open: c,
21///     high: h,
22///     low: l,
23///     close: c,
24///     volume: 0.0,
25/// })
26/// .collect();
27///
28/// let out = PivotPoints::new().calculate(&candles);
29/// assert!(out.iter().all(|v| v.is_some()));
30/// ```
31#[derive(Debug, Clone)]
32pub struct PivotPoints;
33
34impl PivotPoints {
35    pub fn new() -> Self {
36        Self
37    }
38}
39
40impl Default for PivotPoints {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl Indicator for PivotPoints {
47    type Output = PivotOutput;
48
49    fn next(&mut self, candle: &Candle) -> Option<Self::Output> {
50        let pp = (candle.high + candle.low + candle.close) / 3.0;
51        let r1 = 2.0 * pp - candle.low;
52        let s1 = 2.0 * pp - candle.high;
53        let r2 = pp + (candle.high - candle.low);
54        let s2 = pp - (candle.high - candle.low);
55        let r3 = candle.high + 2.0 * (pp - candle.low);
56        let s3 = candle.low - 2.0 * (candle.high - pp);
57
58        Some(PivotOutput {
59            pp,
60            r1,
61            r2,
62            r3,
63            s1,
64            s2,
65            s3,
66        })
67    }
68
69    fn reset(&mut self) {}
70
71    fn warmup_period(&self) -> usize {
72        0
73    }
74
75    fn clone_boxed(&self) -> Box<dyn Indicator<Output = Self::Output>> {
76        Box::new(self.clone())
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn computes_pivots() {
86        let mut pivots = PivotPoints::new();
87        let candle = Candle {
88            timestamp: 0,
89            open: 0.0,
90            high: 12.0,
91            low: 8.0,
92            close: 10.0,
93            volume: 0.0,
94        };
95        let out = pivots.next(&candle).unwrap();
96        assert_eq!(out.pp, 10.0);
97        assert_eq!(out.r1, 12.0);
98        assert_eq!(out.s1, 8.0);
99    }
100}