ta_lib_in_rust/indicators/volatility/
gk_volatility.rs

1use polars::prelude::*;
2
3/// Calculates Garman-Klass volatility estimator (uses OHLC data)
4///
5/// # Arguments
6///
7/// * `df` - DataFrame containing the price data
8/// * `window` - Window size for smoothing (typically 10)
9///
10/// # Returns
11///
12/// Returns a PolarsResult containing the GK volatility Series
13pub fn calculate_gk_volatility(df: &DataFrame, window: usize) -> PolarsResult<Series> {
14    let high = df.column("high")?.f64()?;
15    let low = df.column("low")?.f64()?;
16    let open = df.column("open")?.f64()?;
17    let close = df.column("close")?.f64()?;
18
19    let mut gk_values = Vec::with_capacity(df.height());
20
21    for i in 0..df.height() {
22        let h = high.get(i).unwrap_or(0.0);
23        let l = low.get(i).unwrap_or(0.0);
24        let o = open.get(i).unwrap_or(0.0);
25        let c = close.get(i).unwrap_or(0.0);
26
27        if h > 0.0 && l > 0.0 && o > 0.0 {
28            let hl = (h / l).ln().powi(2) * 0.5;
29            let co = (c / o).ln().powi(2);
30            gk_values.push(hl - (2.0 * 0.386) * co);
31        } else {
32            gk_values.push(0.0);
33        }
34    }
35
36    let gk_series = Series::new("gk_raw".into(), gk_values);
37
38    // Apply rolling mean to get smoother estimate
39    let gk_volatility = gk_series.rolling_mean(RollingOptionsFixedWindow {
40        window_size: window,
41        min_periods: 1, // Allow calculation with fewer values
42        center: false,
43        weights: None,
44        fn_params: None,
45    })?;
46
47    Ok(gk_volatility.with_name("gk_volatility".into()))
48}