feat(indicators): add B6 Bands & Channels family (429 -> 434) (#191)

Adds the **B6 Bands & Channels** batch — five band/channel indicators, taking the catalogue from 429 to 434.

| Indicator | Input → Output | Summary |
|-----------|----------------|---------|
| `ProjectionBands` | `Candle` → `{upper,middle,lower}` | Widner forward-projected high/low regression envelope |
| `ProjectionOscillator` | `Candle` → `f64` | Close position inside the projection bands, scaled 0..100 |
| `QuartileBands` | `f64` → `{upper,middle,lower}` | Rolling 25th/50th/75th-percentile (Q1/median/Q3) envelope |
| `BomarBands` | `f64` → `{upper,middle,lower}` | Adaptive percentage bands containing a target coverage fraction of recent closes |
| `MedianChannel` | `f64` → `{upper,middle,lower}` | Robust median ± multiplier·MAD envelope |

All five are distinct from existing indicators (verified against the core: `LinRegChannel`, `StandardErrorBands`, `Donchian`, `RollingQuantile`, `HurstChannel`). SKIPped from the roadmap: Price Channel (= `Donchian`) and Moving-Average Channel (≈ `MaEnvelope`/`Keltner`).

Each ships:
- Core indicator with per-branch unit tests (Codecov-strict 100%).
- python / node / wasm bindings (struct outputs are hand-written; `ProjectionOscillator` uses the generated candle→f64 path).
- Fuzz drives, python (`MULTI`/`SCALAR_MULTI`/`CANDLE_SCALAR`) + node test registries, README + CHANGELOG counter bump to 434.

Verified locally: `cargo fmt`, `clippy --workspace --all-targets --all-features -D warnings` (clean), `wickra-core` 3511 lib + 392 doc tests, node 509 tests, pytest 840.
This commit is contained in:
kingchenc
2026-06-07 00:03:02 +02:00
committed by GitHub
parent 3dfbc415c5
commit 67feec598a
20 changed files with 2174 additions and 46 deletions
+65
View File
@@ -199,6 +199,26 @@ export interface StandardErrorBandsValue {
middle: number
lower: number
}
export interface QuartileBandsValue {
upper: number
middle: number
lower: number
}
export interface BomarBandsValue {
upper: number
middle: number
lower: number
}
export interface MedianChannelValue {
upper: number
middle: number
lower: number
}
export interface ProjectionBandsValue {
upper: number
middle: number
lower: number
}
export interface DoubleBollingerValue {
upperOuter: number
upperInner: number
@@ -1639,6 +1659,15 @@ export declare class VolatilityRatio {
isReady(): boolean
warmupPeriod(): number
}
export type ProjectionOscillatorNode = ProjectionOscillator
export declare class ProjectionOscillator {
constructor(period: number)
update(high: number, low: number, close: number): number | null
batch(high: Array<number>, low: Array<number>, close: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type StochNode = Stochastic
export declare class Stochastic {
constructor(kPeriod: number, dPeriod: number)
@@ -2627,6 +2656,42 @@ export declare class StandardErrorBands {
isReady(): boolean
warmupPeriod(): number
}
export type QuartileBandsNode = QuartileBands
export declare class QuartileBands {
constructor(period: number)
update(value: number): QuartileBandsValue | null
batch(prices: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type BomarBandsNode = BomarBands
export declare class BomarBands {
constructor(period: number, coverage: number)
update(value: number): BomarBandsValue | null
batch(prices: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type MedianChannelNode = MedianChannel
export declare class MedianChannel {
constructor(period: number, multiplier: number)
update(value: number): MedianChannelValue | null
batch(prices: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type ProjectionBandsNode = ProjectionBands
export declare class ProjectionBands {
constructor(period: number)
update(high: number, low: number): ProjectionBandsValue | null
batch(high: Array<number>, low: Array<number>): Array<number>
reset(): void
isReady(): boolean
warmupPeriod(): number
}
export type DoubleBollingerNode = DoubleBollinger
export declare class DoubleBollinger {
constructor(period: number, kInner: number, kOuter: number)