ta_lib_in_rust/indicators/stats/
beta.rs1use crate::util::dataframe_utils::check_window_size;
2use polars::prelude::*;
3
4pub fn calculate_beta(
17 df: &DataFrame,
18 price_column: &str,
19 market_column: &str,
20 window: usize,
21) -> PolarsResult<Series> {
22 check_window_size(df, window, "Beta")?;
23
24 if !df.schema().contains(price_column) || !df.schema().contains(market_column) {
25 return Err(PolarsError::ComputeError(
26 format!("Beta calculation requires {price_column} and {market_column} columns").into(),
27 ));
28 }
29
30 let price = df.column(price_column)?.f64()?;
31 let market = df.column(market_column)?.f64()?;
32
33 let mut beta_values = Vec::with_capacity(df.height());
34
35 for _ in 0..window - 1 {
37 beta_values.push(f64::NAN);
38 }
39
40 for i in window - 1..df.height() {
42 let mut sum_xy = 0.0;
43 let mut sum_x = 0.0;
44 let mut sum_y = 0.0;
45 let mut sum_x2 = 0.0;
46 let mut count = 0;
47
48 for j in 0..window {
49 let x_idx = i - j;
50 let x = market.get(x_idx).unwrap_or(f64::NAN);
51 let y = price.get(x_idx).unwrap_or(f64::NAN);
52
53 if !x.is_nan() && !y.is_nan() {
54 sum_xy += x * y;
55 sum_x += x;
56 sum_y += y;
57 sum_x2 += x * x;
58 count += 1;
59 }
60 }
61
62 if count > 1 {
63 let numerator = (count as f64 * sum_xy) - (sum_x * sum_y);
65 let denominator = (count as f64 * sum_x2) - (sum_x * sum_x);
66
67 if denominator != 0.0 {
68 beta_values.push(numerator / denominator);
69 } else {
70 beta_values.push(f64::NAN);
71 }
72 } else {
73 beta_values.push(f64::NAN);
74 }
75 }
76
77 Ok(Series::new("beta".into(), beta_values))
78}