@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.
Files changed (60) hide show
  1. package/README.md +161 -0
  2. package/bun-ffi.d.ts +54 -0
  3. package/dist/index.js +576 -0
  4. package/dist/src/index.d.ts +324 -0
  5. package/dist/src/index.d.ts.map +1 -0
  6. package/dist/types/index.d.ts +403 -0
  7. package/dist/types/index.d.ts.map +1 -0
  8. package/native/README.md +62 -0
  9. package/native/darwin-arm64/libquant_rust.dylib +0 -0
  10. package/package.json +70 -0
  11. package/scripts/postinstall.cjs +85 -0
  12. package/src/ffi.rs +496 -0
  13. package/src/index.ts +1073 -0
  14. package/src/indicators/ma.rs +222 -0
  15. package/src/indicators/mod.rs +18 -0
  16. package/src/indicators/momentum.rs +353 -0
  17. package/src/indicators/sr.rs +195 -0
  18. package/src/indicators/trend.rs +351 -0
  19. package/src/indicators/volatility.rs +270 -0
  20. package/src/indicators/volume.rs +213 -0
  21. package/src/lib.rs +130 -0
  22. package/src/patterns/breakout.rs +431 -0
  23. package/src/patterns/chart.rs +772 -0
  24. package/src/patterns/mod.rs +394 -0
  25. package/src/patterns/sr.rs +423 -0
  26. package/src/prediction/amm.rs +338 -0
  27. package/src/prediction/arbitrage.rs +230 -0
  28. package/src/prediction/calibration.rs +317 -0
  29. package/src/prediction/kelly.rs +232 -0
  30. package/src/prediction/lmsr.rs +194 -0
  31. package/src/prediction/mod.rs +59 -0
  32. package/src/prediction/odds.rs +229 -0
  33. package/src/prediction/pnl.rs +254 -0
  34. package/src/prediction/risk.rs +228 -0
  35. package/src/risk/beta.rs +257 -0
  36. package/src/risk/drawdown.rs +256 -0
  37. package/src/risk/leverage.rs +201 -0
  38. package/src/risk/mod.rs +388 -0
  39. package/src/risk/portfolio.rs +287 -0
  40. package/src/risk/ratios.rs +290 -0
  41. package/src/risk/sizing.rs +194 -0
  42. package/src/risk/var.rs +222 -0
  43. package/src/stats/cdf.rs +257 -0
  44. package/src/stats/correlation.rs +225 -0
  45. package/src/stats/distribution.rs +194 -0
  46. package/src/stats/hypothesis.rs +177 -0
  47. package/src/stats/matrix.rs +346 -0
  48. package/src/stats/mod.rs +257 -0
  49. package/src/stats/regression.rs +239 -0
  50. package/src/stats/rolling.rs +193 -0
  51. package/src/stats/timeseries.rs +263 -0
  52. package/src/types.rs +224 -0
  53. package/src/utils/mod.rs +215 -0
  54. package/src/utils/normalize.rs +192 -0
  55. package/src/utils/price.rs +167 -0
  56. package/src/utils/quantiles.rs +177 -0
  57. package/src/utils/returns.rs +158 -0
  58. package/src/utils/rolling.rs +97 -0
  59. package/src/utils/stats.rs +154 -0
  60. package/types/index.ts +513 -0
