use std::collections::VecDeque;
use crate::strategy_engine::Strategy;
#[derive(Debug, Clone)]
pub struct BollingerBands {
pub prices: VecDeque<f64>,
pub window_size: usize,
}
impl BollingerBands {
pub fn new(window_size: usize) -> Self {
Self {
prices: VecDeque::with_capacity(window_size),
window_size,
}
}
pub fn update_price(&mut self, price: f64) {
self.prices.push_back(price);
if self.prices.len() > self.prices.capacity() {
self.prices.pop_front();
}
}
}
impl Strategy for BollingerBands {
fn evaluate(&self, price: &f64) -> f64 {
let avg = self.prices.iter().sum::<f64>() / self.prices.len() as f64;
let std_dev = (self.prices.iter().map(|x| (x - avg).powi(2)).sum::<f64>() / self.prices.len() as f64).sqrt();
let lower_band = avg - 2.0 * std_dev;
let upper_band = avg + 2.0 * std_dev;
if *price < lower_band {
1.0 } else if *price > upper_band {
-1.0 } else {
0.0 }
}
fn calculate_indicator(&self, prices: &Vec<f64>) -> f64 {
let mut max_drawdown = 0.0;
let mut peak = prices[0];
for price in prices {
if *price > peak {
peak = *price;
} else {
max_drawdown = max_f64(max_drawdown,1.0 - (*price / peak));
}
}
max_drawdown }
}
fn max_f64(a: f64, b: f64) -> f64 {
match a.partial_cmp(&b) {
Some(std::cmp::Ordering::Greater) => a,
_ => b,
}
}