feat(family-13): add Ichimoku + Heikin-Ashi (#50)

Two new indicators in a brand-new "Ichimoku & alternative charts"
family:

- `Ichimoku` (Ichimoku Kinko Hyo): the full five-line cloud system
  (Tenkan-sen, Kijun-sen, Senkou Span A/B, Chikou Span). Classic
  (9, 26, 52, 26) defaults; configurable. Forward displacement is
  handled in an O(1) ring buffer so the visible Senkou A/B at bar n
  are the values computed at bar n-displacement.
- `HeikinAshi`: recursive candle smoothing transform emitting a
  four-field synthetic candle. Seeds ha_open from (open+close)/2 on
  the first bar.

Touchpoints: core + unit tests, mod.rs/lib.rs re-exports, Python +
Node + WASM bindings (multi-output via PyArray2 / interleaved Vec<f64>
/ Object+Float64Array), Python tests across smoke/new-indicators/
input-validation, Node parity tests, fuzz target (Candle), benches,
README family table + counter (71 -> 73, 8 -> 9 families), CHANGELOG.

Note: Renko, Kagi, and Point & Figure from the family-13 ideas list
are intentionally skipped. They are bar generators (the bar boundary
is defined by price moves, not by a fixed time interval) rather than
indicators that consume a candle stream, and belong in wickra-data
as candle/tick transforms alongside the existing tick-to-candle
aggregator and resampler.
This commit is contained in:
kingchenc
2026-05-25 23:02:29 +02:00
committed by GitHub
parent b971e671b4
commit 5aa0949bce
17 changed files with 1423 additions and 27 deletions
+30 -11
View File
@@ -25,17 +25,18 @@ use libfuzzer_sys::fuzz_target;
use wickra_core::{
AccelerationBands, AcceleratorOscillator, AdOscillator, Adl, Adx, Adxr, Alligator,
AnchoredVwap, Aroon, AroonOscillator, Atr, AtrBands, AtrTrailingStop, AwesomeOscillator,
AwesomeOscillatorHistogram, BalanceOfPower, BatchExt, Camarilla, Candle, Cci, ChaikinMoneyFlow,
ChaikinOscillator, ChaikinVolatility, ChandeKrollStop, ChandelierExit, ChoppinessIndex,
ClassicPivots, DemandIndex, DemarkPivots, Donchian, DonchianStop, EaseOfMovement, Evwma,
FibonacciPivots, ForceIndex, FractalChaosBands, GarmanKlassVolatility, HiLoActivator,
HurstChannel, Indicator, Inertia, Keltner, Kvo, MarketFacilitationIndex, MassIndex, MedianPrice,
Mfi, Natr, Nvi, Obv, ParkinsonVolatility, Pgo, Psar, Pvi, RogersSatchellVolatility, RollingVwap,
Rvi, Rwi, Smi, StarcBands, Stochastic, SuperTrend, TdCombo, TdCountdown, TdDeMarker,
TdDifferential, TdLines, TdOpen, TdPressure, TdRangeProjection, TdRei, TdRiskLevel,
TdSequential, TdSetup, TrueRange, Tsv, TtmSqueeze, TypicalPrice, UltimateOscillator, VoltyStop,
VolumeOscillator, VolumePriceTrend, Vortex, Vwap, VwapStdDevBands, Vwma, Vzo, WaveTrend,
WeightedClose, WilliamsFractals, WilliamsR, WoodiePivots, YangZhangVolatility, YoyoExit, ZigZag,
AwesomeOscillatorHistogram, BalanceOfPower, BatchExt, Camarilla, Candle, Cci,
ChaikinMoneyFlow, ChaikinOscillator, ChaikinVolatility, ChandeKrollStop, ChandelierExit,
ChoppinessIndex, ClassicPivots, DemandIndex, DemarkPivots, Donchian, DonchianStop,
EaseOfMovement, Evwma, FibonacciPivots, ForceIndex, FractalChaosBands,
GarmanKlassVolatility, HeikinAshi, HiLoActivator, HurstChannel, Ichimoku, Indicator,
Inertia, Keltner, Kvo, MarketFacilitationIndex, MassIndex, MedianPrice, Mfi, Natr, Nvi,
Obv, ParkinsonVolatility, Pgo, Psar, Pvi, RogersSatchellVolatility, RollingVwap, Rvi, Rwi,
Smi, StarcBands, Stochastic, SuperTrend, TdCombo, TdCountdown, TdDeMarker, TdDifferential,
TdLines, TdOpen, TdPressure, TdRangeProjection, TdRei, TdRiskLevel, TdSequential, TdSetup,
TrueRange, Tsv, TtmSqueeze, TypicalPrice, UltimateOscillator, VoltyStop, VolumeOscillator,
VolumePriceTrend, Vortex, Vwap, VwapStdDevBands, Vwma, Vzo, WaveTrend, WeightedClose,
WilliamsFractals, WilliamsR, WoodiePivots, YangZhangVolatility, YoyoExit, ZigZag,
};
/// Convert a flat `f64` stream into a `Vec<Candle>` by chunking it into
@@ -165,6 +166,24 @@ fuzz_target!(|data: Vec<f64>| {
let _ = Stochastic::new(14, 3).unwrap().batch(&candles);
}
// --- Ichimoku (5 lines, hand-rolled because of multi-Option output) ---
{
let mut ichi = Ichimoku::classic();
for c in &candles {
let _ = ichi.update(*c);
}
let _ = Ichimoku::classic().batch(&candles);
}
// --- Heikin-Ashi (4-field candle transform) ---
{
let mut ha = HeikinAshi::new();
for c in &candles {
let _ = ha.update(*c);
}
let _ = HeikinAshi::new().batch(&candles);
}
// --- DeMark family ---
drive(|| TdSetup::new(4, 9).unwrap(), &candles);
drive(|| TdDeMarker::new(14).unwrap(), &candles);