use super::engine::{CandleColor, PatternDefinition, RecognitionContext};
use super::{CandleSettingType, CandleSettings, PatternDirection, PatternSignal};
define_pattern_config!(CDL2CROWSConfig, CDL2CROWSBatchRunner, CDL2CROWSStream);
impl CDL2CROWSConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[CandleSettingType::BodyLong])
+ 2
}
}
impl PatternDefinition for CDL2CROWSConfig {
type State = ();
fn name(&self) -> &'static str {
"CDL2CROWS"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::BodyLong]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let first = context.candle(2);
let second = context.candle(1);
let third = context.candle(0);
if context.color(2) == CandleColor::White
&& context.real_body(2) > context.average(CandleSettingType::BodyLong, 2)
&& context.color(1) == CandleColor::Black
&& context.real_body_gap_up(1, 2)
&& context.color(0) == CandleColor::Black
&& third.open < second.open
&& third.open > second.close
&& third.close > first.open
&& third.close < first.close
{
PatternSignal::standard(PatternDirection::Bearish)
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDL3LINESTRIKEConfig,
CDL3LINESTRIKEBatchRunner,
CDL3LINESTRIKEStream
);
impl CDL3LINESTRIKEConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[CandleSettingType::Near]) + 3
}
}
impl PatternDefinition for CDL3LINESTRIKEConfig {
type State = ();
fn name(&self) -> &'static str {
"CDL3LINESTRIKE"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::Near]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let first = context.candle(3);
let second = context.candle(2);
let third = context.candle(1);
let fourth = context.candle(0);
let line_color = context.color(1);
let fourth_is_opposite = match line_color {
CandleColor::White => context.color(0) == CandleColor::Black,
CandleColor::Black => context.color(0) == CandleColor::White,
};
let near_first = context.average(CandleSettingType::Near, 3);
let near_second = context.average(CandleSettingType::Near, 2);
let strike = match line_color {
CandleColor::White => {
third.close > second.close
&& second.close > first.close
&& fourth.open > third.close
&& fourth.close < first.open
}
CandleColor::Black => {
third.close < second.close
&& second.close < first.close
&& fourth.open < third.close
&& fourth.close > first.open
}
};
if context.color(3) == context.color(2)
&& context.color(2) == line_color
&& fourth_is_opposite
&& second.open >= context.body_low(3) - near_first
&& second.open <= context.body_high(3) + near_first
&& third.open >= context.body_low(2) - near_second
&& third.open <= context.body_high(2) + near_second
&& strike
{
PatternSignal::standard(line_color.direction())
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDLGAPSIDESIDEWHITEConfig,
CDLGAPSIDESIDEWHITEBatchRunner,
CDLGAPSIDESIDEWHITEStream
);
impl CDLGAPSIDESIDEWHITEConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(
self.candle_settings,
&[CandleSettingType::Equal, CandleSettingType::Near],
) + 2
}
}
impl PatternDefinition for CDLGAPSIDESIDEWHITEConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLGAPSIDESIDEWHITE"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::Equal, CandleSettingType::Near]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let second = context.candle(1);
let third = context.candle(0);
let upside = context.real_body_gap_up(1, 2) && context.real_body_gap_up(0, 2);
let downside = context.real_body_gap_down(1, 2) && context.real_body_gap_down(0, 2);
let near = context.average(CandleSettingType::Near, 1);
let equal = context.average(CandleSettingType::Equal, 1);
if (upside || downside)
&& context.color(1) == CandleColor::White
&& context.color(0) == CandleColor::White
&& context.real_body(0) >= context.real_body(1) - near
&& context.real_body(0) <= context.real_body(1) + near
&& third.open >= second.open - equal
&& third.open <= second.open + equal
{
PatternSignal::standard(if upside {
PatternDirection::Bullish
} else {
PatternDirection::Bearish
})
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDLSTICKSANDWICHConfig,
CDLSTICKSANDWICHBatchRunner,
CDLSTICKSANDWICHStream
);
impl CDLSTICKSANDWICHConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[CandleSettingType::Equal]) + 2
}
}
impl PatternDefinition for CDLSTICKSANDWICHConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLSTICKSANDWICH"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::Equal]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let first = context.candle(2);
let second = context.candle(1);
let third = context.candle(0);
let equal = context.average(CandleSettingType::Equal, 2);
if context.color(2) == CandleColor::Black
&& context.color(1) == CandleColor::White
&& context.color(0) == CandleColor::Black
&& second.low > first.close
&& third.close <= first.close + equal
&& third.close >= first.close - equal
{
PatternSignal::standard(PatternDirection::Bullish)
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDLTASUKIGAPConfig,
CDLTASUKIGAPBatchRunner,
CDLTASUKIGAPStream
);
impl CDLTASUKIGAPConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[CandleSettingType::Near]) + 2
}
}
impl PatternDefinition for CDLTASUKIGAPConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLTASUKIGAP"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::Near]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let second = context.candle(1);
let third = context.candle(0);
let near = context.average(CandleSettingType::Near, 1);
let near_size = (context.real_body(1) - context.real_body(0)).abs() < near;
let upside = context.real_body_gap_up(1, 2)
&& context.color(1) == CandleColor::White
&& context.color(0) == CandleColor::Black
&& third.open < second.close
&& third.open > second.open
&& third.close < second.open
&& third.close > context.body_high(2)
&& near_size;
let downside = context.real_body_gap_down(1, 2)
&& context.color(1) == CandleColor::Black
&& context.color(0) == CandleColor::White
&& third.open < second.open
&& third.open > second.close
&& third.close > second.open
&& third.close < context.body_low(2)
&& near_size;
if upside || downside {
PatternSignal::standard(context.color(1).direction())
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(CDLTRISTARConfig, CDLTRISTARBatchRunner, CDLTRISTARStream);
impl CDLTRISTARConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[CandleSettingType::BodyDoji])
+ 2
}
}
impl PatternDefinition for CDLTRISTARConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLTRISTAR"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::BodyDoji]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let threshold = context.average(CandleSettingType::BodyDoji, 2);
if context.real_body(2) <= threshold
&& context.real_body(1) <= threshold
&& context.real_body(0) <= threshold
{
if context.real_body_gap_up(1, 2) && context.body_high(0) < context.body_high(1) {
PatternSignal::standard(PatternDirection::Bearish)
} else if context.real_body_gap_down(1, 2) && context.body_low(0) > context.body_low(1)
{
PatternSignal::standard(PatternDirection::Bullish)
} else {
PatternSignal::NoMatch
}
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDLUPSIDEGAP2CROWSConfig,
CDLUPSIDEGAP2CROWSBatchRunner,
CDLUPSIDEGAP2CROWSStream
);
impl CDLUPSIDEGAP2CROWSConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(
self.candle_settings,
&[CandleSettingType::BodyLong, CandleSettingType::BodyShort],
) + 2
}
}
impl PatternDefinition for CDLUPSIDEGAP2CROWSConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLUPSIDEGAP2CROWS"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[CandleSettingType::BodyLong, CandleSettingType::BodyShort]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let first = context.candle(2);
let second = context.candle(1);
let third = context.candle(0);
if context.color(2) == CandleColor::White
&& context.real_body(2) > context.average(CandleSettingType::BodyLong, 2)
&& context.color(1) == CandleColor::Black
&& context.real_body(1) <= context.average(CandleSettingType::BodyShort, 1)
&& context.real_body_gap_up(1, 2)
&& context.color(0) == CandleColor::Black
&& third.open > second.open
&& third.close < second.close
&& third.close > first.close
{
PatternSignal::standard(PatternDirection::Bearish)
} else {
PatternSignal::NoMatch
}
}
}
define_pattern_config!(
CDLXSIDEGAP3METHODSConfig,
CDLXSIDEGAP3METHODSBatchRunner,
CDLXSIDEGAP3METHODSStream
);
impl CDLXSIDEGAP3METHODSConfig {
#[inline]
pub fn warm_up(&self) -> usize {
super::engine::maximum_average_period(self.candle_settings, &[]) + 2
}
}
impl PatternDefinition for CDLXSIDEGAP3METHODSConfig {
type State = ();
fn name(&self) -> &'static str {
"CDLXSIDEGAP3METHODS"
}
fn settings(&self) -> CandleSettings {
self.candle_settings
}
fn referenced_settings(&self) -> &'static [CandleSettingType] {
&[]
}
fn lookback(&self) -> usize {
self.warm_up()
}
fn transition_start(&self) -> usize {
self.lookback()
}
fn initial_state(&self) -> Self::State {}
fn transition(
&self,
context: &RecognitionContext<'_>,
_state: &mut Self::State,
) -> PatternSignal {
let first_color = context.color(2);
let third = context.candle(0);
if first_color == context.color(1)
&& first_color != context.color(0)
&& third.open < context.body_high(1)
&& third.open > context.body_low(1)
&& third.close < context.body_high(2)
&& third.close > context.body_low(2)
&& ((first_color == CandleColor::White && context.real_body_gap_up(1, 2))
|| (first_color == CandleColor::Black && context.real_body_gap_down(1, 2)))
{
PatternSignal::standard(first_color.direction())
} else {
PatternSignal::NoMatch
}
}
}