1use crate::{Interval, Series};
2use serde::{Deserialize, Serialize};
3use std::collections::{HashMap, VecDeque};
4use std::fmt;
5
6use self::{
7 bollinger::calculate_bollinger_bands,
8 ema::{calculate_ema, calculate_ema_slice},
9 macd::calculate_macd,
10 rsi::calculate_rsi,
11 sma::calculate_sma,
12 stochastic::calculate_stochastic,
13};
14
15pub(crate) mod bollinger;
16pub(crate) mod ema;
17pub(crate) mod macd;
18pub(crate) mod rsi;
19pub(crate) mod sma;
20pub(crate) mod stochastic;
21
22#[derive(Debug, Serialize, Deserialize)]
24pub struct EnhancedMarketSeries {
25 pub symbol: String,
27 pub interval: Interval,
29 pub series: Vec<Series>,
31 pub asks: Vec<Ask>,
33 pub indicators: Indicators,
35}
36
37#[derive(Debug, Serialize, Deserialize)]
38pub enum Ask {
39 SMA(usize),
40 EMA(usize),
41 RSI(usize),
42 Stochastic(usize),
43 MACD(usize, usize, usize),
44 BB(usize, usize),
45}
46
47#[derive(Debug, Default, Serialize, Deserialize)]
49pub struct Indicators {
50 pub sma: HashMap<String, VecDeque<f32>>,
52 pub ema: HashMap<String, VecDeque<f32>>,
54 pub rsi: HashMap<String, VecDeque<f32>>,
56 pub stochastic: HashMap<String, VecDeque<f32>>,
58 pub macd: HashMap<String, (VecDeque<f32>, VecDeque<f32>, VecDeque<f32>)>,
60 pub bb: HashMap<String, (VecDeque<f32>, VecDeque<f32>, VecDeque<f32>)>,
62}
63
64impl EnhancedMarketSeries {
65 pub fn with_sma(mut self, period: usize) -> Self {
67 self.asks.push(Ask::SMA(period));
68 self
69 }
70
71 pub fn with_ema(mut self, period: usize) -> Self {
73 self.asks.push(Ask::EMA(period));
74 self
75 }
76
77 pub fn with_rsi(mut self, period: usize) -> Self {
79 self.asks.push(Ask::RSI(period));
80 self
81 }
82
83 pub fn with_stochastic(mut self, period: usize) -> Self {
85 self.asks.push(Ask::Stochastic(period));
86 self
87 }
88
89 pub fn with_macd(mut self, fast: usize, slow: usize, signal: usize) -> Self {
91 self.asks.push(Ask::MACD(fast, slow, signal));
92 self
93 }
94
95 pub fn with_bb(mut self, period: usize, std_dev: usize) -> Self {
97 self.asks.push(Ask::BB(period, std_dev));
98 self
99 }
100
101 pub fn calculate(mut self) -> Self {
103 self.asks.iter().for_each(|ind| match ind {
104 Ask::SMA(period) => {
105 let calc_sma = calculate_sma(&self.series, period.clone());
106 self.indicators
107 .sma
108 .insert(format!("SMA {}", period), calc_sma);
109 }
110
111 Ask::EMA(period) => {
112 let calc_ema = calculate_ema(&self.series, period.clone());
113 self.indicators
114 .ema
115 .insert(format!("EMA {}", period), calc_ema);
116 }
117
118 Ask::RSI(period) => {
119 let calc_rsi = calculate_rsi(&self.series, period.clone());
120 self.indicators
121 .rsi
122 .insert(format!("RSI {}", period), calc_rsi);
123 }
124
125 Ask::Stochastic(period) => {
126 let calc_stoch = calculate_stochastic(&self.series, period.clone());
127 self.indicators
128 .stochastic
129 .insert(format!("STO {}", period), calc_stoch);
130 }
131
132 Ask::MACD(fast, slow, signal) => {
133 let (calc_macd, calc_signal, calc_histogram) =
134 calculate_macd(&self.series, fast.clone(), slow.clone(), signal.clone());
135
136 self.indicators.macd.insert(
137 format!("MACD ({}, {}, {})", fast, slow, signal),
138 (calc_macd, calc_signal, calc_histogram),
139 );
140 }
141 Ask::BB(period, std_dev) => {
142 let (upper_band, mid_band, lower_band) =
143 calculate_bollinger_bands(&self.series, period.clone(), std_dev.clone());
144
145 self.indicators.bb.insert(
146 format!("BB ({}, {})", period, std_dev),
147 (upper_band, mid_band, lower_band),
148 );
149 }
150 });
151
152 self
153 }
154}
155
156impl fmt::Display for Ask {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 match self {
159 Ask::SMA(period) => write!(f, "SMA({})", period),
160 Ask::EMA(period) => write!(f, "EMA({})", period),
161 Ask::RSI(period) => write!(f, "RSI({})", period),
162 Ask::MACD(fast, slow, signal) => write!(f, "MACD({}, {}, {})", fast, slow, signal),
163 Ask::Stochastic(period) => write!(f, "STO({})", period),
164 Ask::BB(period, std_dev) => write!(f, "BB({}, {})", period, std_dev),
165 }
166 }
167}
168
169impl fmt::Display for EnhancedMarketSeries {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(
172 f,
173 "EnhancedMarketSerie: Symbol = {}, Interval = {}, Requested Indicators: {:?}, Series: \n",
174 self.symbol, self.interval, self.asks
175 )?;
176 for (i, series) in self.series.iter().enumerate() {
177 write!(
178 f,
179 "Date: {}, Open: {:.2}, Close: {:.2}, High: {:.2}, Low: {:.2}, Volume: {:.2}, ",
180 series.date, series.open, series.close, series.high, series.low, series.volume
181 )?;
182
183 for (indicator_name, indicator_values) in &self.indicators.sma {
184 if let Some(value) = indicator_values.get(i) {
185 write!(f, "{}: {:.2}, ", indicator_name, value)?;
186 }
187 }
188
189 for (indicator_name, indicator_values) in &self.indicators.ema {
190 if let Some(value) = indicator_values.get(i) {
191 write!(f, "{}: {:.2}, ", indicator_name, value)?;
192 }
193 }
194
195 for (indicator_name, indicator_values) in &self.indicators.rsi {
196 if let Some(value) = indicator_values.get(i) {
197 write!(f, "{}: {:.2}, ", indicator_name, value)?;
198 }
199 }
200
201 for (indicator_name, indicator_values) in &self.indicators.stochastic {
202 if let Some(value) = indicator_values.get(i) {
203 write!(f, "{}: {:.2}, ", indicator_name, value)?;
204 }
205 }
206
207 for (indicator_name, (macd, signal, histogram)) in &self.indicators.macd {
208 if let Some(macd_value) = macd.get(i) {
209 if let Some(signal_value) = signal.get(i) {
210 if let Some(hist_value) = histogram.get(i) {
211 write!(
212 f,
213 "{}: {:.2}, {:.2}, {:.2}, ",
214 indicator_name, macd_value, signal_value, hist_value
215 )?;
216 }
217 }
218 }
219 }
220
221 for (indicator_name, (upper_band, mid_band, lower_band)) in &self.indicators.bb {
222 if let Some(upper_band) = upper_band.get(i) {
223 if let Some(mid_band) = mid_band.get(i) {
224 if let Some(lower_band) = lower_band.get(i) {
225 write!(
226 f,
227 "{}: {:.2}, {:.2}, {:.2}, ",
228 indicator_name, upper_band, mid_band, lower_band
229 )?;
230 }
231 }
232 }
233 }
234
235 if i < self.series.len() - 1 {
239 writeln!(f, ",")?;
240 }
241 }
242
243 Ok(())
244 }
245}