use super::*;
use crate::error::TaError;
use crate::indicator::indicator;
indicator! {
fn cdl_sticksandwich(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_sticksandwich_with_output init zero;
}
pub fn cdl_sticksandwich_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_sticksandwich_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_sticksandwich")?;
let n = open.len();
let lookback = EQUAL.avg_period + 2; if n <= lookback {
return Ok(());
}
let mut sum_avg_eq = {
let mut s = lookback - 2 - 5;
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_eq = lookback - 2 - 5;
let mut i = lookback;
while i < n {
let cur_avg_eq = high_low_range(high[i - 2], low[i - 2]);
let val_avg_eq = sum_avg_eq / 5 as f64 * 0.05;
out[i] = if 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 && low[i - 1] > close[i - 2] && close[i] <= close[i - 2] + val_avg_eq && close[i] >= close[i - 2] - val_avg_eq
{
100.0
} else {
0.0
};
sum_avg_eq += cur_avg_eq - high_low_range(high[trail_avg_eq], low[trail_avg_eq]);
trail_avg_eq += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_takuri(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_takuri_with_output init zero;
}
pub fn cdl_takuri_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_takuri_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_takuri")?;
let n = open.len();
let lookback = BODY_DOJI
.avg_period
.max(SHADOW_VERY_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 += high_low_range(high[s], low[s]);
s += 1;
}
acc
};
let mut trail_avg_body = lookback - 0 - 10;
let mut sum_avg_us = {
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_us = lookback - 0 - 10;
let mut sum_avg_ls = {
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_ls = lookback - 0 - 0;
let mut i = lookback;
while i < n {
let cur_avg_body = high_low_range(high[i], low[i]);
let val_avg_body = sum_avg_body / 10 as f64 * 0.1;
let cur_avg_us = high_low_range(high[i], low[i]);
let val_avg_us = sum_avg_us / 10 as f64 * 0.1;
let cur_avg_ls = real_body(open[i], close[i]);
let val_avg_ls = cur_avg_ls * 2.0;
out[i] = if cur_avg_ls <= val_avg_body
&& upper_shadow(open[i], high[i], close[i]) < val_avg_us
&& lower_shadow(open[i], low[i], close[i]) > val_avg_ls
{
100.0
} else {
0.0
};
sum_avg_body += cur_avg_body - high_low_range(high[trail_avg_body], low[trail_avg_body]);
trail_avg_body += 1;
sum_avg_us += cur_avg_us - high_low_range(high[trail_avg_us], low[trail_avg_us]);
trail_avg_us += 1;
sum_avg_ls += cur_avg_ls - real_body(open[trail_avg_ls], close[trail_avg_ls]);
trail_avg_ls += 1;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_tasukigap(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_tasukigap_with_output init zero;
}
pub fn cdl_tasukigap_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_tasukigap_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_tasukigap")?;
let n = open.len();
let lookback = NEAR.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 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;
out[i] = if (real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2]) && candle_color(open[i - 1], close[i - 1]) == 1.0 && candle_color(open[i], close[i]) == -1.0 && open[i] < close[i - 1] && open[i] > open[i - 1] && close[i] < open[i - 1] && close[i] > f64::max(close[i - 2], open[i - 2]) && (real_body(open[i - 1], close[i - 1]) - real_body(open[i], close[i])).abs()
< val_avg_near)
|| (real_body_gap_down(open[i - 1], close[i - 1], open[i - 2], close[i - 2]) && candle_color(open[i - 1], close[i - 1]) == -1.0 && candle_color(open[i], close[i]) == 1.0 && open[i] < open[i - 1] && open[i] > close[i - 1] && close[i] > open[i - 1] && close[i] < f64::min(close[i - 2], open[i - 2]) && (real_body(open[i - 1], close[i - 1]) - real_body(open[i], close[i])).abs()
< val_avg_near)
{
candle_color(open[i - 1], close[i - 1]) * 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;
i += 1;
}
Ok(())
}
indicator! {
fn cdl_thrusting(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_thrusting_with_output init zero;
}
pub fn cdl_thrusting_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_thrusting_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_thrusting")?;
let n = open.len();
let lookback = EQUAL.avg_period.max(BODY_LONG.avg_period) + 1; if n <= lookback {
return Ok(());
}
let mut sum_avg_eq = {
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_eq = lookback - 1 - 5;
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_eq = high_low_range(high[i - 1], low[i - 1]);
let val_avg_eq = sum_avg_eq / 5 as f64 * 0.05;
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] < low[i - 1] && close[i] > close[i - 1] + val_avg_eq && close[i] <= close[i - 1] + real_body(open[i - 1], close[i - 1]) * 0.5
{
-100.0
} else {
0.0
};
sum_avg_eq += cur_avg_eq - high_low_range(high[trail_avg_eq], low[trail_avg_eq]);
trail_avg_eq += 1;
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_tristar(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_tristar_with_output init zero;
}
pub fn cdl_tristar_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_tristar_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_tristar")?;
let n = open.len();
let lookback = BODY_DOJI.avg_period + 2; if n <= lookback {
return Ok(());
}
let mut avg_body = CandleAvg::new(BODY_DOJI, open, high, low, close, lookback, 2);
let mut i = lookback;
while i < n {
if real_body(open[i - 2], close[i - 2]) <= avg_body.value(i, open, high, low, close) && real_body(open[i - 1], close[i - 1]) <= avg_body.value(i, open, high, low, close) && real_body(open[i], close[i]) <= avg_body.value(i, open, high, low, close)
{
out[i] = 0.0;
if real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2]) && f64::max(open[i], close[i]) < f64::max(open[i - 1], close[i - 1])
{
out[i] = -100.0;
}
if real_body_gap_down(open[i - 1], close[i - 1], open[i - 2], close[i - 2]) && f64::min(open[i], close[i]) > f64::min(open[i - 1], close[i - 1])
{
out[i] = 100.0;
}
} else {
out[i] = 0.0;
}
avg_body.advance(i, open, high, low, close);
i += 1;
}
Ok(())
}
indicator! {
fn cdl_unique3river(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_unique3river_with_output init zero;
}
pub fn cdl_unique3river_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_unique3river_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_unique3river")?;
let n = open.len();
let lookback = BODY_SHORT.avg_period.max(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 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_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 && candle_color(open[i - 1], close[i - 1]) == -1.0 && close[i - 1] > close[i - 2] && open[i - 1] <= open[i - 2] && low[i - 1] < low[i - 2] && cur_avg_body_short < val_avg_body_short && candle_color(open[i], close[i]) == 1.0 && open[i] > low[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_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_upsidegap2crows(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_upsidegap2crows_with_output init zero;
}
pub fn cdl_upsidegap2crows_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_upsidegap2crows_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_upsidegap2crows")?;
let n = open.len();
let lookback = BODY_SHORT.avg_period.max(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 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 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;
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(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]) && candle_color(open[i], close[i]) == -1.0 && open[i] > open[i - 1] && close[i] < close[i - 1] && 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;
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_xsidegap3methods(open: &[f64], high: &[f64], low: &[f64], close: &[f64]) -> Vec<f64> with cdl_xsidegap3methods_with_output init zero;
}
pub fn cdl_xsidegap3methods_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_xsidegap3methods_with_output: out length must equal input length".into(),
));
}
check_ohlc(open, high, low, close, "cdl_xsidegap3methods")?;
let n = open.len();
let lookback = 2; if n <= lookback {
return Ok(());
}
let mut i = lookback;
while i < n {
if candle_color(open[i - 2], close[i - 2]) == candle_color(open[i - 1], close[i - 1]) && candle_color(open[i - 1], close[i - 1]) == -candle_color(open[i], close[i]) && open[i] < f64::max(close[i - 1], open[i - 1]) && open[i] > f64::min(close[i - 1], open[i - 1]) && close[i] < f64::max(close[i - 2], open[i - 2]) && close[i] > f64::min(close[i - 2], open[i - 2]) && ((candle_color(open[i - 2], close[i - 2]) == 1.0
&& real_body_gap_up(open[i - 1], close[i - 1], open[i - 2], close[i - 2])) || (candle_color(open[i - 2], close[i - 2]) == -1.0
&& real_body_gap_down(open[i - 1], close[i - 1], open[i - 2], close[i - 2])))
{
out[i] = candle_color(open[i - 2], close[i - 2]) * 100.0;
} else {
out[i] = 0.0;
}
i += 1;
}
Ok(())
}