ta_lib_in_rust/indicators/math/
mod.rs1use polars::prelude::*;
2
3pub fn calculate_add(df: &DataFrame, col1: &str, col2: &str) -> PolarsResult<Series> {
15 if !df.schema().contains(col1) || !df.schema().contains(col2) {
16 return Err(PolarsError::ComputeError(
17 format!("Addition requires both {col1} and {col2} columns").into()
18 ));
19 }
20
21 let series1 = df.column(col1)?.f64()?;
22 let series2 = df.column(col2)?.f64()?;
23
24 let result = series1 + series2;
25
26 Ok(result.with_name(format!("{col1}_add_{col2}").into()).into())
27}
28
29pub fn calculate_sub(df: &DataFrame, col1: &str, col2: &str) -> PolarsResult<Series> {
41 if !df.schema().contains(col1) || !df.schema().contains(col2) {
42 return Err(PolarsError::ComputeError(
43 format!("Subtraction requires both {col1} and {col2} columns").into()
44 ));
45 }
46
47 let series1 = df.column(col1)?.f64()?;
48 let series2 = df.column(col2)?.f64()?;
49
50 let result = series1 - series2;
51
52 Ok(result.with_name(format!("{col1}_sub_{col2}").into()).into())
53}
54
55pub fn calculate_mult(df: &DataFrame, col1: &str, col2: &str) -> PolarsResult<Series> {
67 if !df.schema().contains(col1) || !df.schema().contains(col2) {
68 return Err(PolarsError::ComputeError(
69 format!("Multiplication requires both {col1} and {col2} columns").into()
70 ));
71 }
72
73 let series1 = df.column(col1)?.f64()?;
74 let series2 = df.column(col2)?.f64()?;
75
76 let result = series1 * series2;
77
78 Ok(result.with_name(format!("{col1}_mult_{col2}").into()).into())
79}
80
81pub fn calculate_div(df: &DataFrame, col1: &str, col2: &str) -> PolarsResult<Series> {
93 if !df.schema().contains(col1) || !df.schema().contains(col2) {
94 return Err(PolarsError::ComputeError(
95 format!("Division requires both {col1} and {col2} columns").into()
96 ));
97 }
98
99 let series1 = df.column(col1)?.f64()?;
100 let series2 = df.column(col2)?.f64()?;
101
102 let mut div_values = Vec::with_capacity(df.height());
104
105 for i in 0..df.height() {
106 let num = series1.get(i).unwrap_or(f64::NAN);
107 let denom = series2.get(i).unwrap_or(f64::NAN);
108
109 if denom != 0.0 && !denom.is_nan() && !num.is_nan() {
110 div_values.push(num / denom);
111 } else {
112 div_values.push(f64::NAN);
113 }
114 }
115
116 Ok(Series::new(format!("{col1}_div_{col2}").into(), div_values))
117}
118
119pub fn calculate_max(df: &DataFrame, column: &str, window: usize) -> PolarsResult<Series> {
131 if !df.schema().contains(column) {
132 return Err(PolarsError::ComputeError(
133 format!("MAX calculation requires {column} column").into()
134 ));
135 }
136
137 let series = df.column(column)?.f64()?;
138
139 let mut max_values = Vec::with_capacity(df.height());
140
141 for i in 0..window-1 {
143 max_values.push(f64::NAN);
144 }
145
146 for i in window-1..df.height() {
148 let mut max_val = f64::NEG_INFINITY;
149 let mut all_nan = true;
150
151 for j in 0..window {
152 let val = series.get(i - j).unwrap_or(f64::NAN);
153 if !val.is_nan() {
154 max_val = max_val.max(val);
155 all_nan = false;
156 }
157 }
158
159 if all_nan {
160 max_values.push(f64::NAN);
161 } else {
162 max_values.push(max_val);
163 }
164 }
165
166 Ok(Series::new(format!("{column}_max_{window}").into(), max_values))
167}
168
169pub fn calculate_min(df: &DataFrame, column: &str, window: usize) -> PolarsResult<Series> {
181 if !df.schema().contains(column) {
182 return Err(PolarsError::ComputeError(
183 format!("MIN calculation requires {column} column").into()
184 ));
185 }
186
187 let series = df.column(column)?.f64()?;
188
189 let mut min_values = Vec::with_capacity(df.height());
190
191 for i in 0..window-1 {
193 min_values.push(f64::NAN);
194 }
195
196 for i in window-1..df.height() {
198 let mut min_val = f64::INFINITY;
199 let mut all_nan = true;
200
201 for j in 0..window {
202 let val = series.get(i - j).unwrap_or(f64::NAN);
203 if !val.is_nan() {
204 min_val = min_val.min(val);
205 all_nan = false;
206 }
207 }
208
209 if all_nan {
210 min_values.push(f64::NAN);
211 } else {
212 min_values.push(min_val);
213 }
214 }
215
216 Ok(Series::new(format!("{column}_min_{window}").into(), min_values))
217}
218
219pub fn calculate_sum(df: &DataFrame, column: &str, window: usize) -> PolarsResult<Series> {
231 if !df.schema().contains(column) {
232 return Err(PolarsError::ComputeError(
233 format!("SUM calculation requires {column} column").into()
234 ));
235 }
236
237 let series = df.column(column)?.f64()?;
238
239 let mut sum_values = Vec::with_capacity(df.height());
240
241 for i in 0..window-1 {
243 sum_values.push(f64::NAN);
244 }
245
246 for i in window-1..df.height() {
248 let mut sum = 0.0;
249 let mut all_nan = true;
250
251 for j in 0..window {
252 let val = series.get(i - j).unwrap_or(f64::NAN);
253 if !val.is_nan() {
254 sum += val;
255 all_nan = false;
256 }
257 }
258
259 if all_nan {
260 sum_values.push(f64::NAN);
261 } else {
262 sum_values.push(sum);
263 }
264 }
265
266 Ok(Series::new(format!("{column}_sum_{window}").into(), sum_values))
267}