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: &[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>(data: &[T], dev_mul: f64, exponential: bool) -> Result<Self, ToolkitError>
47 where
48 T: Candle + BaseData + Clone,
49 {
50 if data.len() == 0 {
51 return Err(ToolkitError::EmptyData);
52 }
53 let mut data = data.to_owned();
54 data.sort_by_key(|k| Candle::epoch_time(k));
55 let mut sum = 0f64;
56 let mut variation = 0f64;
57
58 for elem in data.iter() {
59 sum += elem.close_price();
60 }
61 let mean = sum / (data.len() as f64);
62 for elem in data.iter() {
63 variation += (mean - elem.close_price()).powi(2);
64 }
65 let stdev = (variation / data.len() as f64).sqrt();
66
67 let mid = if exponential {
68 MovingAverage::exponential(&data).inner()
69 } else {
70 mean
71 };
72 let upper = mid + dev_mul * stdev;
73 let lower = mid - dev_mul * stdev;
74
75 Ok(Self::Bollinger(Band { upper, mid, lower }))
76 }
77}