use super::*;
use crate::error::TaError;
use crate::indicator::indicator;
indicator! {
fn cdl_doji(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_doji_with_output init zero;
}
pub fn cdl_doji_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_doji_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_doji")?;
let n = open.len();
let lookback = BODY_DOJI.avg_period; if n <= lookback {
return Ok(());
}
let mut sum_avg = {
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 = lookback - 0 - 10;
let mut i = lookback;
while i < n {
let cur_avg = high_low_range(high[i], low[i]);
let val_avg = sum_avg / 10 as f64 * 0.1;
out[i] = if real_body(open[i], close[i]) <= val_avg {
100.0
} else {
0.0
};
sum_avg += cur_avg - high_low_range(high[trail_avg], low[trail_avg]);
trail_avg += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_marubozu(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_marubozu_with_output init zero;
}
pub fn cdl_marubozu_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_marubozu_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_marubozu")?;
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_shadow = {
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 = 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_shadow = high_low_range(high[i], low[i]);
let val_avg_shadow = sum_avg_shadow / 10 as f64 * 0.1;
out[i] = if cur_avg_body > val_avg_body
&& upper_shadow(open[i], high[i], close[i]) < val_avg_shadow
&& lower_shadow(open[i], low[i], close[i]) < val_avg_shadow
{
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_shadow +=
cur_avg_shadow - high_low_range(high[trail_avg_shadow], low[trail_avg_shadow]);
trail_avg_shadow += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_hammer(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_hammer_with_output init zero;
}
pub fn cdl_hammer_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_hammer_with_output: out length must equal input length".into()));
}
check_ohlc(open, high, low, close, "cdl_hammer")?;
let n = open.len();
let lookback = 11usize;
if n <= lookback {
return Ok(());
}
let mut sum_body = 0.0_f64;
let mut s = 1usize;
while s < lookback {
sum_body += real_body(open[s], close[s]);
s += 1;
}
let mut t_body = 1usize; let mut sum_hl = 0.0_f64;
let mut s = 1usize;
while s < lookback {
sum_hl += high_low_range(high[s], low[s]);
s += 1;
}
let mut t_hl = 1usize;
let near_begin = lookback - 1 - 5; let near_end = lookback - 1; let mut sum_near = 0.0_f64;
let mut s = near_begin;
while s < near_end {
sum_near += high_low_range(high[s], low[s]);
s += 1;
}
let mut t_near = near_begin;
let mut i = lookback;
while i < n {
let rb = real_body(open[i], close[i]);
let ls = lower_shadow(open[i], low[i], close[i]);
let us = upper_shadow(open[i], high[i], close[i]);
let body_avg = (sum_body / 10.0) * 1.0; let shadow_long = rb; let hl_avg = (sum_hl / 10.0) * 0.1; let near_val = (sum_near / 5.0) * 0.2; if rb < body_avg
&& ls > shadow_long
&& us < hl_avg
&& open[i].min(close[i]) <= low[i - 1] + near_val
{
out[i] = 100.0;
} else {
out[i] = 0.0;
}
sum_body += rb - real_body(open[t_body], close[t_body]);
t_body += 1;
sum_hl += high_low_range(high[i], low[i]) - high_low_range(high[t_hl], low[t_hl]);
t_hl += 1;
let ni = i - 1;
sum_near += high_low_range(high[ni], low[ni]) - high_low_range(high[t_near], low[t_near]);
t_near += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_shootingstar(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_shootingstar_with_output init zero;
}
pub fn cdl_shootingstar_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_shootingstar_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_shootingstar")?;
let n = open.len();
let lookback = [
BODY_SHORT.avg_period,
SHADOW_LONG.avg_period,
SHADOW_VERY_SHORT.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 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;
out[i] = if real_body(open[i], close[i]) < val_avg_body
&& upper_shadow(open[i], high[i], close[i]) > val_avg_shadow_long
&& lower_shadow(open[i], low[i], close[i]) < val_avg_shadow_vshort
&& real_body_gap_up(open[i], close[i], 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_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;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_engulfing(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_engulfing_with_output init zero;
}
pub fn cdl_engulfing_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_engulfing_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_engulfing")?;
let n = open.len();
let lookback = 2; if n <= lookback {
return Ok(());
}
let mut prev_open = open[1];
let mut prev_close = close[1];
let mut prev_color = candle_color(prev_open, prev_close);
for i in lookback..n {
let cur_open = open[i];
let cur_close = close[i];
let cur_color = candle_color(cur_open, cur_close);
let bull = cur_color == 1.0 && prev_color == -1.0 && cur_close > prev_open;
let bear = cur_color == -1.0 && prev_color == 1.0 && cur_close < prev_open;
out[i] = if bull {
if cur_open < prev_close {
100.0
} else if cur_open <= prev_close {
80.0
} else {
0.0
}
} else if bear {
if cur_open > prev_close {
-100.0
} else if cur_open >= prev_close {
-80.0
} else {
0.0
}
} else {
0.0
};
prev_open = cur_open;
prev_close = cur_close;
prev_color = cur_color;
}
Ok(())
}
indicator! {
fn cdl_harami(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_harami_with_output init zero;
}
pub fn cdl_harami_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_harami_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_harami")?;
let n = open.len();
let lookback = BODY_LONG.avg_period.max(BODY_SHORT.avg_period) + 1; if n <= lookback {
return Ok(());
}
let mut avg_body_long = CandleAvg::new(BODY_LONG, open, high, low, close, lookback, 1);
let mut avg_body_short = CandleAvg::new(BODY_SHORT, open, high, low, close, lookback, 0);
let mut i = lookback;
while i < n {
let val_avg_body_long = avg_body_long.value(i, open, high, low, close);
let val_avg_body_short = avg_body_short.value(i, open, high, low, close);
out[i] = if real_body(open[i - 1], close[i - 1]) > val_avg_body_long
&& real_body(open[i], close[i]) <= val_avg_body_short
&& 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
};
avg_body_long.advance(i, open, high, low, close);
avg_body_short.advance(i, open, high, low, close);
i += 1;
}
Ok(())
}
indicator! {
fn cdl_highwave(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_highwave_with_output init zero;
}
pub fn cdl_highwave_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_highwave_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_highwave")?;
let n = open.len();
let lookback = BODY_SHORT.avg_period.max(SHADOW_VERY_LONG.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_shadow = {
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 = lookback - 0 - 0;
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 = real_body(open[i], close[i]);
let val_avg_shadow = cur_avg_shadow * 2.0;
out[i] = if real_body(open[i], close[i]) < val_avg_body
&& upper_shadow(open[i], high[i], close[i]) > val_avg_shadow
&& lower_shadow(open[i], low[i], close[i]) > val_avg_shadow
{
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_shadow +=
cur_avg_shadow - real_body(open[trail_avg_shadow], close[trail_avg_shadow]);
trail_avg_shadow += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_2crows(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_2crows_with_output init zero;
}
pub fn cdl_2crows_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_2crows_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_2crows")?;
let n = open.len();
let lookback = BODY_LONG.avg_period + 2; 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 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;
out[i] = if candle_color(open[i - 2], close[i - 2]) == 1.0 && real_body(open[i - 2], close[i - 2]) > val_avg_body_long
&& candle_color(open[i - 1], close[i - 1]) == -1.0 && real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2]) && candle_color(open[i], close[i]) == -1.0 && open[i] < open[i - 1]
&& open[i] > close[i - 1]
&& close[i] > open[i - 2]
&& close[i] < close[i - 2]
{
-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;
i += 1;
}
Ok(())
}