use crate::forecast_trade::error::Result;
use crate::forecast_trade::models::garch::GarchModel;
use crate::forecast_trade::models::ForecastModel;
pub fn historical_volatility(returns: &[f64], window: usize) -> Vec<f64> {
if returns.len() < window || window == 0 {
return vec![0.0; returns.len()];
}
let mut volatility = vec![0.0; returns.len()];
for i in window..returns.len() {
let window_data = &returns[i - window..i];
let mean = window_data.iter().sum::<f64>() / window as f64;
let variance = window_data.iter()
.map(|&x| (x - mean).powi(2))
.sum::<f64>() / window as f64;
volatility[i] = variance;
}
volatility
}
pub fn calculate_returns(prices: &[f64]) -> Vec<f64> {
if prices.len() < 2 {
return Vec::new();
}
prices.windows(2)
.map(|w| (w[1] / w[0]) - 1.0)
.collect()
}
pub fn forecast_volatility(prices: &[f64], forecast_horizon: usize) -> Result<Vec<f64>> {
let returns = calculate_returns(prices);
let mut model = GarchModel::new(1, 1);
model.fit(&returns)?;
let forecast = model.forecast(forecast_horizon)?;
Ok(forecast.values)
}
pub fn annualize_daily_volatility(daily_volatility: f64) -> f64 {
daily_volatility.sqrt() * (252_f64).sqrt()
}
pub fn ewma_volatility(returns: &[f64], lambda: f64) -> Vec<f64> {
if returns.is_empty() {
return Vec::new();
}
let mut volatility = vec![0.0; returns.len()];
volatility[0] = returns[0].powi(2);
for i in 1..returns.len() {
volatility[i] = lambda * volatility[i-1] + (1.0 - lambda) * returns[i].powi(2);
}
volatility
}