feat: TA-Lib candlestick patterns — Doji family (part 3 of 9) (#134)

* feat: add Doji-family candlestick patterns

Five single-/two-bar Doji patterns, all `Input = Candle`, `Output = f64`:

- Doji Star (CDLDOJISTAR) — a long body followed by a doji gapping away in the
  trend direction; bullish +1 (after a black bar), bearish -1 (after a white bar).
- Dragonfly Doji (CDLDRAGONFLYDOJI) — a doji opening and closing at the high with
  a long lower shadow; bullish +1.
- Gravestone Doji (CDLGRAVESTONEDOJI) — a doji opening and closing at the low with
  a long upper shadow; bearish -1.
- Long-Legged Doji (CDLLONGLEGGEDDOJI) — a doji with long shadows on both sides; a
  non-directional indecision flag, +1 on detection.
- Rickshaw Man (CDLRICKSHAWMAN) — a long-legged doji with the body centred in the
  range; a non-directional indecision flag, +1 on detection.

Counter 254 -> 259 (mod-count == lib counted block; FAMILIES total 249 -> 254).

* chore: sync indicator count to 259

---------

Co-authored-by: wickra-bot <wickra-bot@users.noreply.github.com>
This commit is contained in:
kingchenc
2026-06-02 16:45:08 +02:00
committed by GitHub
co-authored by wickra-bot
parent 03ceac1f3b
commit 244d754707
19 changed files with 1051 additions and 39 deletions
@@ -245,6 +245,11 @@ const candleScalar = {
BeltHold: { make: () => new wickra.BeltHold(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
Breakaway: { make: () => new wickra.Breakaway(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
Counterattack: { make: () => new wickra.Counterattack(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
DojiStar: { make: () => new wickra.DojiStar(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
DragonflyDoji: { make: () => new wickra.DragonflyDoji(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
GravestoneDoji: { make: () => new wickra.GravestoneDoji(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
LongLeggedDoji: { make: () => new wickra.LongLeggedDoji(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
RickshawMan: { make: () => new wickra.RickshawMan(), step: (ind, i) => ind.update(open[i], high[i], low[i], close[i]), batch: (ind) => ind.batch(open, high, low, close) },
};
for (const [name, d] of Object.entries(candleScalar)) {
+45
View File
@@ -2300,6 +2300,51 @@ export declare class Counterattack {
isReady(): boolean
warmupPeriod(): number
}
export type DojiStarNode = DojiStar
export declare class DojiStar {
constructor()
update(open: number, high: number, low: number, close: number): number | null
batch(open: Array<number>, high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type DragonflyDojiNode = DragonflyDoji
export declare class DragonflyDoji {
constructor()
update(open: number, high: number, low: number, close: number): number | null
batch(open: Array<number>, high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type GravestoneDojiNode = GravestoneDoji
export declare class GravestoneDoji {
constructor()
update(open: number, high: number, low: number, close: number): number | null
batch(open: Array<number>, high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type LongLeggedDojiNode = LongLeggedDoji
export declare class LongLeggedDoji {
constructor()
update(open: number, high: number, low: number, close: number): number | null
batch(open: Array<number>, high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type RickshawManNode = RickshawMan
export declare class RickshawMan {
constructor()
update(open: number, high: number, low: number, close: number): number | null
batch(open: Array<number>, high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type OrderBookImbalanceTop1Node = OrderBookImbalanceTop1
export declare class OrderBookImbalanceTop1 {
constructor()
+6 -1
View File
@@ -310,7 +310,7 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { version, SMA, EMA, WMA, RSI, DEMA, TEMA, HMA, ROC, TRIX, SMMA, TRIMA, ZLEMA, MOM, CMO, DPO, StdDev, UlcerIndex, VerticalHorizontalFilter, ZScore, McGinleyDynamic, FRAMA, SuperSmoother, FisherTransform, Decycler, CenterOfGravity, CyberneticCycle, InstantaneousTrendline, EhlersStochastic, RVIVolatility, Variance, CoefficientOfVariation, Skewness, Kurtosis, StandardError, DetrendedStdDev, RSquared, MedianAbsoluteDeviation, Autocorrelation, HurstExponent, PearsonCorrelation, Beta, PairwiseBeta, SpearmanCorrelation, PairSpreadZScore, LeadLagCrossCorrelation, Cointegration, RelativeStrengthAB, MACD, BollingerBands, ATR, Stochastic, OBV, ADX, ADXR, CCI, WilliamsR, MFI, PSAR, Keltner, Donchian, VWAP, RollingVWAP, AwesomeOscillator, Aroon, Inertia, ConnorsRSI, LaguerreRSI, SMI, KST, PGO, RVI, AwesomeOscillatorHistogram, STC, ElderImpulse, ZeroLagMACD, CFO, APO, KAMA, EVWMA, Alligator, JMA, VIDYA, ALMA, T3, TSI, PMO, TII, ADL, VolumePriceTrend, ChaikinMoneyFlow, ChaikinOscillator, ForceIndex, NVI, PVI, VolumeOscillator, KVO, WilliamsAD, AnchoredVWAP, DemandIndex, TSV, VZO, MarketFacilitationIndex, EaseOfMovement, SuperTrend, ChandelierExit, ChandeKrollStop, AtrTrailingStop, HiLoActivator, VoltyStop, YoyoExit, DonchianStop, PercentageTrailingStop, StepTrailingStop, RenkoTrailingStop, TypicalPrice, MedianPrice, WeightedClose, LinearRegression, LinRegSlope, AcceleratorOscillator, BalanceOfPower, ChoppinessIndex, TrueRange, ChaikinVolatility, YangZhangVolatility, RogersSatchellVolatility, GarmanKlassVolatility, ParkinsonVolatility, LinRegAngle, BollingerBandwidth, PercentB, NATR, HistoricalVolatility, AroonOscillator, WaveTrend, RWI, Vortex, MassIndex, StochRSI, UltimateOscillator, PPO, Coppock, VWMA, MaEnvelope, AccelerationBands, StarcBands, AtrBands, HurstChannel, LinRegChannel, StandardErrorBands, DoubleBollinger, TtmSqueeze, FractalChaosBands, VwapStdDevBands, ClassicPivots, FibonacciPivots, Camarilla, WoodiePivots, DemarkPivots, WilliamsFractals, ZigZag, TDSetup, TDSequential, TDDeMarker, TDREI, TDPressure, TDCombo, TDCountdown, TDLines, TDRangeProjection, TDDifferential, TDOpen, TDRiskLevel, InverseFisherTransform, DecyclerOscillator, RoofingFilter, EmpiricalModeDecomposition, HilbertDominantCycle, AdaptiveCycle, SineWave, MAMA, FAMA, Ichimoku, HeikinAshi, ValueArea, InitialBalance, OpeningRange, Doji, Hammer, InvertedHammer, HangingMan, ShootingStar, Engulfing, Harami, MorningEveningStar, ThreeSoldiersOrCrows, PiercingDarkCloud, Marubozu, Tweezer, SpinningTop, ThreeInside, ThreeOutside, TwoCrows, UpsideGapTwoCrows, IdenticalThreeCrows, ThreeLineStrike, ThreeStarsInSouth, AbandonedBaby, AdvanceBlock, BeltHold, Breakaway, Counterattack, OrderBookImbalanceTop1, OrderBookImbalanceFull, Microprice, QuotedSpread, DepthSlope, OrderBookImbalanceTopN, SignedVolume, CumulativeVolumeDelta, TradeImbalance, EffectiveSpread, RealizedSpread, KylesLambda, Footprint, FundingRate, FundingRateMean, FundingRateZScore, FundingBasis, OpenInterestDelta, OIPriceDivergence, OIWeighted, LongShortRatio, TakerBuySellRatio, LiquidationFeatures, TermStructureBasis, CalendarSpread, SharpeRatio, SortinoRatio, CalmarRatio, OmegaRatio, MaxDrawdown, AverageDrawdown, DrawdownDuration, PainIndex, ValueAtRisk, ConditionalValueAtRisk, ProfitFactor, GainLossRatio, RecoveryFactor, KellyCriterion, TreynorRatio, InformationRatio, Alpha } = nativeBinding
const { version, SMA, EMA, WMA, RSI, DEMA, TEMA, HMA, ROC, TRIX, SMMA, TRIMA, ZLEMA, MOM, CMO, DPO, StdDev, UlcerIndex, VerticalHorizontalFilter, ZScore, McGinleyDynamic, FRAMA, SuperSmoother, FisherTransform, Decycler, CenterOfGravity, CyberneticCycle, InstantaneousTrendline, EhlersStochastic, RVIVolatility, Variance, CoefficientOfVariation, Skewness, Kurtosis, StandardError, DetrendedStdDev, RSquared, MedianAbsoluteDeviation, Autocorrelation, HurstExponent, PearsonCorrelation, Beta, PairwiseBeta, SpearmanCorrelation, PairSpreadZScore, LeadLagCrossCorrelation, Cointegration, RelativeStrengthAB, MACD, BollingerBands, ATR, Stochastic, OBV, ADX, ADXR, CCI, WilliamsR, MFI, PSAR, Keltner, Donchian, VWAP, RollingVWAP, AwesomeOscillator, Aroon, Inertia, ConnorsRSI, LaguerreRSI, SMI, KST, PGO, RVI, AwesomeOscillatorHistogram, STC, ElderImpulse, ZeroLagMACD, CFO, APO, KAMA, EVWMA, Alligator, JMA, VIDYA, ALMA, T3, TSI, PMO, TII, ADL, VolumePriceTrend, ChaikinMoneyFlow, ChaikinOscillator, ForceIndex, NVI, PVI, VolumeOscillator, KVO, WilliamsAD, AnchoredVWAP, DemandIndex, TSV, VZO, MarketFacilitationIndex, EaseOfMovement, SuperTrend, ChandelierExit, ChandeKrollStop, AtrTrailingStop, HiLoActivator, VoltyStop, YoyoExit, DonchianStop, PercentageTrailingStop, StepTrailingStop, RenkoTrailingStop, TypicalPrice, MedianPrice, WeightedClose, LinearRegression, LinRegSlope, AcceleratorOscillator, BalanceOfPower, ChoppinessIndex, TrueRange, ChaikinVolatility, YangZhangVolatility, RogersSatchellVolatility, GarmanKlassVolatility, ParkinsonVolatility, LinRegAngle, BollingerBandwidth, PercentB, NATR, HistoricalVolatility, AroonOscillator, WaveTrend, RWI, Vortex, MassIndex, StochRSI, UltimateOscillator, PPO, Coppock, VWMA, MaEnvelope, AccelerationBands, StarcBands, AtrBands, HurstChannel, LinRegChannel, StandardErrorBands, DoubleBollinger, TtmSqueeze, FractalChaosBands, VwapStdDevBands, ClassicPivots, FibonacciPivots, Camarilla, WoodiePivots, DemarkPivots, WilliamsFractals, ZigZag, TDSetup, TDSequential, TDDeMarker, TDREI, TDPressure, TDCombo, TDCountdown, TDLines, TDRangeProjection, TDDifferential, TDOpen, TDRiskLevel, InverseFisherTransform, DecyclerOscillator, RoofingFilter, EmpiricalModeDecomposition, HilbertDominantCycle, AdaptiveCycle, SineWave, MAMA, FAMA, Ichimoku, HeikinAshi, ValueArea, InitialBalance, OpeningRange, Doji, Hammer, InvertedHammer, HangingMan, ShootingStar, Engulfing, Harami, MorningEveningStar, ThreeSoldiersOrCrows, PiercingDarkCloud, Marubozu, Tweezer, SpinningTop, ThreeInside, ThreeOutside, TwoCrows, UpsideGapTwoCrows, IdenticalThreeCrows, ThreeLineStrike, ThreeStarsInSouth, AbandonedBaby, AdvanceBlock, BeltHold, Breakaway, Counterattack, DojiStar, DragonflyDoji, GravestoneDoji, LongLeggedDoji, RickshawMan, OrderBookImbalanceTop1, OrderBookImbalanceFull, Microprice, QuotedSpread, DepthSlope, OrderBookImbalanceTopN, SignedVolume, CumulativeVolumeDelta, TradeImbalance, EffectiveSpread, RealizedSpread, KylesLambda, Footprint, FundingRate, FundingRateMean, FundingRateZScore, FundingBasis, OpenInterestDelta, OIPriceDivergence, OIWeighted, LongShortRatio, TakerBuySellRatio, LiquidationFeatures, TermStructureBasis, CalendarSpread, SharpeRatio, SortinoRatio, CalmarRatio, OmegaRatio, MaxDrawdown, AverageDrawdown, DrawdownDuration, PainIndex, ValueAtRisk, ConditionalValueAtRisk, ProfitFactor, GainLossRatio, RecoveryFactor, KellyCriterion, TreynorRatio, InformationRatio, Alpha } = nativeBinding
module.exports.version = version
module.exports.SMA = SMA
@@ -525,6 +525,11 @@ module.exports.AdvanceBlock = AdvanceBlock
module.exports.BeltHold = BeltHold
module.exports.Breakaway = Breakaway
module.exports.Counterattack = Counterattack
module.exports.DojiStar = DojiStar
module.exports.DragonflyDoji = DragonflyDoji
module.exports.GravestoneDoji = GravestoneDoji
module.exports.LongLeggedDoji = LongLeggedDoji
module.exports.RickshawMan = RickshawMan
module.exports.OrderBookImbalanceTop1 = OrderBookImbalanceTop1
module.exports.OrderBookImbalanceFull = OrderBookImbalanceFull
module.exports.Microprice = Microprice
+5
View File
@@ -8775,6 +8775,11 @@ node_candle_pattern!(AdvanceBlockNode, wc::AdvanceBlock, "AdvanceBlock");
node_candle_pattern!(BeltHoldNode, wc::BeltHold, "BeltHold");
node_candle_pattern!(BreakawayNode, wc::Breakaway, "Breakaway");
node_candle_pattern!(CounterattackNode, wc::Counterattack, "Counterattack");
node_candle_pattern!(DojiStarNode, wc::DojiStar, "DojiStar");
node_candle_pattern!(DragonflyDojiNode, wc::DragonflyDoji, "DragonflyDoji");
node_candle_pattern!(GravestoneDojiNode, wc::GravestoneDoji, "GravestoneDoji");
node_candle_pattern!(LongLeggedDojiNode, wc::LongLeggedDoji, "LongLeggedDoji");
node_candle_pattern!(RickshawManNode, wc::RickshawMan, "RickshawMan");
// ============================== Microstructure: Order Book ==============================
//
+10
View File
@@ -250,6 +250,11 @@ from ._wickra import (
BeltHold,
Breakaway,
Counterattack,
DojiStar,
DragonflyDoji,
GravestoneDoji,
LongLeggedDoji,
RickshawMan,
# Microstructure: order book
OrderBookImbalanceTop1,
OrderBookImbalanceTopN,
@@ -527,6 +532,11 @@ __all__ = [
"BeltHold",
"Breakaway",
"Counterattack",
"DojiStar",
"DragonflyDoji",
"GravestoneDoji",
"LongLeggedDoji",
"RickshawMan",
# Microstructure: order book
"OrderBookImbalanceTop1",
"OrderBookImbalanceTopN",
+10
View File
@@ -11638,6 +11638,11 @@ candle_pattern_no_param!(PyAdvanceBlock, wc::AdvanceBlock, "AdvanceBlock");
candle_pattern_no_param!(PyBeltHold, wc::BeltHold, "BeltHold");
candle_pattern_no_param!(PyBreakaway, wc::Breakaway, "Breakaway");
candle_pattern_no_param!(PyCounterattack, wc::Counterattack, "Counterattack");
candle_pattern_no_param!(PyDojiStar, wc::DojiStar, "DojiStar");
candle_pattern_no_param!(PyDragonflyDoji, wc::DragonflyDoji, "DragonflyDoji");
candle_pattern_no_param!(PyGravestoneDoji, wc::GravestoneDoji, "GravestoneDoji");
candle_pattern_no_param!(PyLongLeggedDoji, wc::LongLeggedDoji, "LongLeggedDoji");
candle_pattern_no_param!(PyRickshawMan, wc::RickshawMan, "RickshawMan");
// ============================== Microstructure: Order Book ==============================
//
// Order-book indicators consume a depth snapshot rather than OHLCV. Streaming
@@ -14144,6 +14149,11 @@ fn _wickra(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyBeltHold>()?;
m.add_class::<PyBreakaway>()?;
m.add_class::<PyCounterattack>()?;
m.add_class::<PyDojiStar>()?;
m.add_class::<PyDragonflyDoji>()?;
m.add_class::<PyGravestoneDoji>()?;
m.add_class::<PyLongLeggedDoji>()?;
m.add_class::<PyRickshawMan>()?;
// Microstructure: order book.
m.add_class::<PyOrderBookImbalanceTop1>()?;
m.add_class::<PyOrderBookImbalanceTopN>()?;
@@ -563,6 +563,26 @@ CANDLE_SCALAR = {
lambda: ta.Counterattack(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"DojiStar": (
lambda: ta.DojiStar(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"DragonflyDoji": (
lambda: ta.DragonflyDoji(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"GravestoneDoji": (
lambda: ta.GravestoneDoji(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"LongLeggedDoji": (
lambda: ta.LongLeggedDoji(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
"RickshawMan": (
lambda: ta.RickshawMan(),
lambda ind, h, l, c, v: ind.batch(c, h, l, c),
),
}
@@ -1685,6 +1705,32 @@ def test_counterattack_reference():
assert t.update((20.0, 20.1, 14.9, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((10.0, 15.1, 9.9, 15.0, 1.0, 1)) == pytest.approx(1.0)
def test_doji_star_reference():
t = ta.DojiStar()
assert t.update((20.0, 20.2, 14.8, 15.0, 1.0, 0)) == pytest.approx(0.0)
assert t.update((13.0, 13.1, 12.9, 13.0, 1.0, 1)) == pytest.approx(1.0)
def test_dragonfly_doji_reference():
t = ta.DragonflyDoji()
assert t.update((10.0, 10.05, 6.0, 10.0, 1.0, 0)) == pytest.approx(1.0)
def test_gravestone_doji_reference():
t = ta.GravestoneDoji()
assert t.update((10.0, 14.0, 9.95, 10.0, 1.0, 0)) == pytest.approx(-1.0)
def test_long_legged_doji_reference():
t = ta.LongLeggedDoji()
assert t.update((10.0, 12.0, 8.0, 10.05, 1.0, 0)) == pytest.approx(1.0)
def test_rickshaw_man_reference():
t = ta.RickshawMan()
assert t.update((10.0, 12.0, 8.0, 10.0, 1.0, 0)) == pytest.approx(1.0)
# --- Lifecycle ------------------------------------------------------------
+5
View File
@@ -6352,6 +6352,11 @@ wasm_candle_pattern!(WasmAdvanceBlock, wc::AdvanceBlock, AdvanceBlock);
wasm_candle_pattern!(WasmBeltHold, wc::BeltHold, BeltHold);
wasm_candle_pattern!(WasmBreakaway, wc::Breakaway, Breakaway);
wasm_candle_pattern!(WasmCounterattack, wc::Counterattack, Counterattack);
wasm_candle_pattern!(WasmDojiStar, wc::DojiStar, DojiStar);
wasm_candle_pattern!(WasmDragonflyDoji, wc::DragonflyDoji, DragonflyDoji);
wasm_candle_pattern!(WasmGravestoneDoji, wc::GravestoneDoji, GravestoneDoji);
wasm_candle_pattern!(WasmLongLeggedDoji, wc::LongLeggedDoji, LongLeggedDoji);
wasm_candle_pattern!(WasmRickshawMan, wc::RickshawMan, RickshawMan);
// ============================== Microstructure: Order Book ==============================
//