use super::*;
use crate::error::TaError;
use crate::indicator::indicator;
indicator! {
fn cdl_belthold(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_belthold_with_output init zero;
}
pub fn cdl_belthold_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_belthold_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_belthold")?;
let n = open.len();
let lookback = BODY_LONG.avg_period.max(SHADOW_VERY_SHORT.avg_period); 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_vs = {
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_vs = lookback - 0 - 10;
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_vs = high_low_range(high[i], low[i]);
let val_avg_vs = sum_avg_vs / 10 as f64 * 0.1;
out[i] = if cur_avg_body > val_avg_body
&& ((candle_color(open[i], close[i]) == 1.0
&& lower_shadow(open[i], low[i], close[i]) < val_avg_vs)
|| (candle_color(open[i], close[i]) == -1.0
&& upper_shadow(open[i], high[i], close[i]) < val_avg_vs))
{
candle_color(open[i], close[i]) * 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_vs += cur_avg_vs - high_low_range(high[trail_avg_vs], low[trail_avg_vs]);
trail_avg_vs += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_breakaway(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_breakaway_with_output init zero;
}
pub fn cdl_breakaway_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_breakaway_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_breakaway")?;
let n = open.len();
let lookback = BODY_LONG.avg_period + 4; if n <= lookback {
return Ok(());
}
let mut sum_avg_body = {
let mut s = lookback - 4 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 4) {
acc += real_body(open[s], close[s]);
s += 1;
}
acc
};
let mut trail_avg_body = lookback - 4 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body = real_body(open[i - 4], close[i - 4]);
let val_avg_body = sum_avg_body / 10 as f64 * 1.0;
out[i] = if real_body(open[i - 4], close[i - 4]) > val_avg_body
&& candle_color(open[i - 4], close[i - 4]) == candle_color(open[i - 3], close[i - 3])
&& candle_color(open[i - 3], close[i - 3]) == candle_color(open[i - 1], close[i - 1])
&& candle_color(open[i - 1], close[i - 1]) == -candle_color(open[i], close[i])
&& ((candle_color(open[i - 4], close[i - 4]) == -1.0
&& real_body_gap_down(open[i - 3], close[i - 3], open[i - 4], close[i - 4])
&& high[i - 2] < high[i - 3]
&& low[i - 2] < low[i - 3]
&& high[i - 1] < high[i - 2]
&& low[i - 1] < low[i - 2]
&& close[i] > open[i - 3]
&& close[i] < close[i - 4])
|| (candle_color(open[i - 4], close[i - 4]) == 1.0
&& real_body_gap_up(open[i - 3], close[i - 3], open[i - 4], close[i - 4])
&& high[i - 2] > high[i - 3]
&& low[i - 2] > low[i - 3]
&& high[i - 1] > high[i - 2]
&& low[i - 1] > low[i - 2]
&& close[i] < open[i - 3]
&& close[i] > close[i - 4]))
{
candle_color(open[i], close[i]) * 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;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_closingmarubozu(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_closingmarubozu_with_output init zero;
}
pub fn cdl_closingmarubozu_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_closingmarubozu_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_closingmarubozu")?;
let n = open.len();
let lookback = BODY_LONG.avg_period.max(SHADOW_VERY_SHORT.avg_period); 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_vs = {
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_vs = lookback - 0 - 10;
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_vs = high_low_range(high[i], low[i]);
let val_avg_vs = sum_avg_vs / 10 as f64 * 0.1;
out[i] = if cur_avg_body > val_avg_body
&& ((candle_color(open[i], close[i]) == 1.0
&& upper_shadow(open[i], high[i], close[i]) < val_avg_vs)
|| (candle_color(open[i], close[i]) == -1.0
&& lower_shadow(open[i], low[i], close[i]) < val_avg_vs))
{
candle_color(open[i], close[i]) * 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_vs += cur_avg_vs - high_low_range(high[trail_avg_vs], low[trail_avg_vs]);
trail_avg_vs += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_concealbabyswall(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_concealbabyswall_with_output init zero;
}
pub fn cdl_concealbabyswall_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_concealbabyswall_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_concealbabyswall")?;
let n = open.len();
let lookback = SHADOW_VERY_SHORT.avg_period + 3; if n <= lookback {
return Ok(());
}
let mut sum_avg_vs_3 = {
let mut s = lookback - 3 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 3) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_vs_3 = lookback - 3 - 10;
let mut sum_avg_vs_2 = {
let mut s = lookback - 2 - 10;
let mut acc = 0.0_f64;
while s < (lookback - 2) {
acc += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_vs_2 = lookback - 2 - 10;
let mut sum_avg_vs_1 = {
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_vs_1 = lookback - 1 - 10;
let mut i = lookback;
while i < n {
let cur_avg_vs_3 = high_low_range(high[i - 3], low[i - 3]);
let val_avg_vs_3 = sum_avg_vs_3 / 10 as f64 * 0.1;
let cur_avg_vs_2 = high_low_range(high[i - 2], low[i - 2]);
let val_avg_vs_2 = sum_avg_vs_2 / 10 as f64 * 0.1;
let cur_avg_vs_1 = high_low_range(high[i - 1], low[i - 1]);
let val_avg_vs_1 = sum_avg_vs_1 / 10 as f64 * 0.1;
out[i] = if candle_color(open[i - 3], close[i - 3]) == -1.0
&& candle_color(open[i - 2], close[i - 2]) == -1.0
&& candle_color(open[i - 1], close[i - 1]) == -1.0
&& candle_color(open[i], close[i]) == -1.0
&& lower_shadow(open[i - 3], low[i - 3], close[i - 3]) < val_avg_vs_3
&& upper_shadow(open[i - 3], high[i - 3], close[i - 3]) < val_avg_vs_3
&& lower_shadow(open[i - 2], low[i - 2], close[i - 2]) < val_avg_vs_2
&& upper_shadow(open[i - 2], high[i - 2], close[i - 2]) < val_avg_vs_2
&& real_body_gap_down(open[i - 1], close[i - 1], open[i - 2], close[i - 2])
&& upper_shadow(open[i - 1], high[i - 1], close[i - 1]) > val_avg_vs_1
&& high[i - 1] > close[i - 2]
&& high[i] > high[i - 1]
&& low[i] < low[i - 1]
{
100.0
} else {
0.0
};
sum_avg_vs_3 += cur_avg_vs_3 - high_low_range(high[trail_avg_vs_3], low[trail_avg_vs_3]);
trail_avg_vs_3 += 1;
sum_avg_vs_2 += cur_avg_vs_2 - high_low_range(high[trail_avg_vs_2], low[trail_avg_vs_2]);
trail_avg_vs_2 += 1;
sum_avg_vs_1 += cur_avg_vs_1 - high_low_range(high[trail_avg_vs_1], low[trail_avg_vs_1]);
trail_avg_vs_1 += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_counterattack(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_counterattack_with_output init zero;
}
pub fn cdl_counterattack_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_counterattack_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_counterattack")?;
let n = open.len();
let lookback = BODY_LONG.avg_period.max(EQUAL.avg_period) + 1; if n <= lookback {
return Ok(());
}
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 sum_avg_body_1 = {
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_1 = lookback - 1 - 10;
let mut sum_avg_body_0 = {
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_0 = lookback - 0 - 10;
let mut i = lookback;
while i < n {
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 cur_avg_body_1 = real_body(open[i - 1], close[i - 1]);
let val_avg_body_1 = sum_avg_body_1 / 10 as f64 * 1.0;
let cur_avg_body_0 = real_body(open[i], close[i]);
let val_avg_body_0 = sum_avg_body_0 / 10 as f64 * 1.0;
out[i] = if candle_color(open[i - 1], close[i - 1]) == -candle_color(open[i], close[i])
&& real_body(open[i - 1], close[i - 1]) > val_avg_body_1
&& cur_avg_body_0 > val_avg_body_0
&& close[i] <= close[i - 1] + val_avg_equal
&& close[i] >= close[i - 1] - val_avg_equal
{
candle_color(open[i], close[i]) * 100.0
} else {
0.0
};
sum_avg_equal +=
cur_avg_equal - high_low_range(high[trail_avg_equal], low[trail_avg_equal]);
trail_avg_equal += 1;
sum_avg_body_1 +=
cur_avg_body_1 - real_body(open[trail_avg_body_1], close[trail_avg_body_1]);
trail_avg_body_1 += 1;
sum_avg_body_0 +=
cur_avg_body_0 - real_body(open[trail_avg_body_0], close[trail_avg_body_0]);
trail_avg_body_0 += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_darkcloudcover(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_darkcloudcover_with_output init zero;
}
pub fn cdl_darkcloudcover_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_darkcloudcover_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_darkcloudcover")?;
let n = open.len();
let lookback = BODY_LONG.avg_period + 1; let penetration: f64 = 0.5; if n <= lookback {
return Ok(());
}
let mut sum_avg_body = {
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 = lookback - 1 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body = real_body(open[i - 1], close[i - 1]);
let val_avg_body = sum_avg_body / 10 as f64 * 1.0;
out[i] = if candle_color(open[i - 1], close[i - 1]) == 1.0
&& real_body(open[i - 1], close[i - 1]) > val_avg_body
&& candle_color(open[i], close[i]) == -1.0
&& open[i] > high[i - 1]
&& close[i] > open[i - 1]
&& close[i] < close[i - 1] - real_body(open[i - 1], close[i - 1]) * penetration
{
-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;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_dojistar(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_dojistar_with_output init zero;
}
pub fn cdl_dojistar_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_dojistar_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_dojistar")?;
let n = open.len();
let lookback = BODY_LONG.avg_period.max(BODY_DOJI.avg_period) + 1; if n <= lookback {
return Ok(());
}
let mut sum_avg_body = {
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 = lookback - 1 - 10;
let mut sum_avg_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_doji = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_body = real_body(open[i - 1], close[i - 1]);
let val_avg_body = sum_avg_body / 10 as f64 * 1.0;
let cur_avg_doji = high_low_range(high[i], low[i]);
let val_avg_doji = sum_avg_doji / 10 as f64 * 0.1;
out[i] = if real_body(open[i - 1], close[i - 1]) > val_avg_body
&& real_body(open[i], close[i]) <= val_avg_doji
&& ((candle_color(open[i - 1], close[i - 1]) == 1.0
&& real_body_gap_up(open[i], close[i], open[i - 1], close[i - 1]))
|| (candle_color(open[i - 1], close[i - 1]) == -1.0
&& real_body_gap_down(open[i], close[i], open[i - 1], close[i - 1])))
{
-candle_color(open[i - 1], close[i - 1]) * 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_doji += cur_avg_doji - high_low_range(high[trail_avg_doji], low[trail_avg_doji]);
trail_avg_doji += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_dragonflydoji(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_dragonflydoji_with_output init zero;
}
pub fn cdl_dragonflydoji_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_dragonflydoji_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_dragonflydoji")?;
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_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_doji = lookback - 0 - 10;
let mut sum_avg_vs = {
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_vs = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg_doji = high_low_range(high[i], low[i]);
let val_avg_doji = sum_avg_doji / 10 as f64 * 0.1;
let cur_avg_vs = high_low_range(high[i], low[i]);
let val_avg_vs = sum_avg_vs / 10 as f64 * 0.1;
out[i] = if real_body(open[i], close[i]) <= val_avg_doji
&& upper_shadow(open[i], high[i], close[i]) < val_avg_vs
&& lower_shadow(open[i], low[i], close[i]) > val_avg_vs
{
100.0
} else {
0.0
};
sum_avg_doji += cur_avg_doji - high_low_range(high[trail_avg_doji], low[trail_avg_doji]);
trail_avg_doji += 1;
sum_avg_vs += cur_avg_vs - high_low_range(high[trail_avg_vs], low[trail_avg_vs]);
trail_avg_vs += 1;
i += 1;
}
Ok(())
}