feat(family-14): add 15 candlestick patterns (#53)

* feat(family-14): add 15 candlestick patterns

Introduces the Candlestick Patterns family (block A of the family-14 spec)
as scalar f64 indicators on Candle inputs. Each detector emits +1.0 for a
bullish reading, -1.0 for a bearish reading, and 0.0 when no pattern is
present. Doji is direction-less and emits +1.0 / 0.0 only.

New indicators (15):

- Doji
- Hammer
- InvertedHammer
- HangingMan
- ShootingStar
- Engulfing
- Harami
- MorningEveningStar (signed: +1.0 morning star, -1.0 evening star)
- ThreeSoldiersOrCrows (signed: +1.0 soldiers, -1.0 crows)
- PiercingDarkCloud (signed: +1.0 piercing, -1.0 dark cloud)
- Marubozu (signed: +1.0 bullish, -1.0 bearish, 5 percent shadow tolerance default)
- Tweezer (signed: +1.0 bottom, -1.0 top, 10 bps relative tolerance default)
- SpinningTop (direction-signed indecision)
- ThreeInside (confirmed Harami)
- ThreeOutside (confirmed Engulfing)

MVP scope notes:

- Pattern-shape check only, no trend filter applied. Caller combines with a
  trend indicator for actionable signals. Documented in every doc comment.
- Block B (Harmonic patterns) and block C (Chart patterns) remain
  out-of-scope and will follow when the pattern-detection framework (pivot
  detector, multi-bar state machines) lands.

Touched across all bindings: Python, Node, WASM. Fuzz target, Python tests
(streaming-vs-batch + reference values), Node tests (streaming-vs-batch +
reference values), and a representative bench subset (1-, 2- and 3-bar
patterns) added. README family table + indicator counter (71 -> 86, eight
-> nine families) and CHANGELOG [Unreleased] updated.

* fix(family-14): unpack MULTI values with *_ to handle 3-element tuples

* cov(family-14): cover Default impl cold paths and MorningEveningStar guard branches
This commit is contained in:
kingchenc
2026-05-26 00:54:11 +02:00
committed by GitHub
parent 9b8e1346ed
commit 55284a3042
28 changed files with 3490 additions and 50 deletions
+30
View File
@@ -49,6 +49,7 @@ mod dema;
mod demand_index;
mod demark_pivots;
mod detrended_std_dev;
mod doji;
mod donchian;
mod donchian_stop;
mod double_bollinger;
@@ -58,6 +59,7 @@ mod ehlers_stochastic;
mod elder_impulse;
mod ema;
mod empirical_mode_decomposition;
mod engulfing;
mod evwma;
mod fama;
mod fibonacci_pivots;
@@ -66,6 +68,9 @@ mod force_index;
mod fractal_chaos_bands;
mod frama;
mod garman_klass;
mod hammer;
mod hanging_man;
mod harami;
mod heikin_ashi;
mod hilbert_dominant_cycle;
mod hilo_activator;
@@ -78,6 +83,7 @@ mod inertia;
mod initial_balance;
mod instantaneous_trendline;
mod inverse_fisher_transform;
mod inverted_hammer;
mod jma;
mod kama;
mod keltner;
@@ -93,12 +99,14 @@ mod ma_envelope;
mod macd;
mod mama;
mod market_facilitation_index;
mod marubozu;
mod mass_index;
mod mcginley_dynamic;
mod median_absolute_deviation;
mod median_price;
mod mfi;
mod mom;
mod morning_evening_star;
mod natr;
mod nvi;
mod obv;
@@ -108,6 +116,7 @@ mod pearson_correlation;
mod percent_b;
mod percentage_trailing_stop;
mod pgo;
mod piercing_dark_cloud;
mod pmo;
mod ppo;
mod psar;
@@ -121,12 +130,14 @@ mod rsi;
mod rvi;
mod rvi_volatility;
mod rwi;
mod shooting_star;
mod sine_wave;
mod skewness;
mod sma;
mod smi;
mod smma;
mod spearman_correlation;
mod spinning_top;
mod standard_error;
mod standard_error_bands;
mod starc_bands;
@@ -151,6 +162,9 @@ mod td_risk_level;
mod td_sequential;
mod td_setup;
mod tema;
mod three_inside;
mod three_outside;
mod three_soldiers_or_crows;
mod tii;
mod trima;
mod trix;
@@ -158,6 +172,7 @@ mod true_range;
mod tsi;
mod tsv;
mod ttm_squeeze;
mod tweezer;
mod typical_price;
mod ulcer_index;
mod ultimate_oscillator;
@@ -231,6 +246,7 @@ pub use dema::Dema;
pub use demand_index::DemandIndex;
pub use demark_pivots::{DemarkPivots, DemarkPivotsOutput};
pub use detrended_std_dev::DetrendedStdDev;
pub use doji::Doji;
pub use donchian::{Donchian, DonchianOutput};
pub use donchian_stop::{DonchianStop, DonchianStopOutput};
pub use double_bollinger::{DoubleBollinger, DoubleBollingerOutput};
@@ -240,6 +256,7 @@ pub use ehlers_stochastic::EhlersStochastic;
pub use elder_impulse::ElderImpulse;
pub use ema::Ema;
pub use empirical_mode_decomposition::EmpiricalModeDecomposition;
pub use engulfing::Engulfing;
pub use evwma::Evwma;
pub use fama::Fama;
pub use fibonacci_pivots::{FibonacciPivots, FibonacciPivotsOutput};
@@ -248,6 +265,9 @@ pub use force_index::ForceIndex;
pub use fractal_chaos_bands::{FractalChaosBands, FractalChaosBandsOutput};
pub use frama::Frama;
pub use garman_klass::GarmanKlassVolatility;
pub use hammer::Hammer;
pub use hanging_man::HangingMan;
pub use harami::Harami;
pub use heikin_ashi::{HeikinAshi, HeikinAshiOutput};
pub use hilbert_dominant_cycle::HilbertDominantCycle;
pub use hilo_activator::HiLoActivator;
@@ -260,6 +280,7 @@ pub use inertia::Inertia;
pub use initial_balance::{InitialBalance, InitialBalanceOutput};
pub use instantaneous_trendline::InstantaneousTrendline;
pub use inverse_fisher_transform::InverseFisherTransform;
pub use inverted_hammer::InvertedHammer;
pub use jma::Jma;
pub use kama::Kama;
pub use keltner::{Keltner, KeltnerOutput};
@@ -275,12 +296,14 @@ pub use ma_envelope::{MaEnvelope, MaEnvelopeOutput};
pub use macd::{MacdIndicator, MacdOutput};
pub use mama::{Mama, MamaOutput};
pub use market_facilitation_index::MarketFacilitationIndex;
pub use marubozu::Marubozu;
pub use mass_index::MassIndex;
pub use mcginley_dynamic::McGinleyDynamic;
pub use median_absolute_deviation::MedianAbsoluteDeviation;
pub use median_price::MedianPrice;
pub use mfi::Mfi;
pub use mom::Mom;
pub use morning_evening_star::MorningEveningStar;
pub use natr::Natr;
pub use nvi::Nvi;
pub use obv::Obv;
@@ -290,6 +313,7 @@ pub use pearson_correlation::PearsonCorrelation;
pub use percent_b::PercentB;
pub use percentage_trailing_stop::PercentageTrailingStop;
pub use pgo::Pgo;
pub use piercing_dark_cloud::PiercingDarkCloud;
pub use pmo::Pmo;
pub use ppo::Ppo;
pub use psar::Psar;
@@ -303,12 +327,14 @@ pub use rsi::Rsi;
pub use rvi::Rvi;
pub use rvi_volatility::RviVolatility;
pub use rwi::{Rwi, RwiOutput};
pub use shooting_star::ShootingStar;
pub use sine_wave::SineWave;
pub use skewness::Skewness;
pub use sma::Sma;
pub use smi::Smi;
pub use smma::Smma;
pub use spearman_correlation::SpearmanCorrelation;
pub use spinning_top::SpinningTop;
pub use standard_error::StandardError;
pub use standard_error_bands::{StandardErrorBands, StandardErrorBandsOutput};
pub use starc_bands::{StarcBands, StarcBandsOutput};
@@ -333,6 +359,9 @@ pub use td_risk_level::{TdRiskLevel, TdRiskLevelOutput};
pub use td_sequential::{TdSequential, TdSequentialOutput};
pub use td_setup::TdSetup;
pub use tema::Tema;
pub use three_inside::ThreeInside;
pub use three_outside::ThreeOutside;
pub use three_soldiers_or_crows::ThreeSoldiersOrCrows;
pub use tii::Tii;
pub use trima::Trima;
pub use trix::Trix;
@@ -340,6 +369,7 @@ pub use true_range::TrueRange;
pub use tsi::Tsi;
pub use tsv::Tsv;
pub use ttm_squeeze::{TtmSqueeze, TtmSqueezeOutput};
pub use tweezer::Tweezer;
pub use typical_price::TypicalPrice;
pub use ulcer_index::UlcerIndex;
pub use ultimate_oscillator::UltimateOscillator;