use crate::{
KandError,
TAFloat,
TAInt,
helper::{real_body_length, upper_shadow_length},
types::Signal,
};
pub const fn lookback() -> Result<usize, KandError> {
Ok(0)
}
pub fn cdl_dragonfly_doji(
input_open: &[TAFloat],
input_high: &[TAFloat],
input_low: &[TAFloat],
input_close: &[TAFloat],
param_body_percent: TAFloat,
output_signals: &mut [TAInt],
) -> Result<(), KandError> {
let len = input_open.len();
#[cfg(feature = "check")]
{
if len != input_high.len()
|| len != input_low.len()
|| len != input_close.len()
|| len != output_signals.len()
{
return Err(KandError::LengthMismatch);
}
if param_body_percent <= 0.0 {
return Err(KandError::InvalidParameter);
}
}
#[cfg(feature = "deep-check")]
{
for i in 0..len {
if input_open[i].is_nan()
|| input_high[i].is_nan()
|| input_low[i].is_nan()
|| input_close[i].is_nan()
{
return Err(KandError::NaNDetected);
}
}
}
for i in 0..len {
output_signals[i] = cdl_dragonfly_doji_inc(
input_open[i],
input_high[i],
input_low[i],
input_close[i],
param_body_percent,
)?;
}
Ok(())
}
pub fn cdl_dragonfly_doji_inc(
input_open: TAFloat,
input_high: TAFloat,
input_low: TAFloat,
input_close: TAFloat,
param_body_percent: TAFloat,
) -> Result<TAInt, KandError> {
#[cfg(feature = "check")]
{
if param_body_percent <= 0.0 {
return Err(KandError::InvalidParameter);
}
}
#[cfg(feature = "deep-check")]
{
if input_open.is_nan() || input_high.is_nan() || input_low.is_nan() || input_close.is_nan()
{
return Err(KandError::NaNDetected);
}
}
let body = real_body_length(input_open, input_close);
let range = input_high - input_low;
let up_shadow = upper_shadow_length(input_high, input_open, input_close);
let is_doji_body = range > 0.0 && body <= range * param_body_percent / 100.0;
let has_minimal_upper_shadow = up_shadow <= body;
let signal = if is_doji_body && has_minimal_upper_shadow {
Signal::Bullish.into()
} else {
Signal::Neutral.into()
};
Ok(signal)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cdl_dragonfly_doji() {
let input_open = vec![
97285.7, 97486.5, 97009.3, 96554.9, 96542.5, 96450.1, 96772.8, 96797.0, 96662.7,
96252.2, 96131.1, 96364.3, 96274.1, 96448.0, 96408.3, 95960.1, 95946.0, 96238.8,
96358.5, 96770.6, 96884.2, 96613.9, 96489.0, 96710.1, 96779.9, 96149.6, 96548.1,
96560.0, 96923.0, 96567.1, 96571.7, 96341.5, 96515.0, 96720.2, 96746.1, 96461.1,
96460.9, 96735.0, 96679.9, 96759.9, 97350.8, 97216.6, 97346.4, 97419.9, 97534.2,
97521.6,
];
let input_high = vec![
97500.0, 97500.0, 97076.1, 96754.1, 96826.5, 96795.0, 97154.2, 96936.7, 96797.1,
96415.7, 96430.0, 96539.7, 96530.5, 96883.1, 96412.7, 96161.9, 96327.2, 96408.3,
96781.0, 97041.4, 96913.2, 96696.8, 96730.7, 96827.7, 96794.7, 96577.5, 96560.0,
96923.0, 96923.0, 96638.4, 96634.5, 96576.4, 96896.7, 96896.5, 96788.3, 96563.4,
96815.0, 96822.3, 96835.0, 97805.8, 97561.9, 97473.4, 97480.0, 97586.0, 97727.7,
97639.8,
];
let input_low = vec![
97147.7, 96845.8, 96536.0, 96337.2, 96330.0, 96440.0, 96592.4, 96662.7, 96220.0,
96111.0, 95811.1, 96161.5, 95880.1, 96390.5, 95860.0, 95613.5, 95736.0, 96093.4,
96337.3, 96650.8, 96609.1, 96313.0, 96050.4, 96522.0, 96036.0, 96130.0, 96313.1,
96410.4, 96548.1, 96439.6, 96161.1, 96311.8, 96488.5, 96611.9, 96446.1, 96358.3,
96456.2, 96600.0, 96508.0, 96700.0, 97150.0, 97021.3, 97290.0, 97333.5, 97411.4,
97355.0,
];
let input_close = vec![
97486.5, 97009.3, 96555.0, 96542.5, 96450.1, 96772.8, 96796.9, 96662.7, 96252.3,
96131.1, 96364.4, 96274.1, 96447.8, 96408.3, 95960.1, 95946.1, 96238.8, 96359.0,
96770.6, 96884.2, 96613.9, 96489.1, 96710.0, 96780.0, 96149.6, 96548.1, 96560.0,
96923.0, 96567.2, 96571.7, 96341.5, 96515.1, 96720.2, 96746.1, 96461.0, 96460.9,
96735.0, 96679.9, 96759.9, 97350.9, 97216.7, 97346.3, 97419.9, 97534.2, 97521.5,
97384.1,
];
let param_body_percent = 5.0;
let mut output_signals = vec![0i64; input_open.len()];
cdl_dragonfly_doji(
&input_open,
&input_high,
&input_low,
&input_close,
param_body_percent,
&mut output_signals,
)
.unwrap();
println!("output_signals: {output_signals:?}");
assert_eq!(output_signals[26], Signal::Bullish.into());
for i in 0..18 {
let signal: i64 = cdl_dragonfly_doji_inc(
input_open[i],
input_high[i],
input_low[i],
input_close[i],
param_body_percent,
)
.unwrap();
assert_eq!(signal, output_signals[i]);
}
}
}