Add B9 Price Statistics deepening (5 indicators) (#197)
Deepens the **Price Statistics** family (B9) with five rolling-statistics indicators (447 -> 452): - **ShannonEntropy** — Shannon entropy of a binned rolling value distribution. - **SampleEntropy** — Richman-Moorman sample entropy (regularity/complexity of a window). - **KendallTau** — Kendall rank correlation (tau-b) over paired observations (pairwise; distinct from Pearson/Spearman). - **JarqueBera** — Jarque-Bera normality test statistic over a rolling window. - **RollingMinMaxScaler** — maps the latest value to 0..1 over a rolling window. All scalar f64 input except KendallTau (pairwise). Multi-arg scalars (Shannon/Sample entropy) use hand-written Python/Node bindings + the variadic wasm macro; KendallTau uses the pair macros. Verified locally: 3668 core lib + 410 doc tests, clippy clean, 527 node tests, 871 pytest, counter 452.
This commit is contained in:
@@ -28,6 +28,10 @@ function num(v) {
|
||||
// --- Scalar indicators: update(value) vs batch(prices) ---
|
||||
|
||||
const scalarFactories = {
|
||||
SAMPLEENT: () => new wickra.SAMPLEENT(20, 2, 0.2),
|
||||
SHANNONENT: () => new wickra.SHANNONENT(20, 8),
|
||||
ROLLINGMINMAX: () => new wickra.ROLLINGMINMAX(20),
|
||||
JARQUEBERA: () => new wickra.JARQUEBERA(20),
|
||||
BipowerVariation: () => new wickra.BipowerVariation(20),
|
||||
VolatilityOfVolatility: () => new wickra.VolatilityOfVolatility(20, 20),
|
||||
Garch11: () => new wickra.Garch11(0.000002, 0.1, 0.88),
|
||||
@@ -629,6 +633,7 @@ const pairFactories = {
|
||||
VarianceRatio: () => new wickra.VarianceRatio(60, 2),
|
||||
GrangerCausality: () => new wickra.GrangerCausality(60, 1),
|
||||
SpreadAr1Coefficient: () => new wickra.SpreadAr1Coefficient(40),
|
||||
KendallTau: () => new wickra.KendallTau(20),
|
||||
};
|
||||
|
||||
for (const [name, make] of Object.entries(pairFactories)) {
|
||||
|
||||
Vendored
+49
@@ -1052,6 +1052,42 @@ export declare class BipowerVariation {
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type JarqueBeraNode = JARQUEBERA
|
||||
export declare class JARQUEBERA {
|
||||
constructor(period: number)
|
||||
update(value: number): number | null
|
||||
batch(prices: Array<number>): Array<number>
|
||||
reset(): void
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type RollingMinMaxScalerNode = ROLLINGMINMAX
|
||||
export declare class ROLLINGMINMAX {
|
||||
constructor(period: number)
|
||||
update(value: number): number | null
|
||||
batch(prices: Array<number>): Array<number>
|
||||
reset(): void
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type ShannonEntropyNode = SHANNONENT
|
||||
export declare class SHANNONENT {
|
||||
constructor(period: number, bins: number)
|
||||
update(value: number): number | null
|
||||
batch(prices: Array<number>): Array<number>
|
||||
reset(): void
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type SampleEntropyNode = SAMPLEENT
|
||||
export declare class SAMPLEENT {
|
||||
constructor(period: number, m: number, rFactor: number)
|
||||
update(value: number): number | null
|
||||
batch(prices: Array<number>): Array<number>
|
||||
reset(): void
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type EwmaVolatilityNode = EwmaVolatility
|
||||
export declare class EwmaVolatility {
|
||||
constructor(lambda: number)
|
||||
@@ -1263,6 +1299,19 @@ export declare class DistanceSsd {
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type KendallTauNode = KendallTau
|
||||
export declare class KendallTau {
|
||||
constructor(period: number)
|
||||
update(x: number, y: number): number | null
|
||||
/**
|
||||
* Batch over two equally-sized arrays. Returns a length-`n` array
|
||||
* with `NaN` for warmup positions.
|
||||
*/
|
||||
batch(x: Array<number>, y: Array<number>): Array<number>
|
||||
reset(): void
|
||||
isReady(): boolean
|
||||
warmupPeriod(): number
|
||||
}
|
||||
export type BetaNeutralSpreadNode = BetaNeutralSpread
|
||||
export declare class BetaNeutralSpread {
|
||||
constructor(period: number)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -225,6 +225,86 @@ node_scalar_indicator!(
|
||||
"BipowerVariation",
|
||||
wc::BipowerVariation
|
||||
);
|
||||
node_scalar_indicator!(JarqueBeraNode, "JARQUEBERA", wc::JarqueBera);
|
||||
node_scalar_indicator!(
|
||||
RollingMinMaxScalerNode,
|
||||
"ROLLINGMINMAX",
|
||||
wc::RollingMinMaxScaler
|
||||
);
|
||||
|
||||
// Shannon Entropy / Sample Entropy: multi-arg scalar ctors, hand-written
|
||||
// (node_scalar_indicator! only generates a single-period constructor).
|
||||
|
||||
#[napi(js_name = "SHANNONENT")]
|
||||
pub struct ShannonEntropyNode {
|
||||
inner: wc::ShannonEntropy,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl ShannonEntropyNode {
|
||||
#[napi(constructor)]
|
||||
pub fn new(period: u32, bins: u32) -> napi::Result<Self> {
|
||||
Ok(Self {
|
||||
inner: wc::ShannonEntropy::new(period as usize, bins as usize).map_err(map_err)?,
|
||||
})
|
||||
}
|
||||
#[napi]
|
||||
pub fn update(&mut self, value: f64) -> Option<f64> {
|
||||
self.inner.update(value)
|
||||
}
|
||||
#[napi]
|
||||
pub fn batch(&mut self, prices: Vec<f64>) -> Vec<f64> {
|
||||
flatten(self.inner.batch(&prices))
|
||||
}
|
||||
#[napi]
|
||||
pub fn reset(&mut self) {
|
||||
self.inner.reset();
|
||||
}
|
||||
#[napi(js_name = "isReady")]
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.inner.is_ready()
|
||||
}
|
||||
#[napi(js_name = "warmupPeriod")]
|
||||
pub fn warmup_period(&self) -> u32 {
|
||||
self.inner.warmup_period() as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[napi(js_name = "SAMPLEENT")]
|
||||
pub struct SampleEntropyNode {
|
||||
inner: wc::SampleEntropy,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl SampleEntropyNode {
|
||||
#[napi(constructor)]
|
||||
pub fn new(period: u32, m: u32, r_factor: f64) -> napi::Result<Self> {
|
||||
Ok(Self {
|
||||
inner: wc::SampleEntropy::new(period as usize, m as usize, r_factor)
|
||||
.map_err(map_err)?,
|
||||
})
|
||||
}
|
||||
#[napi]
|
||||
pub fn update(&mut self, value: f64) -> Option<f64> {
|
||||
self.inner.update(value)
|
||||
}
|
||||
#[napi]
|
||||
pub fn batch(&mut self, prices: Vec<f64>) -> Vec<f64> {
|
||||
flatten(self.inner.batch(&prices))
|
||||
}
|
||||
#[napi]
|
||||
pub fn reset(&mut self) {
|
||||
self.inner.reset();
|
||||
}
|
||||
#[napi(js_name = "isReady")]
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.inner.is_ready()
|
||||
}
|
||||
#[napi(js_name = "warmupPeriod")]
|
||||
pub fn warmup_period(&self) -> u32 {
|
||||
self.inner.warmup_period() as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[napi(js_name = "EwmaVolatility")]
|
||||
pub struct EwmaVolatilityNode {
|
||||
@@ -675,6 +755,7 @@ node_pair_indicator!(
|
||||
node_pair_indicator!(OuHalfLifeNode, "OuHalfLife", wc::OuHalfLife);
|
||||
node_pair_indicator!(SpreadHurstNode, "SpreadHurst", wc::SpreadHurst);
|
||||
node_pair_indicator!(DistanceSsdNode, "DistanceSsd", wc::DistanceSsd);
|
||||
node_pair_indicator!(KendallTauNode, "KendallTau", wc::KendallTau);
|
||||
node_pair_indicator!(
|
||||
BetaNeutralSpreadNode,
|
||||
"BetaNeutralSpread",
|
||||
|
||||
Reference in New Issue
Block a user