use super::*;
use crate::error::TaError;
use crate::indicator::indicator;
indicator! {
fn cdl_eveningdojistar(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_eveningdojistar_with_output init zero;
}
pub fn cdl_eveningdojistar_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_eveningdojistar_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_eveningdojistar")?;
let n = open.len();
let lookback = [
BODY_DOJI.avg_period,
BODY_LONG.avg_period,
BODY_SHORT.avg_period,
]
.iter()
.max()
.copied()
.unwrap()
+ 2; let penetration = 0.3;
if n <= lookback {
return Ok(());
}
let mut sum_avg_body_long = {
let mut s = lookback - 2 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 2) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_long = lookback - 2 - 10;
let mut sum_avg_body_doji = {
let mut s = lookback - 1 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_body_doji = lookback - 1 - 10;
let mut sum_avg_body_short = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_short = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body_long = real_body(open[i - 2], close[i - 2]);
let val_avg_body_long = sum_avg_body_long / 10 as f64 * 1.0;
let cur_avg_body_doji = high_low_range(high[i - 1], low[i - 1]);
let val_avg_body_doji = sum_avg_body_doji / 10 as f64 * 0.1;
let cur_avg_body_short = real_body(open[i], close[i]);
let val_avg_body_short = sum_avg_body_short / 10 as f64 * 1.0;
out[i] = if real_body(open[i - 2], close[i - 2]) > val_avg_body_long
&& candle_color(open[i - 2], close[i - 2]) == 1.0
&& real_body(open[i - 1], close[i - 1]) <= val_avg_body_doji
&& real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2])
&& cur_avg_body_short > val_avg_body_short
&& candle_color(open[i], close[i]) == -1.0
&& close[i] < close[i - 2] - real_body(open[i - 2], close[i - 2]) * penetration
{
-100.0
} else {
0.0
};
sum_avg_body_long +=
cur_avg_body_long - real_body(open[trail_avg_body_long], close[trail_avg_body_long]);
trail_avg_body_long += 1;
sum_avg_body_doji +=
cur_avg_body_doji - high_low_range(high[trail_avg_body_doji], low[trail_avg_body_doji]);
trail_avg_body_doji += 1;
sum_avg_body_short +=
cur_avg_body_short - real_body(open[trail_avg_body_short], close[trail_avg_body_short]);
trail_avg_body_short += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_eveningstar(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_eveningstar_with_output init zero;
}
pub fn cdl_eveningstar_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_eveningstar_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_eveningstar")?;
let n = open.len();
let lookback = BODY_SHORT.avg_period.max(BODY_LONG.avg_period) + 2; let penetration = 0.3;
if n <= lookback {
return Ok(());
}
let mut sum_avg_body_long = {
let mut s = lookback - 2 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 2) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_long = lookback - 2 - 10;
let mut sum_avg_body_short = {
let mut s = lookback - 1 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_short = lookback - 1 - 10;
let mut sum_avg_body_short2 = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_short2 = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body_long = real_body(open[i - 2], close[i - 2]);
let val_avg_body_long = sum_avg_body_long / 10 as f64 * 1.0;
let cur_avg_body_short = real_body(open[i - 1], close[i - 1]);
let val_avg_body_short = sum_avg_body_short / 10 as f64 * 1.0;
let cur_avg_body_short2 = real_body(open[i], close[i]);
let val_avg_body_short2 = sum_avg_body_short2 / 10 as f64 * 1.0;
out[i] = if real_body(open[i - 2], close[i - 2]) > val_avg_body_long
&& candle_color(open[i - 2], close[i - 2]) == 1.0
&& real_body(open[i - 1], close[i - 1]) <= val_avg_body_short
&& real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2])
&& cur_avg_body_short2 > val_avg_body_short2
&& candle_color(open[i], close[i]) == -1.0
&& close[i] < close[i - 2] - real_body(open[i - 2], close[i - 2]) * penetration
{
-100.0
} else {
0.0
};
sum_avg_body_long +=
cur_avg_body_long - real_body(open[trail_avg_body_long], close[trail_avg_body_long]);
trail_avg_body_long += 1;
sum_avg_body_short +=
cur_avg_body_short - real_body(open[trail_avg_body_short], close[trail_avg_body_short]);
trail_avg_body_short += 1;
sum_avg_body_short2 += cur_avg_body_short2
- real_body(open[trail_avg_body_short2], close[trail_avg_body_short2]);
trail_avg_body_short2 += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_gapsidesidewhite(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_gapsidesidewhite_with_output init zero;
}
pub fn cdl_gapsidesidewhite_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_gapsidesidewhite_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_gapsidesidewhite")?;
let n = open.len();
let lookback = NEAR.avg_period.max(EQUAL.avg_period) + 2; if n <= lookback {
return Ok(());
}
let mut sum_avg_near = {
let mut s = lookback - 1 - 5;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_near = lookback - 1 - 5;
let mut sum_avg_equal = {
let mut s = lookback - 1 - 5;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_equal = lookback - 1 - 5;
let mut i = lookback;
while i < n {
let cur_avg_near = high_low_range(high[i - 1], low[i - 1]);
let val_avg_near = sum_avg_near / 5 as f64 * 0.2;
let cur_avg_equal = high_low_range(high[i - 1], low[i - 1]);
let val_avg_equal = sum_avg_equal / 5 as f64 * 0.05;
let gap_up = real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2])
&& real_body_gap_up(open[i], close[i], open[i - 2], close[i - 2]);
let gap_down = real_body_gap_down(open[i - 1], close[i - 1], open[i - 2], close[i - 2])
&& real_body_gap_down(open[i], close[i], open[i - 2], close[i - 2]);
out[i] = if (gap_up || gap_down)
&& candle_color(open[i - 1], close[i - 1]) == 1.0
&& candle_color(open[i], close[i]) == 1.0
&& real_body(open[i], close[i]) >= real_body(open[i - 1], close[i - 1]) - val_avg_near
&& real_body(open[i], close[i]) <= real_body(open[i - 1], close[i - 1]) + val_avg_near
&& open[i] >= open[i - 1] - val_avg_equal
&& open[i] <= open[i - 1] + val_avg_equal
{
if gap_up { 100.0 } else { -100.0 }
} else {
0.0
};
sum_avg_near += cur_avg_near - high_low_range(high[trail_avg_near], low[trail_avg_near]);
trail_avg_near += 1;
sum_avg_equal +=
cur_avg_equal - high_low_range(high[trail_avg_equal], low[trail_avg_equal]);
trail_avg_equal += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_gravestonedoji(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_gravestonedoji_with_output init zero;
}
pub fn cdl_gravestonedoji_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_gravestonedoji_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_gravestonedoji")?;
let n = open.len();
let lookback = BODY_DOJI.avg_period.max(SHADOW_VERY_SHORT.avg_period); if n <= lookback {
return Ok(());
}
let mut sum_avg_body_doji = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_body_doji = lookback - 0 - 10;
let mut sum_avg_shadow_vshort = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_shadow_vshort = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body_doji = high_low_range(high[i], low[i]);
let val_avg_body_doji = sum_avg_body_doji / 10 as f64 * 0.1;
let cur_avg_shadow_vshort = high_low_range(high[i], low[i]);
let val_avg_shadow_vshort = sum_avg_shadow_vshort / 10 as f64 * 0.1;
out[i] = if real_body(open[i], close[i]) <= val_avg_body_doji
&& lower_shadow(open[i], low[i], close[i]) < val_avg_shadow_vshort
&& upper_shadow(open[i], high[i], close[i]) > val_avg_shadow_vshort
{
100.0
} else {
0.0
};
sum_avg_body_doji +=
cur_avg_body_doji - high_low_range(high[trail_avg_body_doji], low[trail_avg_body_doji]);
trail_avg_body_doji += 1;
sum_avg_shadow_vshort += cur_avg_shadow_vshort
- high_low_range(high[trail_avg_shadow_vshort], low[trail_avg_shadow_vshort]);
trail_avg_shadow_vshort += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_hangingman(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_hangingman_with_output init zero;
}
pub fn cdl_hangingman_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_hangingman_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_hangingman")?;
let n = open.len();
let lookback = [
BODY_SHORT.avg_period,
SHADOW_LONG.avg_period,
SHADOW_VERY_SHORT.avg_period,
NEAR.avg_period,
]
.iter()
.max()
.copied()
.unwrap()
+ 1; if n <= lookback {
return Ok(());
}
let mut sum_avg_body = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body = lookback - 0 - 10;
let mut sum_avg_shadow_long = {
let mut s = lookback - 0 - 0;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_shadow_long = lookback - 0 - 0;
let mut sum_avg_shadow_vshort = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_shadow_vshort = lookback - 0 - 10;
let mut sum_avg_near = {
let mut s = lookback - 1 - 5;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_near = lookback - 1 - 5;
let mut i = lookback;
while i < n {
let cur_avg_body = real_body(open[i], close[i]);
let val_avg_body = sum_avg_body / 10 as f64 * 1.0;
let cur_avg_shadow_long = real_body(open[i], close[i]);
let val_avg_shadow_long = cur_avg_shadow_long * 1.0;
let cur_avg_shadow_vshort = high_low_range(high[i], low[i]);
let val_avg_shadow_vshort = sum_avg_shadow_vshort / 10 as f64 * 0.1;
let cur_avg_near = high_low_range(high[i - 1], low[i - 1]);
let val_avg_near = sum_avg_near / 5 as f64 * 0.2;
out[i] = if real_body(open[i], close[i]) < val_avg_body
&& lower_shadow(open[i], low[i], close[i]) > val_avg_shadow_long
&& upper_shadow(open[i], high[i], close[i]) < val_avg_shadow_vshort
&& open[i].min(close[i]) >= high[i - 1] - val_avg_near
{
-100.0
} else {
0.0
};
sum_avg_body += cur_avg_body - real_body(open[trail_avg_body], close[trail_avg_body]);
trail_avg_body += 1;
sum_avg_shadow_long += cur_avg_shadow_long
- real_body(open[trail_avg_shadow_long], close[trail_avg_shadow_long]);
trail_avg_shadow_long += 1;
sum_avg_shadow_vshort += cur_avg_shadow_vshort
- high_low_range(high[trail_avg_shadow_vshort], low[trail_avg_shadow_vshort]);
trail_avg_shadow_vshort += 1;
sum_avg_near += cur_avg_near - high_low_range(high[trail_avg_near], low[trail_avg_near]);
trail_avg_near += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_haramicross(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_haramicross_with_output init zero;
}
pub fn cdl_haramicross_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_haramicross_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_haramicross")?;
let n = open.len();
let lookback = BODY_DOJI.avg_period.max(BODY_LONG.avg_period) + 1; if n <= lookback {
return Ok(());
}
let mut sum_avg_body_long = {
let mut s = lookback - 1 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 1) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body_long = lookback - 1 - 10;
let mut sum_avg_body_doji = {
let mut s = lookback - 0 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 0) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_body_doji = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body_long = real_body(open[i - 1], close[i - 1]);
let val_avg_body_long = sum_avg_body_long / 10 as f64 * 1.0;
let cur_avg_body_doji = high_low_range(high[i], low[i]);
let val_avg_body_doji = sum_avg_body_doji / 10 as f64 * 0.1;
out[i] = if real_body(open[i - 1], close[i - 1]) > val_avg_body_long
&& real_body(open[i], close[i]) <= val_avg_body_doji
&& open[i].max(close[i]) < open[i - 1].max(close[i - 1])
&& open[i].min(close[i]) > open[i - 1].min(close[i - 1])
{
-candle_color(open[i - 1], close[i - 1]) * 100.0
} else {
0.0
};
sum_avg_body_long +=
cur_avg_body_long - real_body(open[trail_avg_body_long], close[trail_avg_body_long]);
trail_avg_body_long += 1;
sum_avg_body_doji +=
cur_avg_body_doji - high_low_range(high[trail_avg_body_doji], low[trail_avg_body_doji]);
trail_avg_body_doji += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_hikkake(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_hikkake_with_output init zero;
}
pub fn cdl_hikkake_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_hikkake_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_hikkake")?;
let n = open.len();
let lookback = 5;
if n <= lookback {
return Ok(());
}
let mut pattern_idx: i64 = 0;
let mut pattern_result: f64 = 0.0;
let mut i = lookback - 3;
while i < lookback {
if high[i - 1] < high[i - 2]
&& low[i - 1] > low[i - 2]
&& ((high[i] < high[i - 1] && low[i] < low[i - 1])
|| (high[i] > high[i - 1] && low[i] > low[i - 1]))
{
pattern_result = 100.0 * if high[i] < high[i - 1] { 1.0 } else { -1.0 };
pattern_idx = i as i64;
} else if (i as i64) <= pattern_idx + 3
&& ((pattern_result > 0.0 && close[i] > high[pattern_idx as usize - 1])
|| (pattern_result < 0.0 && close[i] < low[pattern_idx as usize - 1]))
{
pattern_idx = 0;
}
i += 1;
}
i = lookback;
while i < n {
let val;
if high[i - 1] < high[i - 2]
&& low[i - 1] > low[i - 2]
&& ((high[i] < high[i - 1] && low[i] < low[i - 1])
|| (high[i] > high[i - 1] && low[i] > low[i - 1]))
{
pattern_result = 100.0 * if high[i] < high[i - 1] { 1.0 } else { -1.0 };
pattern_idx = i as i64;
val = pattern_result;
} else if (i as i64) <= pattern_idx + 3
&& ((pattern_result > 0.0 && close[i] > high[pattern_idx as usize - 1])
|| (pattern_result < 0.0 && close[i] < low[pattern_idx as usize - 1]))
{
val = pattern_result + 100.0 * if pattern_result > 0.0 { 1.0 } else { -1.0 };
pattern_idx = 0;
} else {
val = 0.0;
}
out[i] = val;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_hikkakemod(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_hikkakemod_with_output init zero;
}
pub fn cdl_hikkakemod_with_output(
open: &[f64],
high: &[f64],
low: &[f64],
close: &[f64],
out: &mut [f64],
) -> Result<(), TaError> {
if out.len() != open.len() {
return Err(TaError::BadParam(
"cdl_hikkakemod_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_hikkakemod")?;
let n = open.len();
let lookback = NEAR.avg_period.max(1) + 5; if n <= lookback {
return Ok(());
}
let mut avg_near = CandleAvg::new(NEAR, open, high, low, close, lookback - 3, 2);
let mut pattern_idx: i64 = 0;
let mut pattern_result: f64 = 0.0;
let mut i = lookback - 3;
while i < lookback {
let near = avg_near.value(i, open, high, low, close);
if high[i - 2] < high[i - 3]
&& low[i - 2] > low[i - 3]
&& high[i - 1] < high[i - 2]
&& low[i - 1] > low[i - 2]
&& ((high[i] < high[i - 1] && low[i] < low[i - 1] && close[i - 2] <= low[i - 2] + near)
|| (high[i] > high[i - 1]
&& low[i] > low[i - 1]
&& close[i - 2] >= high[i - 2] - near))
{
pattern_result = 100.0 * if high[i] < high[i - 1] { 1.0 } else { -1.0 };
pattern_idx = i as i64;
} else if (i as i64) <= pattern_idx + 3
&& ((pattern_result > 0.0 && close[i] > high[pattern_idx as usize - 1])
|| (pattern_result < 0.0 && close[i] < low[pattern_idx as usize - 1]))
{
pattern_idx = 0;
}
avg_near.advance(i, open, high, low, close);
i += 1;
}
i = lookback;
while i < n {
let near = avg_near.value(i, open, high, low, close);
let val;
if high[i - 2] < high[i - 3]
&& low[i - 2] > low[i - 3]
&& high[i - 1] < high[i - 2]
&& low[i - 1] > low[i - 2]
&& ((high[i] < high[i - 1] && low[i] < low[i - 1] && close[i - 2] <= low[i - 2] + near)
|| (high[i] > high[i - 1]
&& low[i] > low[i - 1]
&& close[i - 2] >= high[i - 2] - near))
{
pattern_result = 100.0 * if high[i] < high[i - 1] { 1.0 } else { -1.0 };
pattern_idx = i as i64;
val = pattern_result;
} else if (i as i64) <= pattern_idx + 3
&& ((pattern_result > 0.0 && close[i] > high[pattern_idx as usize - 1])
|| (pattern_result < 0.0 && close[i] < low[pattern_idx as usize - 1]))
{
val = pattern_result + 100.0 * if pattern_result > 0.0 { 1.0 } else { -1.0 };
pattern_idx = 0;
} else {
val = 0.0;
}
out[i] = val;
avg_near.advance(i, open, high, low, close);
i += 1;
}
Ok(())
}