#[path = "common/mod.rs"]
mod common;
use adaq_talib::pattern::*;
use adaq_talib::utils::approx_eq_slice;
fn check_cdl(
name: &str,
f: fn(&[f64], &[f64], &[f64], &[f64]) -> Result<Vec<f64>, adaq_talib::error::TaError>,
) {
let fixture = format!("cdl_{name}.json");
let json = common::load_json(&fixture).expect("load fixture");
let open = common::load_f64_array(&json, "open").expect("open");
let high = common::load_f64_array(&json, "high").expect("high");
let low = common::load_f64_array(&json, "low").expect("low");
let close = common::load_f64_array(&json, "close").expect("close");
let expected = common::load_f64_array(&json, "expected").expect("expected");
let out = f(&open, &high, &low, &close).expect("pattern fn");
assert_eq!(out.len(), expected.len(), "length mismatch for cdl_{name}");
assert!(
approx_eq_slice(&out, &expected),
"cdl_{name} output deviates from golden vector beyond ADR 0005 tolerance"
);
}
fn base(n: usize) -> (Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>) {
let mut o = vec![];
let mut h = vec![];
let mut l = vec![];
let mut c = vec![];
for _ in 0..n {
o.push(10.0);
h.push(12.0);
l.push(8.0);
c.push(10.3);
}
(o, h, l, c)
}
#[test]
fn cdl_piercing_matches_golden_vector() {
check_cdl("piercing", cdl_piercing);
}
#[test]
fn cdl_piercing_trigger() {
let (mut o, mut h, mut l, mut c) = base(15);
o.push(20.0); h.push(21.0); l.push(10.0); c.push(11.0);
o.push(9.0); h.push(16.0); l.push(8.0); c.push(16.0); let out = cdl_piercing(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_piercing_reject() {
let (mut o, mut h, mut l, mut c) = base(15);
o.push(20.0); h.push(21.0); l.push(10.0); c.push(11.0);
o.push(9.0); h.push(13.0); l.push(8.0); c.push(14.0); let out = cdl_piercing(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_rickshawman_matches_golden_vector() {
check_cdl("rickshawman", cdl_rickshawman);
}
#[test]
fn cdl_rickshawman_trigger() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(15.0); l.push(5.0); c.push(10.1);
let out = cdl_rickshawman(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_rickshawman_reject() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(15.0); l.push(5.0); c.push(14.0);
let out = cdl_rickshawman(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_risefall3methods_matches_golden_vector() {
check_cdl("risefall3methods", cdl_risefall3methods);
}
#[test]
fn cdl_risefall3methods_trigger() {
let (mut o, mut h, mut l, mut c) = base(14);
o.push(10.0); h.push(20.0); l.push(9.0); c.push(19.0);
o.push(19.0); h.push(19.1); l.push(18.7); c.push(18.8);
o.push(18.8); h.push(18.9); l.push(18.5); c.push(18.6);
o.push(18.6); h.push(18.7); l.push(18.3); c.push(18.4);
o.push(18.5); h.push(21.0); l.push(18.2); c.push(20.0); let out = cdl_risefall3methods(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_risefall3methods_reject() {
let (mut o, mut h, mut l, mut c) = base(14);
o.push(10.0); h.push(20.0); l.push(9.0); c.push(19.0);
o.push(19.0); h.push(19.1); l.push(18.7); c.push(18.8);
o.push(18.8); h.push(18.9); l.push(18.5); c.push(18.6);
o.push(18.6); h.push(18.7); l.push(18.3); c.push(18.4);
o.push(18.5); h.push(20.0); l.push(18.2); c.push(18.0); let out = cdl_risefall3methods(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_separatinglines_matches_golden_vector() {
check_cdl("separatinglines", cdl_separatinglines);
}
#[test]
fn cdl_separatinglines_trigger() {
let (mut o, mut h, mut l, mut c) = base(11);
o.push(10.0); h.push(11.0); l.push(4.0); c.push(5.0);
o.push(10.0); h.push(20.0); l.push(9.9); c.push(19.0);
let out = cdl_separatinglines(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_separatinglines_reject() {
let (mut o, mut h, mut l, mut c) = base(11);
o.push(10.0); h.push(11.0); l.push(4.0); c.push(5.0);
o.push(11.0); h.push(20.0); l.push(10.9); c.push(19.0);
let out = cdl_separatinglines(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_shortline_matches_golden_vector() {
check_cdl("shortline", cdl_shortline);
}
#[test]
fn cdl_shortline_trigger() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(10.8); l.push(9.2); c.push(10.1);
let out = cdl_shortline(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_shortline_reject() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(15.0); l.push(9.0); c.push(15.0);
let out = cdl_shortline(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_spinningtop_matches_golden_vector() {
check_cdl("spinningtop", cdl_spinningtop);
}
#[test]
fn cdl_spinningtop_trigger() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(15.0); l.push(5.0); c.push(10.1);
let out = cdl_spinningtop(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(100.0));
}
#[test]
fn cdl_spinningtop_reject() {
let (mut o, mut h, mut l, mut c) = base(10);
o.push(10.0); h.push(16.0); l.push(9.0); c.push(15.0);
let out = cdl_spinningtop(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}
#[test]
fn cdl_stalledpattern_matches_golden_vector() {
check_cdl("stalledpattern", cdl_stalledpattern);
}
#[test]
fn cdl_stalledpattern_trigger() {
let (mut o, mut h, mut l, mut c) = base(12);
o.push(10.0); h.push(20.0); l.push(9.0); c.push(19.0);
o.push(14.0); h.push(20.1); l.push(13.5); c.push(20.0);
o.push(19.5); h.push(21.0); l.push(19.0); c.push(20.5);
let out = cdl_stalledpattern(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(-100.0));
}
#[test]
fn cdl_stalledpattern_reject() {
let (mut o, mut h, mut l, mut c) = base(12);
o.push(10.0); h.push(20.0); l.push(9.0); c.push(19.0);
o.push(14.0); h.push(20.1); l.push(13.5); c.push(20.0);
o.push(19.0); h.push(20.5); l.push(18.8); c.push(19.5); let out = cdl_stalledpattern(&o, &h, &l, &c).unwrap();
assert_eq!(out.last().copied(), Some(0.0));
}