@@ -0,0 +1,394 @@
1
+ //! Pattern Recognition Module
2
+ //!
3
+ //! Provides candlestick and chart pattern recognition, support/resistance detection,
4
+ //! trend line analysis, and breakout detection.
5
+ //!
6
+ //! ## Sub-modules
7
+ //! - `sr`: Support and resistance level detection, trend line finding
8
+ //! - `chart`: Chart pattern detection (double tops/bottoms, head and shoulders, triangles, etc.)
9
+ //! - `breakout`: Breakout detection from levels and consolidations
10
+ //!
11
+ //! ## Usage
12
+ //! ```ignore
13
+ //! use quant_rust::patterns::{
14
+ //! find_support_resistance, detect_all_patterns, detect_breakouts,
15
+ //! SupportResistanceLevel, PatternMatch, Breakout
16
+ //! };
17
+ //! ```
18
+
19
+ pub mod breakout;
20
+ pub mod chart;
21
+ pub mod sr;
22
+
23
+ // Re-export types from sub-modules
24
+ pub use breakout::{Breakout, BreakoutDirection};
25
+ pub use chart::{
26
+ detect_all_patterns, detect_channels, detect_double_bottom, detect_double_top,
27
+ detect_gaps, detect_head_and_shoulders, detect_inverse_head_and_shoulders, detect_triangles,
28
+ PatternDirection, PatternMatch, PatternType,
29
+ };
30
+ pub use sr::{find_support_resistance, find_trend_lines, LevelType, SupportResistanceLevel, TrendLine};
31
+
32
+ // Re-export candlestick pattern types for backward compatibility
33
+ use crate::types::{CandlePattern, OHLCV, PatternResult};
34
+ use serde::{Deserialize, Serialize};
35
+
36
+ // Re-export breakout functions
37
+ pub use breakout::{
38
+ detect_all_time_high_breakouts, detect_all_time_low_breakouts,
39
+ detect_breakouts_from_levels, detect_consolidation_breakouts, detect_breakouts,
40
+ };
41
+
42
+ /// Pattern recognition configuration
43
+ #[derive(Debug, Clone, Serialize, Deserialize)]
44
+ pub struct PatternConfig {
45
+ /// Doji threshold (body / range ratio)
46
+ pub doji_threshold: f64,
47
+ /// Minimum pattern confidence to report
48
+ pub min_confidence: f64,
49
+ }
50
+
51
+ impl Default for PatternConfig {
52
+ fn default() -> Self {
53
+ Self {
54
+ doji_threshold: 0.1,
55
+ min_confidence: 0.5,
56
+ }
57
+ }
58
+ }
59
+
60
+ /// Detect candlestick patterns in OHLCV data
61
+ ///
62
+ /// This is a convenience function for detecting candlestick patterns.
63
+ /// For chart patterns, use the functions from the `chart` module.
64
+ pub fn detect_patterns(data: &[OHLCV], config: &PatternConfig) -> Vec<PatternResult> {
65
+ if data.len() < 3 {
66
+ return vec![];
67
+ }
68
+
69
+ let mut results = Vec::new();
70
+
71
+ for i in 2..data.len() {
72
+ // Check single-candle patterns
73
+ if let Some(pattern) = detect_doji(&data[i], config) {
74
+ results.push(pattern);
75
+ }
76
+ if let Some(pattern) = detect_hammer(&data[i], config) {
77
+ results.push(pattern);
78
+ }
79
+
80
+ // Check two-candle patterns
81
+ if i >= 1 {
82
+ if let Some(pattern) = detect_engulfing(&data[i - 1], &data[i], config) {
83
+ results.push(pattern);
84
+ }
85
+ }
86
+
87
+ // Check three-candle patterns
88
+ if let Some(pattern) = detect_morning_star(&data[i - 2], &data[i - 1], &data[i], config) {
89
+ results.push(pattern);
90
+ }
91
+ if let Some(pattern) = detect_evening_star(&data[i - 2], &data[i - 1], &data[i], config) {
92
+ results.push(pattern);
93
+ }
94
+ if let Some(pattern) = detect_three_soldiers(&data[i - 2], &data[i - 1], &data[i], config)
95
+ {
96
+ results.push(pattern);
97
+ }
98
+ if let Some(pattern) = detect_three_crows(&data[i - 2], &data[i - 1], &data[i], config) {
99
+ results.push(pattern);
100
+ }
101
+ }
102
+
103
+ // Filter by confidence
104
+ results
105
+ .into_iter()
106
+ .filter(|r| r.confidence >= config.min_confidence)
107
+ .collect()
108
+ }
109
+
110
+ /// Detect Doji pattern
111
+ fn detect_doji(candle: &OHLCV, config: &PatternConfig) -> Option<PatternResult> {
112
+ let range = candle.range();
113
+ if range == 0.0 {
114
+ return None;
115
+ }
116
+
117
+ let body_ratio = candle.body_size() / range;
118
+
119
+ if body_ratio < config.doji_threshold {
120
+ Some(PatternResult {
121
+ pattern: CandlePattern::Doji,
122
+ confidence: 1.0 - body_ratio,
123
+ index: 0, // Will be set by caller
124
+ is_bullish: false, // Doji is neutral
125
+ })
126
+ } else {
127
+ None
128
+ }
129
+ }
130
+
131
+ /// Detect Hammer pattern
132
+ fn detect_hammer(candle: &OHLCV, _config: &PatternConfig) -> Option<PatternResult> {
133
+ let range = candle.range();
134
+ if range == 0.0 {
135
+ return None;
136
+ }
137
+
138
+ let body = candle.body_size();
139
+ let lower_wick = (candle.close.min(candle.open)) - candle.low;
140
+ let upper_wick = candle.high - (candle.close.max(candle.open));
141
+
142
+ // Hammer: long lower wick (2x body), small upper wick, small body
143
+ if lower_wick >= body * 2.0 && upper_wick < body * 0.5 {
144
+ Some(PatternResult {
145
+ pattern: CandlePattern::Hammer,
146
+ confidence: (lower_wick / body / 3.0).min(1.0),
147
+ index: 0,
148
+ is_bullish: true,
149
+ })
150
+ } else if upper_wick >= body * 2.0 && lower_wick < body * 0.5 {
151
+ Some(PatternResult {
152
+ pattern: CandlePattern::InvertedHammer,
153
+ confidence: (upper_wick / body / 3.0).min(1.0),
154
+ index: 0,
155
+ is_bullish: true,
156
+ })
157
+ } else {
158
+ None
159
+ }
160
+ }
161
+
162
+ /// Detect Engulfing pattern
163
+ fn detect_engulfing(prev: &OHLCV, curr: &OHLCV, _config: &PatternConfig) -> Option<PatternResult> {
164
+ let prev_body = prev.body_size();
165
+ let curr_body = curr.body_size();
166
+
167
+ // Bullish engulfing: prev bearish, curr bullish, curr engulfs prev
168
+ if prev.is_bearish() && curr.is_bullish() {
169
+ if curr_body > prev_body && curr.open < prev.close && curr.close > prev.open {
170
+ return Some(PatternResult {
171
+ pattern: CandlePattern::BullishEngulfing,
172
+ confidence: (curr_body / prev_body / 2.0).min(1.0),
173
+ index: 0,
174
+ is_bullish: true,
175
+ });
176
+ }
177
+ }
178
+
179
+ // Bearish engulfing: prev bullish, curr bearish, curr engulfs prev
180
+ if prev.is_bullish() && curr.is_bearish() {
181
+ if curr_body > prev_body && curr.open > prev.close && curr.close < prev.open {
182
+ return Some(PatternResult {
183
+ pattern: CandlePattern::BearishEngulfing,
184
+ confidence: (curr_body / prev_body / 2.0).min(1.0),
185
+ index: 0,
186
+ is_bullish: false,
187
+ });
188
+ }
189
+ }
190
+
191
+ None
192
+ }
193
+
194
+ /// Detect Morning Star pattern (bullish reversal)
195
+ fn detect_morning_star(
196
+ first: &OHLCV,
197
+ second: &OHLCV,
198
+ third: &OHLCV,
199
+ _config: &PatternConfig,
200
+ ) -> Option<PatternResult> {
201
+ // First: large bearish
202
+ // Second: small body (gap down preferred)
203
+ // Third: large bullish closing above midpoint of first
204
+
205
+ if !first.is_bearish() || !third.is_bullish() {
206
+ return None;
207
+ }
208
+
209
+ let first_body = first.body_size();
210
+ let second_body = second.body_size();
211
+ let third_body = third.body_size();
212
+
213
+ // Second should be small
214
+ if second_body > first_body * 0.3 {
215
+ return None;
216
+ }
217
+
218
+ // Third should close above midpoint of first
219
+ let first_mid = (first.open + first.close) / 2.0;
220
+ if third.close < first_mid {
221
+ return None;
222
+ }
223
+
224
+ // Third should be large
225
+ if third_body < first_body * 0.6 {
226
+ return None;
227
+ }
228
+
229
+ Some(PatternResult {
230
+ pattern: CandlePattern::MorningStar,
231
+ confidence: (third_body / first_body).min(1.0),
232
+ index: 0,
233
+ is_bullish: true,
234
+ })
235
+ }
236
+
237
+ /// Detect Evening Star pattern (bearish reversal)
238
+ fn detect_evening_star(
239
+ first: &OHLCV,
240
+ second: &OHLCV,
241
+ third: &OHLCV,
242
+ _config: &PatternConfig,
243
+ ) -> Option<PatternResult> {
244
+ // First: large bullish
245
+ // Second: small body (gap up preferred)
246
+ // Third: large bearish closing below midpoint of first
247
+
248
+ if !first.is_bullish() || !third.is_bearish() {
249
+ return None;
250
+ }
251
+
252
+ let first_body = first.body_size();
253
+ let second_body = second.body_size();
254
+ let third_body = third.body_size();
255
+
256
+ // Second should be small
257
+ if second_body > first_body * 0.3 {
258
+ return None;
259
+ }
260
+
261
+ // Third should close below midpoint of first
262
+ let first_mid = (first.open + first.close) / 2.0;
263
+ if third.close > first_mid {
264
+ return None;
265
+ }
266
+
267
+ // Third should be large
268
+ if third_body < first_body * 0.6 {
269
+ return None;
270
+ }
271
+
272
+ Some(PatternResult {
273
+ pattern: CandlePattern::EveningStar,
274
+ confidence: (third_body / first_body).min(1.0),
275
+ index: 0,
276
+ is_bullish: false,
277
+ })
278
+ }
279
+
280
+ /// Detect Three White Soldiers pattern
281
+ fn detect_three_soldiers(
282
+ first: &OHLCV,
283
+ second: &OHLCV,
284
+ third: &OHLCV,
285
+ _config: &PatternConfig,
286
+ ) -> Option<PatternResult> {
287
+ // Three consecutive bullish candles
288
+ // Each opens within previous body
289
+ // Each closes higher
290
+
291
+ if !first.is_bullish() || !second.is_bullish() || !third.is_bullish() {
292
+ return None;
293
+ }
294
+
295
+ // Check progression
296
+ if second.close <= first.close || third.close <= second.close {
297
+ return None;
298
+ }
299
+
300
+ // Check opens are within previous bodies
301
+ if second.open < first.close.min(first.open)
302
+ || second.open > first.close.max(first.open)
303
+ || third.open < second.close.min(second.open)
304
+ || third.open > second.close.max(second.open)
305
+ {
306
+ return None;
307
+ }
308
+
309
+ Some(PatternResult {
310
+ pattern: CandlePattern::ThreeWhiteSoldiers,
311
+ confidence: 0.9,
312
+ index: 0,
313
+ is_bullish: true,
314
+ })
315
+ }
316
+
317
+ /// Detect Three Black Crows pattern
318
+ fn detect_three_crows(
319
+ first: &OHLCV,
320
+ second: &OHLCV,
321
+ third: &OHLCV,
322
+ _config: &PatternConfig,
323
+ ) -> Option<PatternResult> {
324
+ // Three consecutive bearish candles
325
+ // Each opens within previous body
326
+ // Each closes lower
327
+
328
+ if !first.is_bearish() || !second.is_bearish() || !third.is_bearish() {
329
+ return None;
330
+ }
331
+
332
+ // Check progression
333
+ if second.close >= first.close || third.close >= second.close {
334
+ return None;
335
+ }
336
+
337
+ // Check opens are within previous bodies
338
+ if second.open < first.close.min(first.open)
339
+ || second.open > first.close.max(first.open)
340
+ || third.open < second.close.min(second.open)
341
+ || third.open > second.close.max(second.open)
342
+ {
343
+ return None;
344
+ }
345
+
346
+ Some(PatternResult {
347
+ pattern: CandlePattern::ThreeBlackCrows,
348
+ confidence: 0.9,
349
+ index: 0,
350
+ is_bullish: false,
351
+ })
352
+ }
353
+
354
+ #[cfg(test)]
355
+ mod tests {
356
+ use super::*;
357
+
358
+ #[test]
359
+ fn test_doji_detection() {
360
+ let candle = OHLCV::new(0, 100.0, 105.0, 95.0, 100.5, 1000.0);
361
+ let config = PatternConfig::default();
362
+ let result = detect_doji(&candle, &config);
363
+ assert!(result.is_some());
364
+ assert_eq!(result.unwrap().pattern, CandlePattern::Doji);
365
+ }
366
+
367
+ #[test]
368
+ fn test_bullish_engulfing() {
369
+ let prev = OHLCV::new(0, 102.0, 103.0, 98.0, 99.0, 1000.0);
370
+ let curr = OHLCV::new(0, 98.5, 105.0, 98.0, 104.0, 1000.0);
371
+ let config = PatternConfig::default();
372
+ let result = detect_engulfing(&prev, &curr, &config);
373
+ assert!(result.is_some());
374
+ assert_eq!(result.unwrap().pattern, CandlePattern::BullishEngulfing);
375
+ }
376
+
377
+ #[test]
378
+ fn test_module_reexports() {
379
+ // Test that all types are properly re-exported
380
+ use super::*;
381
+
382
+ // Support/Resistance types
383
+ let _level_type = LevelType::Support;
384
+
385
+ // Chart pattern types
386
+ let _pattern_type = PatternType::DoubleTop;
387
+ let _direction = PatternDirection::Bullish;
388
+
389
+ // Breakout types
390
+ let _breakout_dir = BreakoutDirection::Up;
391
+
392
+ // This test just verifies the types compile correctly
393
+ }
394
+ }