@ebowwa/quant-rust 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -0
- package/bun-ffi.d.ts +54 -0
- package/dist/index.js +576 -0
- package/dist/src/index.d.ts +324 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +403 -0
- package/dist/types/index.d.ts.map +1 -0
- package/native/README.md +62 -0
- package/native/darwin-arm64/libquant_rust.dylib +0 -0
- package/package.json +70 -0
- package/scripts/postinstall.cjs +85 -0
- package/src/ffi.rs +496 -0
- package/src/index.ts +1073 -0
- package/src/indicators/ma.rs +222 -0
- package/src/indicators/mod.rs +18 -0
- package/src/indicators/momentum.rs +353 -0
- package/src/indicators/sr.rs +195 -0
- package/src/indicators/trend.rs +351 -0
- package/src/indicators/volatility.rs +270 -0
- package/src/indicators/volume.rs +213 -0
- package/src/lib.rs +130 -0
- package/src/patterns/breakout.rs +431 -0
- package/src/patterns/chart.rs +772 -0
- package/src/patterns/mod.rs +394 -0
- package/src/patterns/sr.rs +423 -0
- package/src/prediction/amm.rs +338 -0
- package/src/prediction/arbitrage.rs +230 -0
- package/src/prediction/calibration.rs +317 -0
- package/src/prediction/kelly.rs +232 -0
- package/src/prediction/lmsr.rs +194 -0
- package/src/prediction/mod.rs +59 -0
- package/src/prediction/odds.rs +229 -0
- package/src/prediction/pnl.rs +254 -0
- package/src/prediction/risk.rs +228 -0
- package/src/risk/beta.rs +257 -0
- package/src/risk/drawdown.rs +256 -0
- package/src/risk/leverage.rs +201 -0
- package/src/risk/mod.rs +388 -0
- package/src/risk/portfolio.rs +287 -0
- package/src/risk/ratios.rs +290 -0
- package/src/risk/sizing.rs +194 -0
- package/src/risk/var.rs +222 -0
- package/src/stats/cdf.rs +257 -0
- package/src/stats/correlation.rs +225 -0
- package/src/stats/distribution.rs +194 -0
- package/src/stats/hypothesis.rs +177 -0
- package/src/stats/matrix.rs +346 -0
- package/src/stats/mod.rs +257 -0
- package/src/stats/regression.rs +239 -0
- package/src/stats/rolling.rs +193 -0
- package/src/stats/timeseries.rs +263 -0
- package/src/types.rs +224 -0
- package/src/utils/mod.rs +215 -0
- package/src/utils/normalize.rs +192 -0
- package/src/utils/price.rs +167 -0
- package/src/utils/quantiles.rs +177 -0
- package/src/utils/returns.rs +158 -0
- package/src/utils/rolling.rs +97 -0
- package/src/utils/stats.rs +154 -0
- package/types/index.ts +513 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//! Rolling Window Operations Module
|
|
2
|
+
//!
|
|
3
|
+
//! Sliding window calculations for time series analysis
|
|
4
|
+
|
|
5
|
+
use super::stats::{mean, std_dev, max, min};
|
|
6
|
+
|
|
7
|
+
/// Apply a function over a sliding window
|
|
8
|
+
///
|
|
9
|
+
/// Returns an empty vector if the array is shorter than the window size.
|
|
10
|
+
pub fn rolling<T, F>(arr: &[f64], window: usize, f: F) -> Vec<T>
|
|
11
|
+
where
|
|
12
|
+
F: Fn(&[f64]) -> T,
|
|
13
|
+
{
|
|
14
|
+
if arr.len() < window || window == 0 {
|
|
15
|
+
return Vec::new();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let result_len = arr.len() - window + 1;
|
|
19
|
+
let mut result = Vec::with_capacity(result_len);
|
|
20
|
+
|
|
21
|
+
for i in 0..result_len {
|
|
22
|
+
let slice = &arr[i..i + window];
|
|
23
|
+
result.push(f(slice));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
result
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// Rolling mean (Simple Moving Average)
|
|
30
|
+
pub fn rolling_mean(arr: &[f64], period: usize) -> Vec<f64> {
|
|
31
|
+
rolling(arr, period, mean)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Rolling standard deviation (sample)
|
|
35
|
+
pub fn rolling_std_dev(arr: &[f64], period: usize) -> Vec<f64> {
|
|
36
|
+
rolling(arr, period, |slice| std_dev(slice, false))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Rolling minimum
|
|
40
|
+
pub fn rolling_min(arr: &[f64], period: usize) -> Vec<f64> {
|
|
41
|
+
rolling(arr, period, min)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Rolling maximum
|
|
45
|
+
pub fn rolling_max(arr: &[f64], period: usize) -> Vec<f64> {
|
|
46
|
+
rolling(arr, period, max)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Rolling sum
|
|
50
|
+
pub fn rolling_sum(arr: &[f64], period: usize) -> Vec<f64> {
|
|
51
|
+
rolling(arr, period, |slice| slice.iter().sum())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Rolling variance (sample)
|
|
55
|
+
pub fn rolling_variance(arr: &[f64], period: usize) -> Vec<f64> {
|
|
56
|
+
use super::stats::variance;
|
|
57
|
+
rolling(arr, period, |slice| variance(slice, false))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#[cfg(test)]
|
|
61
|
+
mod tests {
|
|
62
|
+
use super::*;
|
|
63
|
+
|
|
64
|
+
#[test]
|
|
65
|
+
fn test_rolling() {
|
|
66
|
+
let data = [1.0, 2.0, 3.0, 4.0, 5.0];
|
|
67
|
+
let result: Vec<f64> = rolling(&data, 3, |s| s.iter().sum());
|
|
68
|
+
assert_eq!(result, vec![6.0, 9.0, 12.0]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
#[test]
|
|
72
|
+
fn test_rolling_mean() {
|
|
73
|
+
let data = [1.0, 2.0, 3.0, 4.0, 5.0];
|
|
74
|
+
let result = rolling_mean(&data, 3);
|
|
75
|
+
assert_eq!(result.len(), 3);
|
|
76
|
+
assert!((result[0] - 2.0).abs() < 1e-10);
|
|
77
|
+
assert!((result[1] - 3.0).abs() < 1e-10);
|
|
78
|
+
assert!((result[2] - 4.0).abs() < 1e-10);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[test]
|
|
82
|
+
fn test_rolling_empty() {
|
|
83
|
+
let data = [1.0, 2.0];
|
|
84
|
+
let result = rolling_mean(&data, 5);
|
|
85
|
+
assert!(result.is_empty());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#[test]
|
|
89
|
+
fn test_rolling_min_max() {
|
|
90
|
+
let data = [5.0, 3.0, 8.0, 2.0, 9.0, 1.0];
|
|
91
|
+
let min_result = rolling_min(&data, 3);
|
|
92
|
+
let max_result = rolling_max(&data, 3);
|
|
93
|
+
|
|
94
|
+
assert_eq!(min_result, vec![3.0, 2.0, 2.0, 1.0]);
|
|
95
|
+
assert_eq!(max_result, vec![8.0, 8.0, 9.0, 9.0]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
//! Array Statistics Module
|
|
2
|
+
//!
|
|
3
|
+
//! Common statistical functions for quantitative analysis
|
|
4
|
+
|
|
5
|
+
/// Calculate the sum of an array
|
|
6
|
+
pub fn sum(arr: &[f64]) -> f64 {
|
|
7
|
+
arr.iter().sum()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/// Calculate the mean (average) of an array
|
|
11
|
+
pub fn mean(arr: &[f64]) -> f64 {
|
|
12
|
+
if arr.is_empty() {
|
|
13
|
+
return 0.0;
|
|
14
|
+
}
|
|
15
|
+
sum(arr) / arr.len() as f64
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Calculate the median of an array
|
|
19
|
+
pub fn median(arr: &[f64]) -> f64 {
|
|
20
|
+
if arr.is_empty() {
|
|
21
|
+
return 0.0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let mut sorted: Vec<f64> = arr.to_vec();
|
|
25
|
+
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
|
26
|
+
|
|
27
|
+
let mid = sorted.len() / 2;
|
|
28
|
+
if sorted.len() % 2 != 0 {
|
|
29
|
+
sorted[mid]
|
|
30
|
+
} else {
|
|
31
|
+
(sorted[mid - 1] + sorted[mid]) / 2.0
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Calculate the mode of an array
|
|
36
|
+
pub fn mode(arr: &[f64]) -> f64 {
|
|
37
|
+
if arr.is_empty() {
|
|
38
|
+
return 0.0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
use std::collections::HashMap;
|
|
42
|
+
let mut frequency: HashMap<u64, usize> = HashMap::new();
|
|
43
|
+
|
|
44
|
+
// Use bit representation for hashing floats
|
|
45
|
+
for &val in arr {
|
|
46
|
+
let key = val.to_bits();
|
|
47
|
+
*frequency.entry(key).or_insert(0) += 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let mut max_freq = 0;
|
|
51
|
+
let mut mode_val = arr[0];
|
|
52
|
+
|
|
53
|
+
for (&key, &freq) in &frequency {
|
|
54
|
+
if freq > max_freq {
|
|
55
|
+
max_freq = freq;
|
|
56
|
+
mode_val = f64::from_bits(key);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
mode_val
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Calculate variance
|
|
64
|
+
/// population: true for population variance, false for sample variance
|
|
65
|
+
pub fn variance(arr: &[f64], population: bool) -> f64 {
|
|
66
|
+
if arr.is_empty() {
|
|
67
|
+
return 0.0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let avg = mean(arr);
|
|
71
|
+
let sum_sq_diff: f64 = arr.iter().map(|&val| (val - avg).powi(2)).sum();
|
|
72
|
+
|
|
73
|
+
let divisor = if population {
|
|
74
|
+
arr.len() as f64
|
|
75
|
+
} else {
|
|
76
|
+
(arr.len() - 1) as f64
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
sum_sq_diff / divisor
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// Calculate standard deviation
|
|
83
|
+
/// population: true for population std dev, false for sample std dev
|
|
84
|
+
pub fn std_dev(arr: &[f64], population: bool) -> f64 {
|
|
85
|
+
variance(arr, population).sqrt()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Calculate the minimum value
|
|
89
|
+
pub fn min(arr: &[f64]) -> f64 {
|
|
90
|
+
if arr.is_empty() {
|
|
91
|
+
return 0.0;
|
|
92
|
+
}
|
|
93
|
+
arr.iter().cloned().fold(f64::INFINITY, f64::min)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// Calculate the maximum value
|
|
97
|
+
pub fn max(arr: &[f64]) -> f64 {
|
|
98
|
+
if arr.is_empty() {
|
|
99
|
+
return 0.0;
|
|
100
|
+
}
|
|
101
|
+
arr.iter().cloned().fold(f64::NEG_INFINITY, f64::max)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// Calculate the range (max - min)
|
|
105
|
+
pub fn range(arr: &[f64]) -> f64 {
|
|
106
|
+
max(arr) - min(arr)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#[cfg(test)]
|
|
110
|
+
mod tests {
|
|
111
|
+
use super::*;
|
|
112
|
+
|
|
113
|
+
#[test]
|
|
114
|
+
fn test_sum() {
|
|
115
|
+
assert_eq!(sum(&[1.0, 2.0, 3.0, 4.0, 5.0]), 15.0);
|
|
116
|
+
assert_eq!(sum(&[]), 0.0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#[test]
|
|
120
|
+
fn test_mean() {
|
|
121
|
+
assert_eq!(mean(&[1.0, 2.0, 3.0, 4.0, 5.0]), 3.0);
|
|
122
|
+
assert_eq!(mean(&[]), 0.0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#[test]
|
|
126
|
+
fn test_median() {
|
|
127
|
+
assert_eq!(median(&[1.0, 2.0, 3.0, 4.0, 5.0]), 3.0);
|
|
128
|
+
assert_eq!(median(&[1.0, 2.0, 3.0, 4.0]), 2.5);
|
|
129
|
+
assert_eq!(median(&[]), 0.0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
#[test]
|
|
133
|
+
fn test_variance() {
|
|
134
|
+
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
|
|
135
|
+
// Population variance
|
|
136
|
+
assert!((variance(&data, true) - 4.0).abs() < 1e-10);
|
|
137
|
+
// Sample variance
|
|
138
|
+
assert!((variance(&data, false) - 4.571428571).abs() < 1e-6);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
#[test]
|
|
142
|
+
fn test_std_dev() {
|
|
143
|
+
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
|
|
144
|
+
assert!((std_dev(&data, true) - 2.0).abs() < 1e-10);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[test]
|
|
148
|
+
fn test_min_max_range() {
|
|
149
|
+
let data = [1.0, 5.0, 3.0, 9.0, 2.0];
|
|
150
|
+
assert_eq!(min(&data), 1.0);
|
|
151
|
+
assert_eq!(max(&data), 9.0);
|
|
152
|
+
assert_eq!(range(&data), 8.0);
|
|
153
|
+
}
|
|
154
|
+
}
|