quantwave_core/indicators/patterns/
cdl3linestrike.rs1use crate::indicators::patterns::candle_settings::{
4 CandleWindow, NEAR, RollingCandleAvg, candle_color,
5};
6use crate::traits::Next;
7
8const LOOKBACK: usize = 5 + 3; #[derive(Debug, Clone)]
11#[allow(non_camel_case_types)]
12pub struct CDL3LINESTRIKE {
13 bars_seen: usize,
14 window: CandleWindow,
15 near_avg: RollingCandleAvg,
16}
17
18impl CDL3LINESTRIKE {
19 pub fn new() -> Self {
20 Self {
21 bars_seen: 0,
22 window: CandleWindow::new(4), near_avg: RollingCandleAvg::new(NEAR),
24 }
25 }
26}
27
28impl Default for CDL3LINESTRIKE {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl Next<(f64, f64, f64, f64)> for CDL3LINESTRIKE {
35 type Output = f64;
36
37 fn next(&mut self, (open, high, low, close): (f64, f64, f64, f64)) -> Self::Output {
38 self.bars_seen += 1;
39
40 self.window.push(open, high, low, close);
41 self.near_avg.push(open, high, low, close);
42
43 if self.bars_seen <= LOOKBACK {
44 return 0.0;
45 }
46
47 let c3 = candle_color(self.window.bar(3).open, self.window.bar(3).close);
48 let c2 = candle_color(self.window.bar(2).open, self.window.bar(2).close);
49 let c1 = candle_color(self.window.bar(1).open, self.window.bar(1).close);
50 let c0 = candle_color(self.window.bar(0).open, self.window.bar(0).close);
51
52 if c3 == c2 && c2 == c1 && c0 != c1 {
53 let progressive = if c3 == 1 {
54 self.window.bar(2).close > self.window.bar(3).close
55 && self.window.bar(1).close > self.window.bar(2).close
56 } else {
57 self.window.bar(2).close < self.window.bar(3).close
58 && self.window.bar(1).close < self.window.bar(2).close
59 };
60
61 let opens_near = if c3 == 1 {
62 self.window.bar(2).open >= self.window.bar(3).open.min(self.window.bar(3).close)
63 && self.window.bar(2).open <= self.window.bar(3).close + self.near_avg.val(3)
64 && self.window.bar(1).open
65 >= self.window.bar(2).open.min(self.window.bar(2).close)
66 && self.window.bar(1).open <= self.window.bar(2).close + self.near_avg.val(2)
67 } else {
68 self.window.bar(2).open <= self.window.bar(3).open.max(self.window.bar(3).close)
69 && self.window.bar(2).open >= self.window.bar(3).close - self.near_avg.val(3)
70 && self.window.bar(1).open
71 <= self.window.bar(2).open.max(self.window.bar(2).close)
72 && self.window.bar(1).open >= self.window.bar(2).close - self.near_avg.val(2)
73 };
74
75 let strike = if c3 == 1 {
76 self.window.bar(0).open >= self.window.bar(1).close
77 && self.window.bar(0).close <= self.window.bar(3).open
78 } else {
79 self.window.bar(0).open <= self.window.bar(1).close
80 && self.window.bar(0).close >= self.window.bar(3).open
81 };
82
83 if progressive && opens_near && strike {
84 return (c3 * 100) as f64;
85 }
86 }
87
88 0.0
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 crate::test_pattern_parity!(
96 test_cdl3linestrike_parity,
97 CDL3LINESTRIKE,
98 talib_rs::pattern::cdl_3linestrike
99 );
100}