Skip to main content

quantwave_core/indicators/patterns/
cdlhammer.rs

1//! Native O(1) streaming CDLHAMMER (matches `talib_rs::pattern::cdl_hammer`).
2//! Source: TA-Lib
3
4use crate::indicators::patterns::candle_settings::{
5    BODY_SHORT, CandleWindow, NEAR, RollingCandleAvg, SHADOW_LONG, SHADOW_VERY_SHORT, lower_shadow,
6    real_body, upper_shadow,
7};
8use crate::traits::Next;
9
10const LOOKBACK: usize = 11; // max(10, 0, 10, 5) + 1
11
12#[derive(Debug, Clone)]
13#[allow(non_camel_case_types)]
14pub struct CDLHAMMER {
15    bars_seen: usize,
16    window: CandleWindow,
17    body_short: RollingCandleAvg,
18    shadow_long: RollingCandleAvg,
19    shadow_vs: RollingCandleAvg,
20    near: RollingCandleAvg,
21}
22
23impl CDLHAMMER {
24    pub fn new() -> Self {
25        Self {
26            bars_seen: 0,
27            window: CandleWindow::new(2),
28            body_short: RollingCandleAvg::new(BODY_SHORT),
29            shadow_long: RollingCandleAvg::new(SHADOW_LONG),
30            shadow_vs: RollingCandleAvg::new(SHADOW_VERY_SHORT),
31            near: RollingCandleAvg::new(NEAR),
32        }
33    }
34}
35
36impl Default for CDLHAMMER {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl Next<(f64, f64, f64, f64)> for CDLHAMMER {
43    type Output = f64;
44
45    fn next(&mut self, (open, high, low, close): (f64, f64, f64, f64)) -> Self::Output {
46        self.bars_seen += 1;
47        self.window.push(open, high, low, close);
48        self.body_short.push(open, high, low, close);
49        self.shadow_long.push(open, high, low, close);
50        self.shadow_vs.push(open, high, low, close);
51        self.near.push(open, high, low, close);
52
53        if self.bars_seen <= LOOKBACK {
54            return 0.0;
55        }
56
57        let curr = self.window.bar(0);
58        let prev = self.window.bar(1);
59
60        let out = (real_body(curr.open, curr.close) < self.body_short.val(0)
61            && lower_shadow(curr.open, curr.low, curr.close) > self.shadow_long.val(0)
62            && upper_shadow(curr.open, curr.high, curr.close) < self.shadow_vs.val(0)
63            && curr.open.min(curr.close) <= prev.low + self.near.val(1)) as i32
64            * 100;
65
66        out as f64
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    crate::test_pattern_parity!(
74        test_cdlhammer_parity,
75        CDLHAMMER,
76        talib_rs::pattern::cdl_hammer
77    );
78}