trading_toolkit/indicator/
channel.rs1use 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}