diff --git a/crates/wickra-core/src/indicators/doji_star.rs b/crates/wickra-core/src/indicators/doji_star.rs index 85b2d22e..75336fb7 100644 --- a/crates/wickra-core/src/indicators/doji_star.rs +++ b/crates/wickra-core/src/indicators/doji_star.rs @@ -202,4 +202,12 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(20.0, 20.2, 14.8, 15.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_yields_zero() { + let mut t = DojiStar::new(); + t.update(c(20.0, 20.2, 14.8, 15.0, 0)); + // Flat second bar (high == low) -> zero-range guard. + assert_eq!(t.update(c(13.0, 13.0, 13.0, 13.0, 1)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/evening_doji_star.rs b/crates/wickra-core/src/indicators/evening_doji_star.rs index 65d09053..639b5fe1 100644 --- a/crates/wickra-core/src/indicators/evening_doji_star.rs +++ b/crates/wickra-core/src/indicators/evening_doji_star.rs @@ -238,4 +238,22 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 15.1, 9.9, 15.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_yields_zero() { + let mut t = EveningDojiStar::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + t.update(c(17.0, 17.1, 16.9, 17.0, 1)); + assert_eq!(t.update(c(16.0, 16.1, 11.9, 12.0, 2)), Some(0.0)); + } + + #[test] + fn short_first_body_yields_zero() { + let mut t = EveningDojiStar::new(); + // bar1 has a wide range but a tiny body -> not a long white body. + t.update(c(10.0, 16.0, 9.0, 10.5, 0)); + t.update(c(17.0, 17.1, 16.9, 17.0, 1)); + assert_eq!(t.update(c(16.0, 16.1, 11.9, 12.0, 2)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/falling_three_methods.rs b/crates/wickra-core/src/indicators/falling_three_methods.rs index 19a0e0c5..6ac04d16 100644 --- a/crates/wickra-core/src/indicators/falling_three_methods.rs +++ b/crates/wickra-core/src/indicators/falling_three_methods.rs @@ -210,4 +210,26 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(15.0, 15.1, 9.9, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = FallingThreeMethods::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + t.update(c(11.0, 12.1, 10.9, 12.0, 1)); + t.update(c(11.5, 12.6, 11.4, 12.5, 2)); + t.update(c(12.0, 13.1, 11.9, 13.0, 3)); + assert_eq!(t.update(c(12.5, 12.6, 8.9, 9.0, 4)), Some(0.0)); + } + + #[test] + fn short_first_body_yields_zero() { + let mut t = FallingThreeMethods::new(); + // bar1 has a wide range but a tiny body -> not a long black body. + t.update(c(10.0, 16.0, 9.0, 10.2, 0)); + t.update(c(11.0, 12.1, 10.9, 12.0, 1)); + t.update(c(11.5, 12.6, 11.4, 12.5, 2)); + t.update(c(12.0, 13.1, 11.9, 13.0, 3)); + assert_eq!(t.update(c(12.5, 12.6, 8.9, 9.0, 4)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/gap_side_by_side_white.rs b/crates/wickra-core/src/indicators/gap_side_by_side_white.rs index f73fe98c..dd780ee2 100644 --- a/crates/wickra-core/src/indicators/gap_side_by_side_white.rs +++ b/crates/wickra-core/src/indicators/gap_side_by_side_white.rs @@ -217,4 +217,22 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 11.1, 9.9, 11.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_yields_zero() { + let mut t = GapSideBySideWhite::new(); + t.update(c(10.0, 11.1, 9.9, 11.0, 0)); + // Flat second bar (range2 == 0) -> rejected. + t.update(c(13.0, 13.0, 13.0, 13.0, 1)); + assert_eq!(t.update(c(13.0, 14.1, 12.9, 14.0, 2)), Some(0.0)); + } + + #[test] + fn body_size_mismatch_yields_zero() { + let mut t = GapSideBySideWhite::new(); + t.update(c(10.0, 11.1, 9.9, 11.0, 0)); + t.update(c(13.0, 16.0, 12.9, 15.0, 1)); // white, body 2.0 + // Level open, white, but its body is more than 2x smaller -> rejected. + assert_eq!(t.update(c(13.0, 13.7, 12.9, 13.5, 2)), Some(0.0)); // body 0.5 + } } diff --git a/crates/wickra-core/src/indicators/in_neck.rs b/crates/wickra-core/src/indicators/in_neck.rs index 16edc2c7..422ef1c1 100644 --- a/crates/wickra-core/src/indicators/in_neck.rs +++ b/crates/wickra-core/src/indicators/in_neck.rs @@ -180,4 +180,12 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(15.0, 15.1, 9.0, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = InNeck::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + assert_eq!(t.update(c(9.0, 10.0, 8.0, 9.5, 1)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/long_line.rs b/crates/wickra-core/src/indicators/long_line.rs index 39ebad74..f3e98fef 100644 --- a/crates/wickra-core/src/indicators/long_line.rs +++ b/crates/wickra-core/src/indicators/long_line.rs @@ -226,4 +226,9 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 13.0, 9.9, 12.9, 0)), Some(0.0)); } + + #[test] + fn default_matches_new() { + assert_eq!(LongLine::default().period(), LongLine::new().period()); + } } diff --git a/crates/wickra-core/src/indicators/mat_hold.rs b/crates/wickra-core/src/indicators/mat_hold.rs index 19c99d1a..b9f0c090 100644 --- a/crates/wickra-core/src/indicators/mat_hold.rs +++ b/crates/wickra-core/src/indicators/mat_hold.rs @@ -271,4 +271,38 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 15.1, 9.9, 15.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = MatHold::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + t.update(c(16.0, 16.1, 15.4, 15.5, 1)); + t.update(c(15.5, 15.6, 14.9, 15.0, 2)); + t.update(c(15.0, 15.1, 14.4, 14.5, 3)); + assert_eq!(t.update(c(14.5, 17.1, 14.4, 17.0, 4)), Some(0.0)); + } + + #[test] + fn short_first_body_yields_zero() { + let mut t = MatHold::new(); + // bar1 has a wide range but a tiny body -> not a long white body. + t.update(c(10.0, 16.0, 9.0, 10.5, 0)); + t.update(c(16.0, 16.1, 15.4, 15.5, 1)); + t.update(c(15.5, 15.6, 14.9, 15.0, 2)); + t.update(c(15.0, 15.1, 14.4, 14.5, 3)); + assert_eq!(t.update(c(14.5, 17.1, 14.4, 17.0, 4)), Some(0.0)); + } + + #[test] + fn no_gap_up_yields_zero() { + let mut t = MatHold::new(); + // Long white bar1 with small pullbacks, but bar2 fails to gap up above + // bar1's close. + t.update(c(10.0, 15.1, 9.9, 15.0, 0)); + t.update(c(14.5, 14.7, 14.3, 14.5, 1)); + t.update(c(14.5, 14.7, 14.3, 14.6, 2)); + t.update(c(14.6, 14.8, 14.4, 14.7, 3)); + assert_eq!(t.update(c(14.7, 17.1, 14.6, 17.0, 4)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/morning_doji_star.rs b/crates/wickra-core/src/indicators/morning_doji_star.rs index 9c368a21..d58a8c02 100644 --- a/crates/wickra-core/src/indicators/morning_doji_star.rs +++ b/crates/wickra-core/src/indicators/morning_doji_star.rs @@ -238,4 +238,22 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(15.0, 15.1, 9.9, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_yields_zero() { + let mut t = MorningDojiStar::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + t.update(c(8.0, 8.1, 7.9, 8.0, 1)); + assert_eq!(t.update(c(9.0, 13.1, 8.9, 13.0, 2)), Some(0.0)); + } + + #[test] + fn short_first_body_yields_zero() { + let mut t = MorningDojiStar::new(); + // bar1 has a wide range but a tiny body -> not a long black body. + t.update(c(10.0, 16.0, 9.0, 9.8, 0)); + t.update(c(8.0, 8.1, 7.9, 8.0, 1)); + assert_eq!(t.update(c(9.0, 13.1, 8.9, 13.0, 2)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/on_neck.rs b/crates/wickra-core/src/indicators/on_neck.rs index 2de38168..8864982a 100644 --- a/crates/wickra-core/src/indicators/on_neck.rs +++ b/crates/wickra-core/src/indicators/on_neck.rs @@ -178,4 +178,12 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(15.0, 15.1, 9.0, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = OnNeck::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + assert_eq!(t.update(c(9.0, 10.0, 8.0, 9.5, 1)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/rising_three_methods.rs b/crates/wickra-core/src/indicators/rising_three_methods.rs index 2c8bec5e..c1df8784 100644 --- a/crates/wickra-core/src/indicators/rising_three_methods.rs +++ b/crates/wickra-core/src/indicators/rising_three_methods.rs @@ -210,4 +210,26 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 15.1, 9.9, 15.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = RisingThreeMethods::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + t.update(c(14.0, 14.1, 12.9, 13.0, 1)); + t.update(c(13.5, 13.6, 12.4, 12.5, 2)); + t.update(c(13.0, 13.1, 11.9, 12.0, 3)); + assert_eq!(t.update(c(12.5, 16.1, 12.4, 16.0, 4)), Some(0.0)); + } + + #[test] + fn short_first_body_yields_zero() { + let mut t = RisingThreeMethods::new(); + // bar1 has a wide range but a tiny body -> not a long white body. + t.update(c(10.0, 16.0, 9.0, 10.2, 0)); + t.update(c(14.0, 14.1, 12.9, 13.0, 1)); + t.update(c(13.5, 13.6, 12.4, 12.5, 2)); + t.update(c(13.0, 13.1, 11.9, 12.0, 3)); + assert_eq!(t.update(c(12.5, 16.1, 12.4, 16.0, 4)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/separating_lines.rs b/crates/wickra-core/src/indicators/separating_lines.rs index 8fd73a22..1989723b 100644 --- a/crates/wickra-core/src/indicators/separating_lines.rs +++ b/crates/wickra-core/src/indicators/separating_lines.rs @@ -199,4 +199,20 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(12.0, 12.1, 9.9, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_yields_zero() { + let mut t = SeparatingLines::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + assert_eq!(t.update(c(10.0, 12.0, 9.0, 11.0, 1)), Some(0.0)); + } + + #[test] + fn short_second_body_yields_zero() { + let mut t = SeparatingLines::new(); + t.update(c(10.0, 12.0, 8.0, 9.0, 0)); + // Opens coincide but bar2's body is too short to be a separating line. + assert_eq!(t.update(c(10.0, 11.0, 9.0, 10.1, 1)), Some(0.0)); + } } diff --git a/crates/wickra-core/src/indicators/short_line.rs b/crates/wickra-core/src/indicators/short_line.rs index 6dd3e906..eabec8b6 100644 --- a/crates/wickra-core/src/indicators/short_line.rs +++ b/crates/wickra-core/src/indicators/short_line.rs @@ -225,4 +225,9 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(10.0, 11.0, 9.9, 10.9, 0)), Some(0.0)); } + + #[test] + fn default_matches_new() { + assert_eq!(ShortLine::default().period(), ShortLine::new().period()); + } } diff --git a/crates/wickra-core/src/indicators/thrusting.rs b/crates/wickra-core/src/indicators/thrusting.rs index dfc3afd3..aebab786 100644 --- a/crates/wickra-core/src/indicators/thrusting.rs +++ b/crates/wickra-core/src/indicators/thrusting.rs @@ -183,4 +183,12 @@ mod tests { assert!(!t.is_ready()); assert_eq!(t.update(c(15.0, 15.1, 9.0, 10.0, 0)), Some(0.0)); } + + #[test] + fn zero_range_first_bar_yields_zero() { + let mut t = Thrusting::new(); + // Flat first bar (range1 == 0) -> rejected. + t.update(c(10.0, 10.0, 10.0, 10.0, 0)); + assert_eq!(t.update(c(9.0, 10.0, 8.0, 9.5, 1)), Some(0.0)); + } }