F1: wire SMMA and TRIMA through every binding and the wiki
Completes the F1 family (Simple & Weighted MAs). The Rust core for both SMMA (Wilder's RMA) and TRIMA (triangular MA) already landed; this adds the remaining Definition-of-Done steps: - Python: PySmma / PyTrima PyO3 classes + module registration + .pyi stubs. - Node: SmmaNode / TrimaNode via the scalar-indicator macro; index.d.ts and index.js updated for the two new classes. - WASM: WasmSmma / WasmTrima via the scalar-indicator macro. - Wiki: Indicator-Smma.md and Indicator-Trima.md (full pages) plus rows in Indicators-Overview.md and entries in Home.md. cargo fmt + clippy (core/wickra/data/wasm/node) clean; 208 core tests, 25 data tests and 31 doctests green.
This commit is contained in:
@@ -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, MACD, BollingerBands, ATR, Stochastic, OBV, ADX, CCI, WilliamsR, MFI, PSAR, Keltner, Donchian, VWAP, AwesomeOscillator, Aroon, KAMA } = nativeBinding
|
||||
const { version, SMA, EMA, WMA, RSI, DEMA, TEMA, HMA, ROC, TRIX, SMMA, TRIMA, MACD, BollingerBands, ATR, Stochastic, OBV, ADX, CCI, WilliamsR, MFI, PSAR, Keltner, Donchian, VWAP, AwesomeOscillator, Aroon, KAMA } = nativeBinding
|
||||
|
||||
module.exports.version = version
|
||||
module.exports.SMA = SMA
|
||||
@@ -322,6 +322,8 @@ module.exports.TEMA = TEMA
|
||||
module.exports.HMA = HMA
|
||||
module.exports.ROC = ROC
|
||||
module.exports.TRIX = TRIX
|
||||
module.exports.SMMA = SMMA
|
||||
module.exports.TRIMA = TRIMA
|
||||
module.exports.MACD = MACD
|
||||
module.exports.BollingerBands = BollingerBands
|
||||
module.exports.ATR = ATR
|
||||
|
||||
@@ -102,6 +102,8 @@ node_scalar_indicator!(TemaNode, "TEMA", wc::Tema);
|
||||
node_scalar_indicator!(HmaNode, "HMA", wc::Hma);
|
||||
node_scalar_indicator!(RocNode, "ROC", wc::Roc);
|
||||
node_scalar_indicator!(TrixNode, "TRIX", wc::Trix);
|
||||
node_scalar_indicator!(SmmaNode, "SMMA", wc::Smma);
|
||||
node_scalar_indicator!(TrimaNode, "TRIMA", wc::Trima);
|
||||
|
||||
// ============================== MACD ==============================
|
||||
|
||||
|
||||
@@ -52,6 +52,30 @@ class WMA:
|
||||
@property
|
||||
def value(self) -> Optional[float]: ...
|
||||
|
||||
class SMMA:
|
||||
def __init__(self, period: int) -> None: ...
|
||||
def update(self, value: float) -> Optional[float]: ...
|
||||
def batch(self, prices: NDArray[np.float64]) -> NDArray[np.float64]: ...
|
||||
def reset(self) -> None: ...
|
||||
def is_ready(self) -> bool: ...
|
||||
def warmup_period(self) -> int: ...
|
||||
@property
|
||||
def period(self) -> int: ...
|
||||
@property
|
||||
def value(self) -> Optional[float]: ...
|
||||
|
||||
class TRIMA:
|
||||
def __init__(self, period: int) -> None: ...
|
||||
def update(self, value: float) -> Optional[float]: ...
|
||||
def batch(self, prices: NDArray[np.float64]) -> NDArray[np.float64]: ...
|
||||
def reset(self) -> None: ...
|
||||
def is_ready(self) -> bool: ...
|
||||
def warmup_period(self) -> int: ...
|
||||
@property
|
||||
def period(self) -> int: ...
|
||||
@property
|
||||
def value(self) -> Optional[float]: ...
|
||||
|
||||
class RSI:
|
||||
def __init__(self, period: int = 14) -> None: ...
|
||||
def update(self, value: float) -> Optional[float]: ...
|
||||
|
||||
@@ -1519,6 +1519,108 @@ impl PyAroon {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== SMMA ==============================
|
||||
|
||||
#[pyclass(name = "SMMA", module = "wickra._wickra")]
|
||||
#[derive(Clone)]
|
||||
struct PySmma {
|
||||
inner: wc::Smma,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PySmma {
|
||||
#[new]
|
||||
fn new(period: usize) -> PyResult<Self> {
|
||||
Ok(Self {
|
||||
inner: wc::Smma::new(period).map_err(map_err)?,
|
||||
})
|
||||
}
|
||||
fn update(&mut self, value: f64) -> Option<f64> {
|
||||
self.inner.update(value)
|
||||
}
|
||||
fn batch<'py>(
|
||||
&mut self,
|
||||
py: Python<'py>,
|
||||
prices: PyReadonlyArray1<'py, f64>,
|
||||
) -> PyResult<Bound<'py, PyArray1<f64>>> {
|
||||
let slice = prices
|
||||
.as_slice()
|
||||
.map_err(|_| PyValueError::new_err(NON_CONTIGUOUS))?;
|
||||
Ok(flatten(self.inner.batch(slice)).into_pyarray_bound(py))
|
||||
}
|
||||
#[getter]
|
||||
fn period(&self) -> usize {
|
||||
self.inner.period()
|
||||
}
|
||||
#[getter]
|
||||
fn value(&self) -> Option<f64> {
|
||||
self.inner.value()
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
self.inner.reset();
|
||||
}
|
||||
fn is_ready(&self) -> bool {
|
||||
self.inner.is_ready()
|
||||
}
|
||||
fn warmup_period(&self) -> usize {
|
||||
self.inner.warmup_period()
|
||||
}
|
||||
fn __repr__(&self) -> String {
|
||||
format!("SMMA(period={})", self.inner.period())
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== TRIMA ==============================
|
||||
|
||||
#[pyclass(name = "TRIMA", module = "wickra._wickra")]
|
||||
#[derive(Clone)]
|
||||
struct PyTrima {
|
||||
inner: wc::Trima,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyTrima {
|
||||
#[new]
|
||||
fn new(period: usize) -> PyResult<Self> {
|
||||
Ok(Self {
|
||||
inner: wc::Trima::new(period).map_err(map_err)?,
|
||||
})
|
||||
}
|
||||
fn update(&mut self, value: f64) -> Option<f64> {
|
||||
self.inner.update(value)
|
||||
}
|
||||
fn batch<'py>(
|
||||
&mut self,
|
||||
py: Python<'py>,
|
||||
prices: PyReadonlyArray1<'py, f64>,
|
||||
) -> PyResult<Bound<'py, PyArray1<f64>>> {
|
||||
let slice = prices
|
||||
.as_slice()
|
||||
.map_err(|_| PyValueError::new_err(NON_CONTIGUOUS))?;
|
||||
Ok(flatten(self.inner.batch(slice)).into_pyarray_bound(py))
|
||||
}
|
||||
#[getter]
|
||||
fn period(&self) -> usize {
|
||||
self.inner.period()
|
||||
}
|
||||
#[getter]
|
||||
fn value(&self) -> Option<f64> {
|
||||
self.inner.value()
|
||||
}
|
||||
fn reset(&mut self) {
|
||||
self.inner.reset();
|
||||
}
|
||||
fn is_ready(&self) -> bool {
|
||||
self.inner.is_ready()
|
||||
}
|
||||
fn warmup_period(&self) -> usize {
|
||||
self.inner.warmup_period()
|
||||
}
|
||||
fn __repr__(&self) -> String {
|
||||
format!("TRIMA(period={})", self.inner.period())
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== Module ==============================
|
||||
|
||||
#[pymodule]
|
||||
@@ -1549,5 +1651,7 @@ fn _wickra(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_class::<PyVwap>()?;
|
||||
m.add_class::<PyAo>()?;
|
||||
m.add_class::<PyAroon>()?;
|
||||
m.add_class::<PySmma>()?;
|
||||
m.add_class::<PyTrima>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ wasm_scalar_indicator!(WasmTema, "TEMA", wc::Tema, period: usize);
|
||||
wasm_scalar_indicator!(WasmHma, "HMA", wc::Hma, period: usize);
|
||||
wasm_scalar_indicator!(WasmRoc, "ROC", wc::Roc, period: usize);
|
||||
wasm_scalar_indicator!(WasmTrix, "TRIX", wc::Trix, period: usize);
|
||||
wasm_scalar_indicator!(WasmSmma, "SMMA", wc::Smma, period: usize);
|
||||
wasm_scalar_indicator!(WasmTrima, "TRIMA", wc::Trima, period: usize);
|
||||
|
||||
// ---------- KAMA (three params) ----------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user