From 71f9f4a6743e740affa7ecc83af69f7b5191ddfc Mon Sep 17 00:00:00 2001 From: Palash Tyagi <23239946+Magnus167@users.noreply.github.com> Date: Sat, 15 Mar 2025 00:03:09 +0000 Subject: [PATCH] Add logging for historic volatility calculations and implement utility to get min/max real dates --- src/panel/historic_vol.rs | 19 ++++++++++++++++--- src/panel/linear_composite.rs | 0 src/utils/misc.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/panel/linear_composite.rs diff --git a/src/panel/historic_vol.rs b/src/panel/historic_vol.rs index 8b2baa2..01dcbe2 100644 --- a/src/panel/historic_vol.rs +++ b/src/panel/historic_vol.rs @@ -131,9 +131,15 @@ fn freq_period_calc( ); } + println!("Calculating historic volatility with the following parameters:"); + println!("lback_periods: {:?}, lback_method: {:?}, half_life: {:?}, remove_zeros: {:?}, nan_tolerance: {:?}, period: {:?}", lback_periods, lback_method, half_life, remove_zeros, nan_tolerance, period); + let mut new_df = dfw.clone(); for col_name in dfw.get_column_names() { + if col_name == "real_date" { + continue; + } let series = dfw.column(col_name)?; let values: Array1 = series .f64()? @@ -174,7 +180,7 @@ fn freq_period_calc( } _ => return Err("Invalid lookback method.".into()), }; - + println!("Successfully calculated result_series for column: {:?}", col_name); new_df.with_column(result_series)?; } @@ -298,9 +304,14 @@ pub fn historic_vol( println!("Successfully got nan_tolerance."); - let start_date = NaiveDate::parse_from_str(&start, "%Y-%m-%d")?; - let end_date = NaiveDate::parse_from_str(&end, "%Y-%m-%d")?; + let (dfw_start_date, dfw_end_date) = + crate::utils::misc::get_min_max_real_dates(&dfw, "real_date")?; + println!("Successfully got min and max real dates."); + let (start_date, end_date) = ( + NaiveDate::parse_from_str(&start, "%Y-%m-%d").unwrap_or_else(|_| dfw_start_date), + NaiveDate::parse_from_str(&end, "%Y-%m-%d").unwrap_or_else(|_| dfw_end_date), + ); println!("Successfully parsed start and end dates."); dfw = dfw @@ -327,6 +338,8 @@ pub fn historic_vol( _ => return Err("Invalid frequency specified.".into()), }; + println!("Successfully got period."); + let dfw = match est_freq.as_str() { "D" => freq_daily_calc( &dfw, diff --git a/src/panel/linear_composite.rs b/src/panel/linear_composite.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/misc.rs b/src/utils/misc.rs index c664708..678062f 100644 --- a/src/utils/misc.rs +++ b/src/utils/misc.rs @@ -1,3 +1,4 @@ +use chrono::NaiveDate; use polars::prelude::*; use std::collections::HashMap; use std::error::Error; @@ -11,6 +12,35 @@ pub fn split_ticker(ticker: String) -> Result<(String, String), Box> Ok((parts[0].to_string(), parts[1].to_string())) } +pub fn get_min_max_real_dates( + df: &DataFrame, + date_col: &str, +) -> Result<(NaiveDate, NaiveDate), Box> { + let date_series = df.column(date_col)?; + if let DataType::Date = date_series.dtype() { + // Convert the `date` series to an i32 (days since 1970-01-01) + let date_as_days = date_series.cast(&DataType::Int32)?; + let min_days = date_as_days.i32()?.min().ok_or("No minimum value found")?; + let max_days = date_as_days.i32()?.max().ok_or("No maximum value found")?; + + // Convert the days back to `NaiveDate` + let min_date = NaiveDate::from_ymd_opt(1970, 1, 1) + .unwrap() + .checked_add_signed(chrono::Duration::days(min_days as i64)) + .ok_or("Invalid minimum date")?; + let max_date = NaiveDate::from_ymd_opt(1970, 1, 1) + .unwrap() + .checked_add_signed(chrono::Duration::days(max_days as i64)) + .ok_or("Invalid maximum date")?; + + Ok((min_date, max_date)) + } else { + Err(Box::new(polars::error::PolarsError::ComputeError( + "The column is not of Date type".into(), + ))) + } +} + #[allow(dead_code)] pub fn get_cid(ticker: String) -> Result> { split_ticker(ticker).map(|(cid, _)| cid)