ta_statistics/traits/single_statistics.rs
1/// Single statistics trait for calculating statistics on a single value
2///
3/// This trait provides a foundation for calculating various statistics on a single value,
4/// such as mean, variance, standard deviation, and other measures of central tendency and
5/// dispersion. It is used as a base trait for more specific statistical calculations that
6/// examine relationships between variables.
7pub trait SingleStatistics<T> {
8 /// Updates the statistical calculations with a new value in the time series
9 ///
10 /// Incorporates a new data point into the rolling window, maintaining the specified
11 /// window size by removing the oldest value when necessary. This is the core method
12 /// that should be called whenever new data is available for processing.
13 fn next(&mut self, value: T) -> &mut Self
14 where
15 Self: Sized;
16 /// Returns the sum of all values in the rolling window
17 ///
18 /// This fundamental calculation serves as the basis for numerous higher-order statistics
19 /// and provides key insights for:
20 ///
21 /// - Aggregating transaction volumes to identify participant interest levels
22 /// - Constructing accumulation/distribution profiles across price action
23 /// - Measuring net directional pressure in time series data
24 /// - Quantifying capital flows between market segments
25 ///
26 /// # Returns
27 ///
28 /// * `Option<T>` - The sum of all values in the window, or `None` if the window is not full
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// # use ta_statistics::{Statistics, SingleStatistics};
34 /// let mut stats = Statistics::new(3);
35 /// let inputs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
36 /// let mut results = vec![];
37 ///
38 /// inputs.iter().for_each(|i| {
39 /// stats.next(*i).sum().map(|v| results.push(v));
40 /// });
41 ///
42 /// let expected = [6.0, 9.0, 12.0, 15.0];
43 /// assert_eq!(&results, &expected);
44 /// ```
45 fn sum(&self) -> Option<T>;
46
47 /// Returns the sum of squares of all values in the rolling window
48 ///
49 /// This calculation provides the sum of squared values in the series, offering insights into
50 /// the magnitude of values regardless of sign:
51 ///
52 /// - Serves as a component for calculating variance and other dispersion measures
53 /// - Emphasizes larger values due to the squaring operation
54 /// - Provides power estimation in signal processing applications
55 /// - Helps detect significant deviations from expected behavior
56 ///
57 /// # Returns
58 ///
59 /// * `Option<T>` - The sum of squares in the window, or `None` if the window is not full
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// # use ta_statistics::{Statistics, SingleStatistics};
65 /// let mut stats = Statistics::new(3);
66 /// let inputs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
67 /// let mut results = vec![];
68 ///
69 /// inputs.iter().for_each(|i| {
70 /// stats.next(*i).sum_sq().map(|v| results.push(v));
71 /// });
72 ///
73 /// let expected = [14.0, 29.0, 50.0, 77.0];
74 /// assert_eq!(&results, &expected);
75 /// ```
76 fn sum_sq(&self) -> Option<T>;
77
78 /// Returns the arithmetic mean of all values in the rolling window
79 ///
80 /// This central tendency measure forms the foundation for numerous statistical calculations
81 /// and serves as a reference point for analyzing data distributions:
82 ///
83 /// - Establishes equilibrium levels for reversion-based analytical models
84 /// - Provides baseline reference for filtering noisy sequential data
85 /// - Creates statistical foundation for pattern detection in time series
86 /// - Enables feature normalization in advanced predictive modeling
87 ///
88 /// # Returns
89 ///
90 /// * `Option<T>` - The arithmetic mean of values in the window, or `None` if the window is not full
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// # use ta_statistics::{Statistics, SingleStatistics};
96 /// let mut stats = Statistics::new(3);
97 /// let inputs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
98 /// let mut results = vec![];
99 ///
100 /// inputs.iter().for_each(|i| {
101 /// stats.next(*i).mean().map(|v| results.push(v));
102 /// });
103 ///
104 /// let expected = [2.0, 3.0, 4.0, 5.0];
105 /// assert_eq!(&results, &expected);
106 /// ```
107 fn mean(&self) -> Option<T>;
108 /// Returns the mean of squares of all values in the rolling window
109 ///
110 /// This calculation provides the average of squared values in the series, offering
111 /// insights into the magnitude of values regardless of sign:
112 ///
113 /// - Serves as a component for calculating variance and other dispersion measures
114 /// - Emphasizes larger values due to the squaring operation
115 /// - Provides power estimation in signal processing applications
116 /// - Helps detect significant deviations from expected behavior
117 ///
118 /// # Returns
119 ///
120 /// * `Option<T>` - The mean of squared values in the window, or `None` if the window is not full
121 ///
122 /// # Examples
123 ///
124 /// ```
125 /// # use ta_statistics::{Statistics, SingleStatistics};
126 /// # use assert_approx_eq::assert_approx_eq;
127 /// let mut stats = Statistics::new(3);
128 /// let inputs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
129 /// let mut results = vec![];
130 ///
131 /// inputs.iter().for_each(|i| {
132 /// stats.next(*i).mean_sq().map(|v| results.push(v));
133 /// });
134 ///
135 /// let expected: [f64; 4] = [4.66, 9.66, 16.66, 25.66];
136 /// for (i, e) in expected.iter().enumerate() {
137 /// assert_approx_eq!(e, results[i], 0.1);
138 /// }
139 /// ```
140 fn mean_sq(&self) -> Option<T>;
141 /// Returns the mode (most frequently occurring value) in the rolling window
142 ///
143 /// The mode identifies the most common value within a distribution, providing
144 /// insight into clustering behavior and prevalent conditions:
145 ///
146 /// - Identifies common price points that may act as magnets or barriers
147 /// - Detects clustering in volume or activity patterns
148 /// - Provides non-parametric central tendency alternative to mean/median
149 /// - Highlights dominant price levels where transactions concentrate
150 ///
151 /// # Returns
152 ///
153 /// * `Option<T>` - The mode of values in the window, or `None` if the window is not full
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// # use ta_statistics::{Statistics, SingleStatistics};
159 /// # use assert_approx_eq::assert_approx_eq;
160 /// let mut stats = Statistics::new(3);
161 /// let inputs = [1.0, 2.0, 1.0, 2.0, 3.0, 3.0, 3.0, 2.0, 2.0, 1.0];
162 /// let mut results = vec![];
163 ///
164 /// inputs.iter().for_each(|i| {
165 /// stats.next(*i).mode().map(|v| results.push(v));
166 /// });
167 ///
168 /// let expected: [f64; 8] = [1.0, 2.0, 1.0, 3.0, 3.0, 3.0, 2.0, 2.0];
169 /// assert_eq!(&results, &expected);
170 /// ```
171 fn mode(&mut self) -> Option<T>;
172 /// Returns the median (middle value) of the rolling window
173 ///
174 /// The median represents the central value when data is sorted, providing a robust
175 /// measure of central tendency that's less affected by outliers than the mean:
176 ///
177 /// - Offers resilient central price estimation in volatile conditions
178 /// - Establishes more stable reference points during extreme events
179 /// - Provides core input for non-parametric statistical models
180 /// - Creates baseline for interquartile range and other robust dispersion measures
181 ///
182 /// # Returns
183 ///
184 /// * `Option<T>` - The median of values in the window, or `None` if the window is not full
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// # use ta_statistics::{Statistics, SingleStatistics};
190 /// # use assert_approx_eq::assert_approx_eq;
191 /// let mut stats = Statistics::new(3);
192 /// let inputs = [5.0, 2.0, 8.0, 1.0, 7.0, 3.0, 9.0];
193 /// let mut results = vec![];
194 ///
195 /// inputs.iter().for_each(|i| {
196 /// stats.next(*i).median().map(|v| results.push(v));
197 /// });
198 ///
199 /// let expected: [f64; 5] = [5.0, 2.0, 7.0, 3.0, 7.0];
200 /// assert_eq!(&results, &expected);
201 /// ```
202 fn median(&mut self) -> Option<T>;
203 /// Returns the minimum value in the rolling window
204 ///
205 /// The minimum value represents the lower bound of a data series over the observation
206 /// period, providing key reference points for analysis and decision-making:
207 ///
208 /// - Establishes potential support levels in price-based analysis
209 /// - Identifies optimal entry thresholds for mean-reverting sequences
210 /// - Sets critical risk boundaries for position management systems
211 /// - Provides baseline scenarios for stress-testing and risk modeling
212 ///
213 /// # Returns
214 ///
215 /// * `Option<T>` - The minimum value in the window, or `None` if the window is not full
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// # use ta_statistics::{Statistics, SingleStatistics};
221 /// # use assert_approx_eq::assert_approx_eq;
222 /// let mut stats = Statistics::new(3);
223 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
224 /// let mut results = vec![];
225 ///
226 /// inputs.iter().for_each(|i| {
227 /// stats.next(*i).min().map(|v| results.push(v));
228 /// });
229 ///
230 /// let expected: [f64; 7] = [25.4, 26.0, 25.8, 25.8, 25.8, 25.9, 26.2];
231 /// assert_eq!(&results, &expected);
232 /// ```
233 fn min(&mut self) -> Option<T>;
234 /// Returns the maximum value in the rolling window
235 ///
236 /// The maximum value identifies the upper bound of a data series over the observation
237 /// period, establishing crucial reference points for analytical frameworks:
238 ///
239 /// - Identifies potential resistance zones in technical analysis
240 /// - Optimizes profit-taking thresholds based on historical precedent
241 /// - Confirms genuine breakouts from established trading ranges
242 /// - Defines upper boundaries for range-bound trading approaches
243 ///
244 /// # Returns
245 ///
246 /// * `Option<T>` - The maximum value in the window, or `None` if the window is not full
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// # use ta_statistics::{Statistics, SingleStatistics};
252 /// # use assert_approx_eq::assert_approx_eq;
253 /// let mut stats = Statistics::new(3);
254 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
255 /// let mut results = vec![];
256 ///
257 /// inputs.iter().for_each(|i| {
258 /// stats.next(*i).max().map(|v| results.push(v));
259 /// });
260 ///
261 /// let expected: [f64; 7] = [26.2, 26.2, 26.1, 26.1, 26.3, 26.3, 26.5];
262 /// assert_eq!(&results, &expected);
263 /// ```
264 fn max(&mut self) -> Option<T>;
265 /// Returns the mean absolute deviation of values in the rolling window
266 ///
267 /// This robust dispersion measure calculates the average absolute difference from the mean,
268 /// offering advantages over variance in certain analytical contexts:
269 ///
270 /// - Provides volatility measurement that's less sensitive to extreme outliers
271 /// - Quantifies data noise levels to enhance signal processing accuracy
272 /// - Complements standard risk models with an alternative dispersion metric
273 /// - Establishes more stable thresholds for adaptive signal generation
274 ///
275 /// # Returns
276 ///
277 /// * `Option<T>` - The mean absolute deviation of values, or `None` if the window is not full
278 ///
279 /// # Examples
280 ///
281 /// ```
282 /// # use ta_statistics::{Statistics, SingleStatistics};
283 /// # use assert_approx_eq::assert_approx_eq;
284 /// let mut stats = Statistics::new(3);
285 /// let mut results = vec![];
286 /// let inputs = [2.0, 4.0, 6.0, 8.0, 10.0];
287 /// inputs.iter().for_each(|i| {
288 /// stats.next(*i).mean_absolute_deviation().map(|v| results.push(v));
289 /// });
290 ///
291 /// let expected: [f64; 3] = [1.3333, 1.3333, 1.3333];
292 /// for (i, e) in expected.iter().enumerate() {
293 /// assert_approx_eq!(e, results[i], 0.1);
294 /// }
295 ///
296 /// ```
297 fn mean_absolute_deviation(&self) -> Option<T>;
298 /// Returns the median absolute deviation of values in the rolling window
299 ///
300 /// This exceptionally robust dispersion measure calculates the median of absolute differences
301 /// from the median, offering superior resistance to outliers:
302 ///
303 /// - Provides reliable volatility assessment in erratic or noisy environments
304 /// - Serves as a foundation for robust anomaly detection systems
305 /// - Enables stable threshold calibration for adaptive decision systems
306 /// - Forms basis for robust statistical estimators in non-normal distributions
307 ///
308 /// # Returns
309 ///
310 /// * `Option<T>` - The median absolute deviation of values, or `None` if the window is not full
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// # use ta_statistics::{Statistics, SingleStatistics};
316 /// # use assert_approx_eq::assert_approx_eq;
317 /// let mut stats = Statistics::new(3);
318 /// let mut results = vec![];
319 /// let inputs = [5.0, 2.0, 8.0, 1.0, 7.0, 3.0, 9.0];
320 /// inputs.iter().for_each(|i| {
321 /// stats.next(*i).median_absolute_deviation().map(|v| results.push(v));
322 /// });
323 ///
324 /// let expected: [f64; 5] = [3.0, 1.0, 1.0, 2.0, 2.0];
325 /// for (i, e) in expected.iter().enumerate() {
326 /// assert_approx_eq!(e, results[i], 0.1);
327 /// }
328 ///
329 /// ```
330 fn median_absolute_deviation(&mut self) -> Option<T>;
331 /// Returns the variance of values in the rolling window
332 ///
333 /// This second-moment statistical measure quantifies dispersion around the mean
334 /// and serves multiple analytical purposes:
335 ///
336 /// - Providing core risk assessment metrics for position sizing decisions
337 /// - Enabling volatility regime detection to adapt methodologies appropriately
338 /// - Filtering signal noise to improve discriminatory power
339 /// - Identifying dispersion-based opportunities in related instrument groups
340 ///
341 /// # Returns
342 ///
343 /// * `Option<T>` - The variance of values in the window, or `None` if the window is not full
344 ///
345 /// # Examples
346 ///
347 /// ```
348 /// # use ta_statistics::{Statistics, SingleStatistics};
349 /// # use assert_approx_eq::assert_approx_eq;
350 /// let mut stats = Statistics::new(3);
351 /// let mut results = vec![];
352 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
353 /// inputs.iter().for_each(|i| {
354 /// stats.next(*i).variance().map(|v| results.push(v));
355 /// });
356 ///
357 /// let expected: [f64; 7] = [0.1156, 0.0067, 0.0156, 0.0156, 0.0422, 0.0289, 0.0156];
358 /// for (i, e) in expected.iter().enumerate() {
359 /// assert_approx_eq!(e, results[i], 0.1);
360 /// }
361 ///
362 /// stats.reset().set_ddof(true);
363 /// results = vec![];
364 /// inputs.iter().for_each(|i| {
365 /// stats.next(*i).variance().map(|v| results.push(v));
366 /// });
367 ///
368 /// let expected: [f64; 7] = [0.1733, 0.0100, 0.0233, 0.0233, 0.0633, 0.0433, 0.0233];
369 /// for (i, e) in expected.iter().enumerate() {
370 /// assert_approx_eq!(e, results[i], 0.1);
371 /// }
372 /// ```
373 fn variance(&self) -> Option<T>;
374 /// Returns the standard deviation of values in the rolling window
375 ///
376 /// As the square root of variance, this statistic provides an intuitive measure
377 /// of data dispersion in the original units and enables:
378 ///
379 /// - Setting dynamic volatility thresholds for risk boundaries
380 /// - Detecting potential mean-reversion opportunities when values deviate significantly
381 /// - Normalizing position sizing across different volatility environments
382 /// - Identifying market regime changes to adapt strategic approaches
383 ///
384 /// # Returns
385 ///
386 /// * `Option<T>` - The standard deviation of values in the window, or `None` if the window is not full
387 ///
388 /// # Examples
389 ///
390 /// ```
391 /// # use ta_statistics::{Statistics, SingleStatistics};
392 /// # use assert_approx_eq::assert_approx_eq;
393 /// let mut stats = Statistics::new(3);
394 /// let mut results = vec![];
395 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
396 /// inputs.iter().for_each(|i| {
397 /// stats.next(*i).stddev().map(|v| results.push(v));
398 /// });
399 ///
400 /// let expected: [f64; 7] = [0.3400, 0.0816, 0.1249, 0.1249, 0.2054, 0.1700, 0.1249];
401 /// for (i, e) in expected.iter().enumerate() {
402 /// assert_approx_eq!(e, results[i], 0.1);
403 /// }
404 ///
405 /// stats.reset().set_ddof(true);
406 /// results = vec![];
407 /// inputs.iter().for_each(|i| {
408 /// stats.next(*i).stddev().map(|v| results.push(v));
409 /// });
410 ///
411 /// let expected: [f64; 7] = [0.4162, 0.1000, 0.1527, 0.1527, 0.2516, 0.2081, 0.1527];
412 /// for (i, e) in expected.iter().enumerate() {
413 /// assert_approx_eq!(e, results[i], 0.1);
414 /// }
415 /// ```
416 fn stddev(&self) -> Option<T>;
417 /// Returns the z-score of the most recent value relative to the rolling window
418 ///
419 /// Z-scores express how many standard deviations a value deviates from the mean,
420 /// providing a normalized measure that facilitates:
421 ///
422 /// - Statistical arbitrage through relative valuation in correlated series
423 /// - Robust outlier detection across varying market conditions
424 /// - Cross-instrument comparisons on a standardized scale
425 /// - Setting consistent thresholds that remain valid across changing volatility regimes
426 ///
427 /// # Returns
428 ///
429 /// * `Option<T>` - The z-score of the most recent value, or `None` if the window is not full
430 ///
431 /// # Examples
432 ///
433 /// ```
434 /// # use ta_statistics::{Statistics, SingleStatistics};
435 /// # use assert_approx_eq::assert_approx_eq;
436 /// let mut stats = Statistics::new(3);
437 /// let mut results = vec![];
438 /// let inputs = [1.2, -0.7, 3.4, 2.1, -1.5, 0.0, 2.2, -0.3, 1.5, -2.0];
439 /// inputs.iter().for_each(|i| {
440 /// stats.next(*i).zscore().map(|v| results.push(v));
441 /// });
442 ///
443 /// let expected: [f64; 8] = [1.253, 0.292, -1.366, -0.136, 1.294, -0.835, 0.349, -1.210];
444 /// for (i, e) in expected.iter().enumerate() {
445 /// assert_approx_eq!(e, results[i], 0.1);
446 /// }
447 ///
448 /// stats.reset().set_ddof(true);
449 /// results = vec![];
450 /// inputs.iter().for_each(|i| {
451 /// stats.next(*i).zscore().map(|v| results.push(v));
452 /// });
453 ///
454 /// let expected: [f64; 8] = [1.024, 0.239, -1.116, -0.103, 1.000, -0.686, 0.285, -0.990];
455 /// for (i, e) in expected.iter().enumerate() {
456 /// assert_approx_eq!(e, results[i], 0.1);
457 /// }
458 /// ```
459 fn zscore(&self) -> Option<T>;
460 /// Returns the skewness of values in the rolling window
461 ///
462 /// This third-moment statistic measures distribution asymmetry, revealing whether
463 /// extreme values tend toward one direction. A comprehensive analysis of skewness:
464 ///
465 /// - Detects asymmetric return distributions critical for accurate risk modeling
466 /// - Reveals directional biases in market microstructure that may predict future movements
467 /// - Provides early signals of potential regime transitions in volatile environments
468 /// - Enables refined models for derivative pricing beyond simple volatility assumptions
469 ///
470 /// # Returns
471 ///
472 /// * `Option<T>` - The skewness of values in the window, or `None` if the window is not full
473 ///
474 /// # Examples
475 ///
476 /// ```
477 /// # use ta_statistics::{Statistics, SingleStatistics};
478 /// # use assert_approx_eq::assert_approx_eq;
479 /// let mut stats = Statistics::new(4);
480 /// let mut results = vec![];
481 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
482 /// inputs.iter().for_each(|i| {
483 /// stats.next(*i).skew().map(|v| results.push(v));
484 /// });
485 ///
486 /// let expected: [f64; 6] = [-0.979, -0.435, -0.0, 0.278, -0.0, -0.323];
487 /// for (i, e) in expected.iter().enumerate() {
488 /// assert_approx_eq!(e, results[i], 0.1);
489 /// }
490 ///
491 /// stats.reset().set_ddof(true);
492 /// results = vec![];
493 /// inputs.iter().for_each(|i| {
494 /// stats.next(*i).skew().map(|v| results.push(v));
495 /// });
496 ///
497 /// let expected: [f64; 6] = [-1.696, -0.753, 0.000, 0.482, 0.000, -0.560];
498 /// for (i, e) in expected.iter().enumerate() {
499 /// assert_approx_eq!(e, results[i], 0.1);
500 /// }
501 /// ```
502 fn skew(&self) -> Option<T>;
503 /// Returns the kurtosis of values in the rolling window
504 ///
505 /// This fourth-moment statistic measures the 'tailedness' of a distribution, describing
506 /// the frequency of extreme values compared to a normal distribution:
507 ///
508 /// - Quantifies fat-tail risk exposure essential for anticipating extreme market movements
509 /// - Signals potentially exploitable market inefficiencies through distribution analysis
510 /// - Provides critical parameters for selecting appropriate derivatives strategies
511 /// - Enhances Value-at-Risk models by incorporating more realistic tail behavior
512 ///
513 /// # Returns
514 ///
515 /// * `Option<T>` - The kurtosis of values in the window, or `None` if the window is not full
516 ///
517 /// # Examples
518 ///
519 /// ```
520 /// # use ta_statistics::{Statistics, SingleStatistics};
521 /// # use assert_approx_eq::assert_approx_eq;
522 /// let mut stats = Statistics::new(4);
523 /// let mut results = vec![];
524 /// let inputs = [25.4, 26.2, 26.0, 26.1, 25.8, 25.9, 26.3, 26.2, 26.5];
525 /// inputs.iter().for_each(|i| {
526 /// stats.next(*i).kurt().map(|v| results.push(v));
527 /// });
528 ///
529 /// let expected: [f64; 6] = [-0.7981, -1.1543, -1.3600, -1.4266, -1.7785, -1.0763];
530 /// for (i, e) in expected.iter().enumerate() {
531 /// assert_approx_eq!(e, results[i], 0.1);
532 /// }
533 ///
534 /// stats.reset().set_ddof(true);
535 /// results = vec![];
536 /// inputs.iter().for_each(|i| {
537 /// stats.next(*i).kurt().map(|v| results.push(v));
538 /// });
539 ///
540 /// let expected: [f64; 6] = [3.014, 0.343, -1.200, -1.700, -4.339, 0.928];
541 /// for (i, e) in expected.iter().enumerate() {
542 /// assert_approx_eq!(e, results[i], 0.1);
543 /// }
544 /// ```
545 fn kurt(&self) -> Option<T>;
546 /// Returns the slope of the linear regression line
547 ///
548 /// The regression slope represents the rate of change in the best-fit linear model,
549 /// quantifying the directional movement and its magnitude within the data:
550 ///
551 /// - Provides precise measurement of trend strength and conviction
552 /// - Quantifies velocity of change for optimal timing decisions
553 /// - Signals potential reversion points when diverging from historical patterns
554 /// - Measures the relative imbalance between supply and demand forces
555 ///
556 /// # Returns
557 ///
558 /// * `Option<T>` - The slope of the linear regression line, or `None` if the window is not full
559 ///
560 /// # Examples
561 ///
562 /// ```
563 /// # use ta_statistics::{Statistics, SingleStatistics};
564 /// # use assert_approx_eq::assert_approx_eq;
565 /// let mut stats = Statistics::new(5);
566 /// let mut results = vec![];
567 /// let inputs = [10.0, 10.5, 11.2, 10.9, 11.5, 11.9, 12.3, 12.1, 11.8, 12.5];
568 /// inputs.iter().for_each(|i| {
569 /// stats.next(*i).linreg_slope().map(|v| results.push(v));
570 /// });
571 ///
572 /// let expected: [f64; 6] = [0.34, 0.31, 0.32, 0.32, 0.08, 0.07];
573 /// for (i, e) in expected.iter().enumerate() {
574 /// assert_approx_eq!(e, results[i], 0.1);
575 /// }
576 /// ```
577 fn linreg_slope(&self) -> Option<T>;
578 /// Returns both slope and intercept of the linear regression line
579 ///
580 /// This comprehensive regression analysis provides the complete linear model,
581 /// enabling more sophisticated trend-based calculations:
582 ///
583 /// - Constructs complete linear models of price or indicator evolution
584 /// - Determines both direction and reference level in a single calculation
585 /// - Enables advanced divergence analysis against actual values
586 /// - Provides foundation for channel-based analytical frameworks
587 ///
588 /// # Returns
589 ///
590 /// * `Option<(T, T)>` - A tuple containing (slope, intercept), or `None` if the window is not full
591 ///
592 /// # Examples
593 ///
594 /// ```
595 /// # use ta_statistics::{Statistics, SingleStatistics};
596 /// # use assert_approx_eq::assert_approx_eq;
597 /// let mut stats = Statistics::new(5);
598 /// let mut ddof = false;
599 /// let mut results = vec![];
600 /// let inputs = [10.0, 10.5, 11.2, 10.9, 11.5, 11.9, 12.3, 12.1, 11.8, 12.5];
601 /// inputs.iter().for_each(|i| {
602 /// stats.next(*i).linreg_slope_intercept().map(|v| results.push(v));
603 /// });
604 ///
605 /// let expected: [(f64, f64); 6] = [
606 /// (0.34, 10.14),
607 /// (0.31, 10.58),
608 /// (0.32, 10.92),
609 /// (0.32, 11.1),
610 /// (0.08, 11.76),
611 /// (0.07, 11.98),
612 /// ];
613 /// for (i, e) in expected.iter().enumerate() {
614 /// assert_approx_eq!(e.0, results[i].0, 0.1);
615 /// assert_approx_eq!(e.1, results[i].1, 0.1);
616 /// }
617 /// ```
618 fn linreg_slope_intercept(&self) -> Option<(T, T)>;
619 /// Returns the y-intercept of the linear regression line
620 ///
621 /// The regression intercept represents the base level or starting point of the
622 /// best-fit linear model, providing key reference information:
623 ///
624 /// - Establishes the theoretical zero-point reference level
625 /// - Complements slope calculations to complete linear projections
626 /// - Assists in fair value determination for mean-reversion models
627 /// - Provides a fixed component for decomposing price into trend and oscillation
628 ///
629 /// # Returns
630 ///
631 /// * `Option<T>` - The y-intercept of the regression line, or `None` if the window is not full
632 ///
633 /// # Examples
634 ///
635 /// ```
636 /// # use ta_statistics::{Statistics, SingleStatistics};
637 /// # use assert_approx_eq::assert_approx_eq;
638 /// let mut stats = Statistics::new(5);
639 /// let mut results = vec![];
640 /// let inputs = [10.0, 10.5, 11.2, 10.9, 11.5, 11.9, 12.3, 12.1, 11.8, 12.5];
641 /// inputs.iter().for_each(|i| {
642 /// stats.next(*i).linreg_intercept().map(|v| results.push(v));
643 /// });
644 ///
645 /// let expected: [f64; 6] = [10.14, 10.58, 10.92, 11.1, 11.76, 11.98];
646 /// for (i, e) in expected.iter().enumerate() {
647 /// assert_approx_eq!(e, results[i], 0.1);
648 /// }
649 ///
650 /// ```
651 fn linreg_intercept(&self) -> Option<T>;
652 /// Returns the angle (in degrees) of the linear regression line
653 ///
654 /// The regression angle converts the slope into degrees, providing a more intuitive
655 /// measure of trend inclination that's bounded between -90 and 90 degrees:
656 ///
657 /// - Offers an easily interpretable measure of trend strength
658 /// - Provides normalized measurement across different scaling contexts
659 /// - Enables clear categorization of trend intensity
660 /// - Simplifies visual representation of directional movement
661 ///
662 /// # Returns
663 ///
664 /// * `Option<T>` - The angle of the regression line in degrees, or `None` if the window is not full
665 ///
666 /// # Examples
667 ///
668 /// ```
669 /// # use ta_statistics::{Statistics, SingleStatistics};
670 /// # use assert_approx_eq::assert_approx_eq;
671 /// let mut stats = Statistics::new(5);
672 /// let mut ddof = false;
673 /// let mut results = vec![];
674 /// let inputs = [10.0, 10.5, 11.2, 10.9, 11.5, 11.9, 12.3, 12.1, 11.8, 12.5];
675 /// inputs.iter().for_each(|i| {
676 /// stats.next(*i).linreg_angle().map(|v| results.push(v));
677 /// });
678 ///
679 /// let expected: [f64; 6] = [0.3396, 0.3100, 0.3199, 0.3199, 0.0799, 0.0699];
680 /// for (i, e) in expected.iter().enumerate() {
681 /// assert_approx_eq!(e, results[i], 0.1);
682 /// }
683 ///
684 /// ```
685 fn linreg_angle(&self) -> Option<T>;
686 /// Returns the linear regression value (predicted y) for the last position
687 ///
688 /// This calculation provides the expected value at the current position according to
689 /// the best-fit linear model across the window period:
690 ///
691 /// - Establishes theoretical fair value targets for mean-reversion analysis
692 /// - Projects trend trajectory for momentum-based methodologies
693 /// - Filters cyclical noise to extract underlying directional bias
694 /// - Provides basis for divergence analysis between actual and expected values
695 ///
696 /// # Returns
697 ///
698 /// * `Option<T>` - The predicted value at the current position, or `None` if the window is not full
699 ///
700 /// # Examples
701 ///
702 /// ```
703 /// # use ta_statistics::{Statistics, SingleStatistics};
704 /// # use assert_approx_eq::assert_approx_eq;
705 /// let mut stats = Statistics::new(5);
706 /// let mut ddof = false;
707 /// let mut results = vec![];
708 /// let inputs = [10.0, 10.5, 11.2, 10.9, 11.5, 11.9, 12.3, 12.1, 11.8, 12.5];
709 /// inputs.iter().for_each(|i| {
710 /// stats.next(*i).linreg().map(|v| results.push(v));
711 /// });
712 ///
713 /// let expected: [f64; 6] = [11.5, 11.82, 12.2, 12.38, 12.08, 12.26];
714 /// for (i, e) in expected.iter().enumerate() {
715 /// assert_approx_eq!(e, results[i], 0.1);
716 /// }
717 ///
718 /// ```
719 fn linreg(&self) -> Option<T>;
720 /// Returns the current drawdown from peak
721 ///
722 /// Measures the percentage decline from the highest observed value to the current value,
723 /// providing crucial insights for risk management and performance evaluation:
724 ///
725 /// - Enables dynamic adjustment of risk exposure during challenging conditions
726 /// - Facilitates strategy rotation based on relative performance metrics
727 /// - Forms the foundation of capital preservation systems during market stress
728 /// - Identifies potential opportunities for strategic positioning during dislocations
729 ///
730 /// # Returns
731 ///
732 /// * `Option<T>` - The current drawdown from peak, or `None` if the window is not full
733 ///
734 /// # Examples
735 ///
736 /// ```
737 /// # use ta_statistics::{Statistics, SingleStatistics};
738 /// # use assert_approx_eq::assert_approx_eq;
739 /// let mut stats = Statistics::new(3);
740 /// let mut results = vec![];
741 /// let inputs = [100.0, 110.0, 105.0, 115.0, 100.0, 95.0, 105.0, 110.0, 100.0];
742 /// inputs.iter().for_each(|i| {
743 /// stats.next(*i).drawdown().map(|v| results.push(v));
744 /// });
745 ///
746 /// let expected: [f64; 7] = [0.045, 0.0, 0.13, 0.174, 0.0, 0.0, 0.091];
747 /// for (i, e) in expected.iter().enumerate() {
748 /// assert_approx_eq!(e, results[i], 0.1);
749 /// }
750 /// ```
751 fn drawdown(&mut self) -> Option<T>;
752 /// Returns the maximum drawdown in the window
753 ///
754 /// Maximum drawdown measures the largest peak-to-trough decline within a time series,
755 /// serving as a foundational metric for risk assessment and strategy evaluation:
756 ///
757 /// - Establishes critical constraints for comprehensive risk management frameworks
758 /// - Provides an objective metric for evaluating strategy viability under stress
759 /// - Informs position sizing parameters to maintain proportional risk exposure
760 /// - Contributes valuable input to market regime classification models
761 ///
762 /// # Returns
763 ///
764 /// * `Option<T>` - The maximum drawdown in the window, or `None` if the window is not full
765 ///
766 /// # Examples
767 ///
768 /// ```
769 /// # use ta_statistics::{Statistics, SingleStatistics};
770 /// # use assert_approx_eq::assert_approx_eq;
771 /// let mut stats = Statistics::new(3);
772 /// let mut results = vec![];
773 /// let inputs = [100.0, 110.0, 105.0, 115.0, 100.0, 95.0, 105.0, 110.0, 100.0];
774 /// inputs.iter().for_each(|i| {
775 /// stats.next(*i).max_drawdown().map(|v| results.push(v));
776 /// });
777 ///
778 /// let expected: [f64; 7] = [0.045, 0.045, 0.13, 0.174, 0.174, 0.174, 0.174];
779 /// for (i, e) in expected.iter().enumerate() {
780 /// assert_approx_eq!(e, results[i], 0.1);
781 /// }
782 ///
783 /// ```
784 fn max_drawdown(&mut self) -> Option<T>;
785 /// Returns the difference between the last and first values
786 ///
787 /// This fundamental calculation of absolute change between two points provides
788 /// essential directional and magnitude information for time series analysis:
789 ///
790 /// - Enables momentum measurement for trend strength evaluation
791 /// - Quantifies rate-of-change to optimize timing decisions
792 /// - Serves as a building block for pattern recognition in sequential data
793 /// - Provides critical inputs for calculating hedge ratios and exposure management
794 ///
795 /// # Returns
796 ///
797 /// * `Option<T>` - The difference between values, or `None` if the window is not full
798 ///
799 /// # Examples
800 ///
801 /// ```
802 /// # use ta_statistics::{Statistics, SingleStatistics};
803 /// # use assert_approx_eq::assert_approx_eq;
804 /// let mut stats = Statistics::new(3);
805 /// let mut results = vec![];
806 /// let inputs = [100.0, 102.0, 105.0, 101.0, 98.0];
807 /// inputs.iter().for_each(|i| {
808 /// stats.next(*i).diff().map(|v| results.push(v));
809 /// });
810 ///
811 /// let expected: [f64; 2] = [1.0, -4.0];
812 /// for (i, e) in expected.iter().enumerate() {
813 /// assert_approx_eq!(e, results[i], 0.1);
814 /// }
815 ///
816 /// ```
817 fn diff(&self) -> Option<T>;
818 /// Returns the percentage change between the first and last values
819 ///
820 /// Percentage change normalizes absolute changes by the starting value, enabling
821 /// meaningful comparisons across different scales and measurement contexts:
822 ///
823 /// - Facilitates cross-asset performance comparison for relative strength analysis
824 /// - Provides risk-normalized return metrics that account for initial exposure
825 /// - Enables position sizing that properly adjusts for varying volatility environments
826 /// - Serves as a key input for comparative performance evaluation across related groups
827 ///
828 /// # Returns
829 ///
830 /// * `Option<T>` - The percentage change, or `None` if the window is not full
831 ///
832 /// # Examples
833 ///
834 /// ```
835 /// # use ta_statistics::{Statistics, SingleStatistics};
836 /// # use assert_approx_eq::assert_approx_eq;
837 /// let mut stats = Statistics::new(3);
838 /// let mut results = vec![];
839 /// let inputs = [100.0, 105.0, 103.0, 106.0, 110.0, 108.0];
840 /// inputs.iter().for_each(|i| {
841 /// stats.next(*i).pct_change().map(|v| results.push(v));
842 /// });
843 ///
844 /// let expected: [f64; 3] = [0.06, 0.04761905, 0.04854369];
845 /// for (i, e) in expected.iter().enumerate() {
846 /// assert_approx_eq!(e, results[i], 0.1);
847 /// }
848 ///
849 /// ```
850 fn pct_change(&self) -> Option<T>;
851 /// Returns the logarithmic return between the first and last values
852 ///
853 /// Logarithmic returns (continuous returns) offer mathematical advantages over simple
854 /// returns, particularly for time series analysis:
855 ///
856 /// - Provides time-additive metrics that can be properly aggregated across periods
857 /// - Normalizes signals in relative-value analysis of related securities
858 /// - Creates a more consistent volatility scale regardless of price levels
859 /// - Improves accuracy in long-horizon analyses through proper handling of compounding
860 ///
861 /// # Returns
862 ///
863 /// * `Option<T>` - The logarithmic return, or `None` if the window is not full
864 ///
865 /// # Examples
866 ///
867 /// ```
868 /// # use ta_statistics::{Statistics, SingleStatistics};
869 /// # use assert_approx_eq::assert_approx_eq;
870 /// let mut stats = Statistics::new(3);
871 /// let mut results = vec![];
872 /// let inputs = [100.0, 105.0, 103.0, 106.0, 110.0, 108.0];
873 /// inputs.iter().for_each(|i| {
874 /// stats.next(*i).pct_change().map(|v| results.push(v));
875 /// });
876 ///
877 /// let expected: [f64; 3] = [0.05827, 0.04652, 0.04727];
878 /// for (i, e) in expected.iter().enumerate() {
879 /// assert_approx_eq!(e, results[i], 0.1);
880 /// }
881 ///
882 /// ```
883 fn log_return(&self) -> Option<T>;
884
885 /// Returns the quantile of the values in the window
886 ///
887 /// # Arguments
888 ///
889 /// * `q` - The quantile to calculate
890 ///
891 /// # Returns
892 ///
893 /// * `Option<T>` - The quantile, or `None` if the window is not full
894 ///
895 /// # Examples
896 ///
897 /// ```
898 /// # use ta_statistics::{Statistics, SingleStatistics};
899 /// # use assert_approx_eq::assert_approx_eq;
900 /// let mut stats = Statistics::new(3);
901 /// let mut results = vec![];
902 /// let inputs = [10.0, 20.0, 30.0, 40.0, 50.0];
903 /// inputs.iter().for_each(|i| {
904 /// stats.next(*i).quantile(0.5).map(|v| results.push(v));
905 /// });
906 ///
907 /// let expected: [f64; 3] = [20.0, 30.0, 40.0];
908 /// for (i, e) in expected.iter().enumerate() {
909 /// assert_approx_eq!(e, results[i], 0.1);
910 /// }
911 /// ```
912 fn quantile(&mut self, q: f64) -> Option<T>;
913
914 /// Returns the interquartile range of the values in the window
915 ///
916 /// # Returns
917 ///
918 /// * `Option<T>` - The interquartile range, or `None` if the window is not full
919 ///
920 /// # Examples
921 ///
922 /// ```
923 /// # use ta_statistics::{Statistics, SingleStatistics};
924 /// # use assert_approx_eq::assert_approx_eq;
925 /// let mut stats = Statistics::new(3);
926 /// let mut results = vec![];
927 /// let inputs = [10.0, 20.0, 30.0, 40.0, 50.0];
928 /// inputs.iter().for_each(|i| {
929 /// stats.next(*i).iqr().map(|v| results.push(v));
930 /// });
931 ///
932 /// let expected: [f64; 3] = [10.0, 10.0, 10.0];
933 /// for (i, e) in expected.iter().enumerate() {
934 /// assert_approx_eq!(e, results[i], 0.1);
935 /// }
936 ///
937 /// ```
938 fn iqr(&mut self) -> Option<T>;
939}