Skip to main content

trading_toolkit/indicator/
channel.rs

1use super::MovingAverage;
2use crate::types::{
3    data::{BaseData, Candle},
4    error::ToolkitError,
5};
6
7#[derive(Debug, Clone, Copy)]
8pub enum Channel {
9    Envelope(Band),
10    Bollinger(Band),
11}
12
13#[derive(Debug, Clone, Copy)]
14pub struct Band {
15    pub upper: f64,
16    pub mid: f64,
17    pub lower: f64,
18}
19
20impl Channel {
21    pub fn inner(&self) -> Band {
22        match self {
23            Channel::Envelope(band) | Channel::Bollinger(band) => band.clone(),
24        }
25    }
26    pub fn envelope<T>(data: &Vec<T>, coefficient: f64) -> Self
27    where
28        T: BaseData + Clone,
29    {
30        let ema = MovingAverage::exponential(&data).inner();
31        Self::Envelope(Band {
32            upper: ema * (1f64 + coefficient),
33            mid: ema,
34            lower: ema * (1f64 - coefficient),
35        })
36    }
37    pub fn envelope_from(ema: MovingAverage, coefficient: f64) -> Self {
38        let ema = ema.inner();
39        Self::Envelope(Band {
40            upper: ema * (1f64 + coefficient),
41            mid: ema,
42            lower: ema * (1f64 - coefficient),
43        })
44    }
45
46    pub fn bollinger<T>(
47        data: &Vec<T>,
48        dev_mul: f64,
49        exponential: bool,
50    ) -> Result<Self, ToolkitError>
51    where
52        T: Candle + BaseData + Clone,
53    {
54        if data.len() == 0 {
55            return Err(ToolkitError::EmptyData);
56        }
57        let mut data = data.clone().to_owned();
58        data.sort_by_key(|k| Candle::epoch_time(k));
59        let mut sum = 0f64;
60        let mut variation = 0f64;
61
62        for elem in data.iter() {
63            sum += elem.close_price();
64        }
65        let mean = sum / (data.len() as f64);
66        for elem in data.iter() {
67            variation += (mean - elem.close_price()).powi(2);
68        }
69        let stdev = (variation / data.len() as f64).sqrt();
70
71        let mid = if exponential {
72            MovingAverage::exponential(&data).inner()
73        } else {
74            mean
75        };
76        let upper = mid + dev_mul * stdev;
77        let lower = mid - dev_mul * stdev;
78
79        Ok(Self::Bollinger(Band { upper, mid, lower }))
80    }
81}