Documentation
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,
    }
}