diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af1abf7..2252946 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,9 +102,17 @@ jobs: - run: python -m pip install --upgrade wickra numpy - name: Check Python doc snippets run: python scripts/check_doc_examples.py + # Naming every symbol correctly is not the same as working: twenty-five + # blocks resolved every name and still raised, by calling `update` with the + # whole derivatives tick, feeding a close-only series to an indicator that + # takes high/low/close, or reaching for `.shape` on a type without one. + - name: Run Python doc snippets + run: python scripts/run_doc_snippets.py - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 20 - run: npm install --no-save wickra - name: Check Node.js doc snippets run: node scripts/check-doc-examples.mjs + - name: Run Node.js doc snippets + run: node scripts/run-doc-snippets.mjs diff --git a/Data-Layer.md b/Data-Layer.md index 3258518..941471a 100644 --- a/Data-Layer.md +++ b/Data-Layer.md @@ -120,7 +120,10 @@ let five_min = resample_all(Timeframe::millis(5 * 60_000)?, one_min_candles)?; let mut r = Resampler::new(Timeframe::millis(60 * 60_000)?); // 1-hour bars let one_min_candles: Vec> = Vec::new(); for candle in one_min_candles { - if let Some(closed) = r.push(candle?)? { + // One push can close several bars at once: with gap filling on, a skipped + // bucket still gets a flat placeholder, so this is a list rather than an + // `Option`. + for closed in r.push(candle?)? { // a coarser bar just closed } } diff --git a/FAQ.md b/FAQ.md index d8b8e92..d060195 100644 --- a/FAQ.md +++ b/FAQ.md @@ -87,8 +87,11 @@ that overflows surfaces an error instead of producing a corrupted candle ## How fast is Wickra? -The streaming path is O(1) per `update` — the per-tick cost does not grow with -how much history you have already seen. Against the pure-Python libraries the +The streaming path is O(1) in the input length — the per-tick cost does not +grow with how much history you have already seen. It is bounded by the window +you configure instead: most indicators do constant work, and the ones that need +an order statistic or a full-window pass scale with the period, never with the +series. Against the pure-Python libraries the gap is large: roughly 6–47× faster than `finta` on batch workloads and 11–56× faster per tick than `talipp` (the only incremental Python peer). Against the other Rust TA crates (`kand`, `ta-rs`, `yata`) it is an honest mixed picture — @@ -115,7 +118,8 @@ with the latest market history via ## How is Wickra different from TA-Lib / pandas-ta / talipp? - TA-Lib and pandas-ta are batch-only — every new tick triggers a full - recomputation. Wickra updates in O(1). The numerical results are the + recomputation. Wickra never revisits the history behind the tick. The + numerical results are the same; the speed gap shows up in live trading and large backtests. - talipp is streaming-first like Wickra but Python-only and slower per update. diff --git a/Indicators-Overview.md b/Indicators-Overview.md index 3e2ee33..1748c9b 100644 --- a/Indicators-Overview.md +++ b/Indicators-Overview.md @@ -5,7 +5,7 @@ family collects indicators that answer the same kind of question, so the taxonomy here maps one-to-one onto the `crates/wickra-core/src/indicators/` source layout. -Every indicator is an O(1) state machine that consumes one input at a time +Every indicator is an incremental state machine that consumes one input at a time and produces either `Option` (Rust), `float | None` (Python), or `number | null` (Node). Inputs are either a `f64` close price or an OHLCV `Candle` (Rust) / dict-or-tuple (Python) / column arrays (Node). The full diff --git a/Indicators/Indicator-AbandonedBaby.md b/Indicators/Indicator-AbandonedBaby.md index 354b4e2..90591eb 100644 --- a/Indicators/Indicator-AbandonedBaby.md +++ b/Indicators/Indicator-AbandonedBaby.md @@ -58,7 +58,7 @@ const _: fn(&mut AbandonedBaby, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Abcd.md b/Indicators/Indicator-Abcd.md index 9d1ae04..e5e83b7 100644 --- a/Indicators/Indicator-Abcd.md +++ b/Indicators/Indicator-Abcd.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::Abcd, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-AbsoluteBreadthIndex.md b/Indicators/Indicator-AbsoluteBreadthIndex.md index 01f378c..7db56ba 100644 --- a/Indicators/Indicator-AbsoluteBreadthIndex.md +++ b/Indicators/Indicator-AbsoluteBreadthIndex.md @@ -50,7 +50,7 @@ const _: fn(&mut AbsoluteBreadthIndex, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-AccelerationBands.md b/Indicators/Indicator-AccelerationBands.md index b577767..7c78639 100644 --- a/Indicators/Indicator-AccelerationBands.md +++ b/Indicators/Indicator-AccelerationBands.md @@ -57,7 +57,7 @@ const _: fn(&mut AccelerationBands, Candle) -> Option = - **Python streaming.** `update(candle)` returns `(upper, middle, lower)` or `None`. - **Python batch.** `AccelerationBands.batch(high, low, close)` returns an - `(n, 3)` `np.ndarray` with columns `[upper, middle, lower]`; warmup rows + `(n, 3)` `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(high, low, close)` returns a `{ upper, middle, lower }` object or `null`. diff --git a/Indicators/Indicator-AdOscillator.md b/Indicators/Indicator-AdOscillator.md index a9307bc..89ec390 100644 --- a/Indicators/Indicator-AdOscillator.md +++ b/Indicators/Indicator-AdOscillator.md @@ -56,7 +56,7 @@ const _: fn(&mut AdOscillator, Candle) -> Option = `. Output is integer-valued `f64` (e.g. `7.0`, `12.0`). Python: `AdaptiveCycle().batch(prices)` -returns a 1-D `np.ndarray`. Node: same shape; `update(value)` +returns an `array.array('d')`. Node: same shape; `update(value)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-AdaptiveLaguerreFilter.md b/Indicators/Indicator-AdaptiveLaguerreFilter.md index 97c04d9..abcfc30 100644 --- a/Indicators/Indicator-AdaptiveLaguerreFilter.md +++ b/Indicators/Indicator-AdaptiveLaguerreFilter.md @@ -62,7 +62,7 @@ const _: fn(&mut AdaptiveLaguerreFilter, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-AdvanceBlock.md b/Indicators/Indicator-AdvanceBlock.md index 3926de3..971bb3b 100644 --- a/Indicators/Indicator-AdvanceBlock.md +++ b/Indicators/Indicator-AdvanceBlock.md @@ -50,7 +50,7 @@ const _: fn(&mut AdvanceBlock, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-AdvanceDecline.md b/Indicators/Indicator-AdvanceDecline.md index 43ab165..722a53c 100644 --- a/Indicators/Indicator-AdvanceDecline.md +++ b/Indicators/Indicator-AdvanceDecline.md @@ -57,7 +57,7 @@ four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)` over one universe; `batch(change, volume, new_high, new_low)` takes one such array group per tick - (lists of lists) and returns a 1-D `ndarray`. + (lists of lists) and returns an `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` takes the same arrays nested one level per tick and returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only — the universe is diff --git a/Indicators/Indicator-AdvanceDeclineRatio.md b/Indicators/Indicator-AdvanceDeclineRatio.md index 7c236bc..a709f33 100644 --- a/Indicators/Indicator-AdvanceDeclineRatio.md +++ b/Indicators/Indicator-AdvanceDeclineRatio.md @@ -55,7 +55,7 @@ signed `change`, a `volume`, and `new_high` / `new_low` flags; the ratio reads o `change`). The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` takes one - array group per tick (lists of lists) and returns a 1-D `ndarray`. + array group per tick (lists of lists) and returns an `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` nests the arrays one level per tick and returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only (the universe is ragged diff --git a/Indicators/Indicator-Adxr.md b/Indicators/Indicator-Adxr.md index 977a75c..1e33d77 100644 --- a/Indicators/Indicator-Adxr.md +++ b/Indicators/Indicator-Adxr.md @@ -49,7 +49,7 @@ const _: fn(&mut Adxr, Candle) -> Option = ::update; ``` - **Python.** `update(candle)` returns `float | None`; - `batch(high, low, close)` returns a 1-D `float64` `np.ndarray` with `NaN` + `batch(high, low, close)` returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(high, low, close)` returns `number | null`; `batch(high, low, close)` returns an `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-Alligator.md b/Indicators/Indicator-Alligator.md index 996d445..1c6baab 100644 --- a/Indicators/Indicator-Alligator.md +++ b/Indicators/Indicator-Alligator.md @@ -55,7 +55,7 @@ const _: fn(&mut Alligator, Candle) -> Option = ` of length `3n`, diff --git a/Indicators/Indicator-Alma.md b/Indicators/Indicator-Alma.md index 9feb425..10fb614 100644 --- a/Indicators/Indicator-Alma.md +++ b/Indicators/Indicator-Alma.md @@ -55,7 +55,7 @@ const _: fn(&mut Alma, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +`float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-AmihudIlliquidity.md b/Indicators/Indicator-AmihudIlliquidity.md index 60ad936..d78c34c 100644 --- a/Indicators/Indicator-AmihudIlliquidity.md +++ b/Indicators/Indicator-AmihudIlliquidity.md @@ -48,7 +48,7 @@ const _: fn(&mut AmihudIlliquidity, Trade) -> Option = ``` Node `update(price, size, isBuy)` and `batch(price[], size[], isBuy[])`; Python -`update(price, size, is_buy)` and `batch(price, size, is_buy)` → 1-D `ndarray`. +`update(price, size, is_buy)` and `batch(price, size, is_buy)` → `array.array('d')`. (The aggressor side is accepted for a uniform trade API but does not affect the value.) diff --git a/Indicators/Indicator-AnchoredRsi.md b/Indicators/Indicator-AnchoredRsi.md index 4119797..244188e 100644 --- a/Indicators/Indicator-AnchoredRsi.md +++ b/Indicators/Indicator-AnchoredRsi.md @@ -57,7 +57,7 @@ const _: fn(&mut AnchoredRsi, f64) -> Option = :: ``` Python streams as `float | None`, batches a close column to a 1-D -`numpy.ndarray` (`NaN` for warmup). Node streams as `number | null`, batches as +`array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. ## Warmup diff --git a/Indicators/Indicator-AndrewsPitchfork.md b/Indicators/Indicator-AndrewsPitchfork.md index d10d63a..0db9a48 100644 --- a/Indicators/Indicator-AndrewsPitchfork.md +++ b/Indicators/Indicator-AndrewsPitchfork.md @@ -102,7 +102,7 @@ import wickra as ta p = ta.AndrewsPitchfork(2) base = 100 + np.sin(np.arange(120) * 0.5) * 10 -median, upper, lower = p.batch(base + 1, base - 1).T +median, upper, lower = np.asarray(p.batch(base + 1, base - 1).tolist()).T ``` ### Node diff --git a/Indicators/Indicator-Apo.md b/Indicators/Indicator-Apo.md index 1afb217..4015512 100644 --- a/Indicators/Indicator-Apo.md +++ b/Indicators/Indicator-Apo.md @@ -48,7 +48,7 @@ const _: fn(&mut Apo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. The Python binding maps this -to `float | None` (streaming) or a `float64` `np.ndarray` with `NaN` warmup +to `float | None` (streaming) or an `array.array('d')` with `NaN` warmup rows (batch). The Node binding maps it to `number | null` / `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-Atr.md b/Indicators/Indicator-Atr.md index 87c547b..fd8c50a 100644 --- a/Indicators/Indicator-Atr.md +++ b/Indicators/Indicator-Atr.md @@ -57,7 +57,7 @@ const _: fn(&mut Atr, Candle) -> Option = ::update; `(open, high, low, close, volume, timestamp)` or a dict with keys `open`, `high`, `low`, `close`, `volume`, and optional `timestamp`. - **Python batch.** `ATR.batch(high, low, close)` takes three equal-length - `numpy.ndarray` columns and returns a 1-D `np.ndarray` with `NaN` for + `array.array('d')` columns and returns an `array.array('d')` with `NaN` for every warmup row. - **Node streaming.** `atr.update(high, low, close)` returns `number | null`. - **Node batch.** `atr.batch(high, low, close)` returns `Array` of diff --git a/Indicators/Indicator-AtrBands.md b/Indicators/Indicator-AtrBands.md index 70da8f4..1fb8862 100644 --- a/Indicators/Indicator-AtrBands.md +++ b/Indicators/Indicator-AtrBands.md @@ -52,7 +52,7 @@ const _: fn(&mut AtrBands, Candle) -> Option = ` diff --git a/Indicators/Indicator-AtrRatchet.md b/Indicators/Indicator-AtrRatchet.md index e31203e..f1edc68 100644 --- a/Indicators/Indicator-AtrRatchet.md +++ b/Indicators/Indicator-AtrRatchet.md @@ -108,7 +108,7 @@ import wickra as ta r = ta.AtrRatchet(14, 4.0, 0.1) n = 60 base = np.arange(n, dtype=float) + 100.0 -value, direction = r.batch(base + 2.0, base - 2.0, base + 1.0).T +value, direction = np.asarray(r.batch(base + 2.0, base - 2.0, base + 1.0).tolist()).T print(value[-1], direction[-1]) ``` diff --git a/Indicators/Indicator-AutoFib.md b/Indicators/Indicator-AutoFib.md index 74e96fc..88a53d3 100644 --- a/Indicators/Indicator-AutoFib.md +++ b/Indicators/Indicator-AutoFib.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::AutoFib, wickra::Candle) -> Option Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float | None`; - `batch(open, high, low, close, volume, timestamp)` → 1-D `ndarray` (`NaN` warmup). + `batch(open, high, low, close, volume, timestamp)` → `array.array('d')` (`NaN` warmup). - **Node.** `update(...)` → `number | null`; `batch(...)` → `number[]`. - **WASM.** `update(...)` → `number | undefined`. diff --git a/Indicators/Indicator-AverageDrawdown.md b/Indicators/Indicator-AverageDrawdown.md index 19df0fa..2fd6158 100644 --- a/Indicators/Indicator-AverageDrawdown.md +++ b/Indicators/Indicator-AverageDrawdown.md @@ -57,7 +57,7 @@ const _: fn(&mut AverageDrawdown, f64) -> Option = Option = ::upd `AvgPrice` is a **candle-input** indicator that reads all four OHLC prices. In Python the streaming `update` accepts a candle (dict or tuple); the batch helper takes `open`, `high`, `low`, `close` numpy arrays and returns a 1-D -`numpy.ndarray` (`NaN` only never appears here, since warmup is a single bar). +`array.array('d')` (`NaN` only never appears here, since warmup is a single bar). Node and WASM expose `update(open, high, low, close)` and the matching `batch`. ## Warmup diff --git a/Indicators/Indicator-AwesomeOscillator.md b/Indicators/Indicator-AwesomeOscillator.md index 21f8a80..c9d74ca 100644 --- a/Indicators/Indicator-AwesomeOscillator.md +++ b/Indicators/Indicator-AwesomeOscillator.md @@ -56,7 +56,7 @@ The `close` and `volume` fields on the input candle are ignored — only `high` and `low` matter, via `Candle::median_price()`. Python's `AwesomeOscillator.batch(high, low)` returns a 1-D `float64` -`np.ndarray`. Node's `AwesomeOscillator.batch(high, low)` returns a +`array.array('d')`. Node's `AwesomeOscillator.batch(high, low)` returns a flat `number[]`. Both produce `NaN` during warmup; only Python exposes a streaming `update(candle)` method. diff --git a/Indicators/Indicator-AwesomeOscillatorHistogram.md b/Indicators/Indicator-AwesomeOscillatorHistogram.md index 34d8105..2c432a5 100644 --- a/Indicators/Indicator-AwesomeOscillatorHistogram.md +++ b/Indicators/Indicator-AwesomeOscillatorHistogram.md @@ -65,7 +65,7 @@ const _: fn(&mut AwesomeOscillatorHistogram, Candle) -> Option = Only `high` and `low` are read (the AO uses the median price), so both native bindings take just those two series. Python streams as `float | None` and batches `AwesomeOscillatorHistogram(fast, slow, lookback).batch(high, low)` to a 1-D -`numpy.ndarray` (`NaN` warmup). Node streams as `number | null` via +`array.array('d')` (`NaN` warmup). Node streams as `number | null` via `update(high, low)` and batches `batch(high, low)`. ## Warmup diff --git a/Indicators/Indicator-Bat.md b/Indicators/Indicator-Bat.md index af2d307..54a0947 100644 --- a/Indicators/Indicator-Bat.md +++ b/Indicators/Indicator-Bat.md @@ -41,7 +41,7 @@ const _: fn(&mut wickra::Bat, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-BeltHold.md b/Indicators/Indicator-BeltHold.md index e7592d7..9475f28 100644 --- a/Indicators/Indicator-BeltHold.md +++ b/Indicators/Indicator-BeltHold.md @@ -56,7 +56,7 @@ const _: fn(&mut BeltHold, Candle) -> Option = ::upd - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-Beta.md b/Indicators/Indicator-Beta.md index 3826ce8..7e65d05 100644 --- a/Indicators/Indicator-Beta.md +++ b/Indicators/Indicator-Beta.md @@ -37,7 +37,7 @@ Population formulas (not sample). Each `update` is O(1). See ## Inputs / Outputs `Indicator`. Python: -`Beta(period).batch(asset, benchmark)` returns a 1-D `np.ndarray` +`Beta(period).batch(asset, benchmark)` returns an `array.array('d')` with `NaN` warmup. Node: same. ## Warmup diff --git a/Indicators/Indicator-BetterVolume.md b/Indicators/Indicator-BetterVolume.md index b1025a3..48ee89c 100644 --- a/Indicators/Indicator-BetterVolume.md +++ b/Indicators/Indicator-BetterVolume.md @@ -113,10 +113,12 @@ bv = ta.BetterVolume(20) n = 60 high = np.array([105.0] * n) low = np.array([100.0] * n) +close = np.array([102.0] * n) volume = np.array([1000.0] * n) volume[-1] = 5000.0 # churn bar high[-1] = 100.5 # narrow range -print(bv.batch(high, low, volume)[-1] > 0) # True +close[-1] = 100.2 # keep the last candle valid (low <= close <= high) +print(bv.batch(high, low, close, volume)[-1] > 0) # True ``` ### Node diff --git a/Indicators/Indicator-BipowerVariation.md b/Indicators/Indicator-BipowerVariation.md index 4a4f3d9..fb52e11 100644 --- a/Indicators/Indicator-BipowerVariation.md +++ b/Indicators/Indicator-BipowerVariation.md @@ -52,7 +52,7 @@ const _: fn(&mut BipowerVariation, f64) -> Option = ` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-BodySizePct.md b/Indicators/Indicator-BodySizePct.md index 82ddefd..e8433fd 100644 --- a/Indicators/Indicator-BodySizePct.md +++ b/Indicators/Indicator-BodySizePct.md @@ -43,7 +43,7 @@ const _: fn(&mut BodySizePct, Candle) -> Option = Option = None i=1 -> None i=2 -> None i=3 -> None -i=4 -> Some(BollingerOutput { upper: 5.759591794226543, middle: 3.8, lower: 1.8404082057734565, stddev: 0.9797958971132716 }) -i=5 -> Some(BollingerOutput { upper: 5.379795897113269, middle: 4.4, lower: 3.420204102886732, stddev: 0.48989794855663404 }) -i=6 -> Some(BollingerOutput { upper: 7.190890230020663, middle: 5.0, lower: 2.809109769979336, stddev: 1.095445115010332 }) -i=7 -> Some(BollingerOutput { upper: 9.577708763999665, middle: 6.0, lower: 2.422291236000335, stddev: 1.7888543819998326 }) +i=4 -> Some(BollingerOutput { upper: 5.759591794226543, middle: 3.8, lower: 1.8404082057734574, stddev: 0.9797958971132712 }) +i=5 -> Some(BollingerOutput { upper: 5.379795897113271, middle: 4.4, lower: 3.4202041028867294, stddev: 0.48989794855663554 }) +i=6 -> Some(BollingerOutput { upper: 7.190890230020665, middle: 5.0, lower: 2.8091097699793353, stddev: 1.0954451150103324 }) +i=7 -> Some(BollingerOutput { upper: 9.577708763999663, middle: 6.0, lower: 2.4222912360003366, stddev: 1.7888543819998317 }) ``` The first emission at `i=4` uses the window `[2, 4, 4, 4, 5]` with mean diff --git a/Indicators/Indicator-BollingerBandwidth.md b/Indicators/Indicator-BollingerBandwidth.md index 272ddee..f2986e2 100644 --- a/Indicators/Indicator-BollingerBandwidth.md +++ b/Indicators/Indicator-BollingerBandwidth.md @@ -50,7 +50,7 @@ const _: fn(&mut BollingerBandwidth, f64) -> Option = ` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-BomarBands.md b/Indicators/Indicator-BomarBands.md index 765877b..221baa7 100644 --- a/Indicators/Indicator-BomarBands.md +++ b/Indicators/Indicator-BomarBands.md @@ -56,7 +56,7 @@ const _: fn(&mut BomarBands, f64) -> Option = ``` - **Python streaming.** `update(value)` returns `(upper, middle, lower)` or `None`. -- **Python batch.** `BomarBands.batch(prices)` returns an `(n, 3)` `np.ndarray` +- **Python batch.** `BomarBands.batch(prices)` returns an `(n, 3)` `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(value)` returns a `{ upper, middle, lower }` object or `null`. diff --git a/Indicators/Indicator-BreadthThrust.md b/Indicators/Indicator-BreadthThrust.md index dd5142d..f15f04c 100644 --- a/Indicators/Indicator-BreadthThrust.md +++ b/Indicators/Indicator-BreadthThrust.md @@ -54,7 +54,7 @@ The bindings pass a tick as four equal-length parallel arrays; the constructor takes the window length: - **Python**: `BreadthThrust(period)`, `update(change, volume, new_high, new_low)`; - `batch(...)` returns a 1-D `ndarray` with `NaN` during warmup. + `batch(...)` returns an `array.array('d')` with `NaN` during warmup. - **Node**: `new BreadthThrust(period)`, `update(change, volume, newHigh, newLow)`; `batch` returns `number[]` with `NaN` during warmup. - **WASM**: `new BreadthThrust(period)`, `update(...)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-Breakaway.md b/Indicators/Indicator-Breakaway.md index 8c4052c..122f35f 100644 --- a/Indicators/Indicator-Breakaway.md +++ b/Indicators/Indicator-Breakaway.md @@ -57,7 +57,7 @@ const _: fn(&mut Breakaway, Candle) -> Option = ::u - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-BullishPercentIndex.md b/Indicators/Indicator-BullishPercentIndex.md index 4002695..c60d3d3 100644 --- a/Indicators/Indicator-BullishPercentIndex.md +++ b/Indicators/Indicator-BullishPercentIndex.md @@ -54,7 +54,7 @@ Build the members with `Member::with_signals(change, volume, new_high, new_low, above_ma, on_buy_signal)`. - **Python**: `update(change, volume, new_high, new_low, on_buy_signal)`; - `batch(...)` takes five array groups per tick and returns a 1-D `ndarray`. + `batch(...)` takes five array groups per tick and returns an `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow, onBuySignal)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow, onBuySignal)` only; every array diff --git a/Indicators/Indicator-Butterfly.md b/Indicators/Indicator-Butterfly.md index a7d9e3c..78fbbcd 100644 --- a/Indicators/Indicator-Butterfly.md +++ b/Indicators/Indicator-Butterfly.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::Butterfly, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-Cci.md b/Indicators/Indicator-Cci.md index 5dcf1d9..a20105d 100644 --- a/Indicators/Indicator-Cci.md +++ b/Indicators/Indicator-Cci.md @@ -56,7 +56,7 @@ use wickra::{Indicator, Cci, Candle}; const _: fn(&mut Cci, Candle) -> Option = ::update; ``` -Python's `CCI.batch(high, low, close)` returns a 1-D `float64` `np.ndarray` +Python's `CCI.batch(high, low, close)` returns an `array.array('d')` with `NaN` during warmup. Node's `CCI.batch(high, low, close)` returns a flat `number[]` (also `NaN` during warmup); the Node binding does not expose a streaming `update()` (`bindings/node/index.d.ts` lists only diff --git a/Indicators/Indicator-CenterOfGravity.md b/Indicators/Indicator-CenterOfGravity.md index 916f6b9..452eefc 100644 --- a/Indicators/Indicator-CenterOfGravity.md +++ b/Indicators/Indicator-CenterOfGravity.md @@ -42,7 +42,7 @@ around zero for a constant input. See ## Inputs / Outputs `Indicator`. Python: -`CenterOfGravity(period).batch(prices)` returns a 1-D `np.ndarray` +`CenterOfGravity(period).batch(prices)` returns an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(value)` returns `number | null`. diff --git a/Indicators/Indicator-CentralPivotRange.md b/Indicators/Indicator-CentralPivotRange.md index ba7709b..78c67a6 100644 --- a/Indicators/Indicator-CentralPivotRange.md +++ b/Indicators/Indicator-CentralPivotRange.md @@ -98,7 +98,7 @@ import numpy as np import wickra as ta cpr = ta.CentralPivotRange() -pivot, tc, bc = cpr.batch(np.array([110.0]), np.array([90.0]), np.array([105.0])).T +pivot, tc, bc = np.asarray(cpr.batch(np.array([110.0]), np.array([90.0]), np.array([105.0])).tolist()).T print(pivot[0], tc[0], bc[0]) ``` diff --git a/Indicators/Indicator-Cfo.md b/Indicators/Indicator-Cfo.md index 92a048a..910022b 100644 --- a/Indicators/Indicator-Cfo.md +++ b/Indicators/Indicator-Cfo.md @@ -46,7 +46,7 @@ const _: fn(&mut Cfo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out (a percentage). Python maps -this to `float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +this to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array` with `NaN` warmup. ## Warmup diff --git a/Indicators/Indicator-CloseVsOpen.md b/Indicators/Indicator-CloseVsOpen.md index 287745f..379ccbc 100644 --- a/Indicators/Indicator-CloseVsOpen.md +++ b/Indicators/Indicator-CloseVsOpen.md @@ -44,7 +44,7 @@ const _: fn(&mut CloseVsOpen, Candle) -> Option = Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-Cmo.md b/Indicators/Indicator-Cmo.md index 07f8597..584cc0a 100644 --- a/Indicators/Indicator-Cmo.md +++ b/Indicators/Indicator-Cmo.md @@ -49,7 +49,7 @@ const _: fn(&mut Cmo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-ConcealingBabySwallow.md b/Indicators/Indicator-ConcealingBabySwallow.md index 3e6d659..0efe0e4 100644 --- a/Indicators/Indicator-ConcealingBabySwallow.md +++ b/Indicators/Indicator-ConcealingBabySwallow.md @@ -55,7 +55,7 @@ const _: fn(&mut ConcealingBabySwallow, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-ConnorsRsi.md b/Indicators/Indicator-ConnorsRsi.md index 2c15136..8e76dc1 100644 --- a/Indicators/Indicator-ConnorsRsi.md +++ b/Indicators/Indicator-ConnorsRsi.md @@ -59,7 +59,7 @@ factory (`connors_rsi.rs:74-77`). ## Inputs / Outputs `Indicator`. Python: `ConnorsRSI.batch(prices)` -returns a 1-D `np.ndarray` with `NaN` in the warmup prefix. Node: +returns an `array.array('d')` with `NaN` in the warmup prefix. Node: `ConnorsRSI.batch(prices)` returns `Array` (`NaN` in warmup slots); `update(value)` returns `number | null`. diff --git a/Indicators/Indicator-Coppock.md b/Indicators/Indicator-Coppock.md index 6e1b548..0f1a838 100644 --- a/Indicators/Indicator-Coppock.md +++ b/Indicators/Indicator-Coppock.md @@ -50,7 +50,7 @@ const _: fn(&mut Coppock, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Counterattack.md b/Indicators/Indicator-Counterattack.md index cec1dc2..3ab9593 100644 --- a/Indicators/Indicator-Counterattack.md +++ b/Indicators/Indicator-Counterattack.md @@ -57,7 +57,7 @@ const _: fn(&mut Counterattack, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Crab.md b/Indicators/Indicator-Crab.md index 4ab5c48..2565b8c 100644 --- a/Indicators/Indicator-Crab.md +++ b/Indicators/Indicator-Crab.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::Crab, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-CumulativeVolumeIndex.md b/Indicators/Indicator-CumulativeVolumeIndex.md index 5f1e383..bb16364 100644 --- a/Indicators/Indicator-CumulativeVolumeIndex.md +++ b/Indicators/Indicator-CumulativeVolumeIndex.md @@ -54,7 +54,7 @@ const _: fn(&mut CumulativeVolumeIndex, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-CupAndHandle.md b/Indicators/Indicator-CupAndHandle.md index d629fa0..3f31e12 100644 --- a/Indicators/Indicator-CupAndHandle.md +++ b/Indicators/Indicator-CupAndHandle.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::CupAndHandle, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-CyberneticCycle.md b/Indicators/Indicator-CyberneticCycle.md index 2f70077..97d494d 100644 --- a/Indicators/Indicator-CyberneticCycle.md +++ b/Indicators/Indicator-CyberneticCycle.md @@ -49,7 +49,7 @@ initial condition so downstream consumers stay reactive. See `Indicator`. Python: `CyberneticCycle(period).batch(prices)` returns a 1-D -`np.ndarray`. Node: same shape; `update(value)` returns `number`. +`array.array('d')`. Node: same shape; `update(value)` returns `number`. ## Warmup diff --git a/Indicators/Indicator-Cypher.md b/Indicators/Indicator-Cypher.md index b8ab279..4240c75 100644 --- a/Indicators/Indicator-Cypher.md +++ b/Indicators/Indicator-Cypher.md @@ -44,7 +44,7 @@ const _: fn(&mut wickra::Cypher, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-DayOfWeekProfile.md b/Indicators/Indicator-DayOfWeekProfile.md index 16eed2b..44427ce 100644 --- a/Indicators/Indicator-DayOfWeekProfile.md +++ b/Indicators/Indicator-DayOfWeekProfile.md @@ -40,7 +40,7 @@ const _: fn(&mut wickra::DayOfWeekProfile, wickra::Candle) -> Option::update; ``` -- **Python.** `update((o,h,l,c,v,ts))` → length-7 `ndarray` (or `None`); +- **Python.** `update((o,h,l,c,v,ts))` → length-7 `Matrix` (or `None`); `batch(...)` → `(n, 7)` array, warmup rows `NaN`. - **Node.** `update(...)` → `number[]` (or `null`); `batch(...)` → flat `number[]` length `n*7`. - **WASM.** `update(...)` → `Float64Array` (or `null`). diff --git a/Indicators/Indicator-Decycler.md b/Indicators/Indicator-Decycler.md index 81dec53..cc0e986 100644 --- a/Indicators/Indicator-Decycler.md +++ b/Indicators/Indicator-Decycler.md @@ -47,7 +47,7 @@ the conventional Ehlers initialisation. See ## Inputs / Outputs `Indicator`. Python: -`Decycler(period).batch(prices)` returns a 1-D `np.ndarray` (the +`Decycler(period).batch(prices)` returns an `array.array('d')` (the first 2 bars pass through input unchanged). Node: same shape; `update(value)` returns `number`. diff --git a/Indicators/Indicator-DecyclerOscillator.md b/Indicators/Indicator-DecyclerOscillator.md index f58d647..4b827a3 100644 --- a/Indicators/Indicator-DecyclerOscillator.md +++ b/Indicators/Indicator-DecyclerOscillator.md @@ -45,7 +45,7 @@ must be strictly less than slow period" }` if `fast >= slow`. `Indicator`. Python: `DecyclerOscillator(fast, slow).batch(prices)` returns a 1-D -`np.ndarray`. Node: same shape; `update(value)` returns `number`. +`array.array('d')`. Node: same shape; `update(value)` returns `number`. ## Warmup diff --git a/Indicators/Indicator-Dema.md b/Indicators/Indicator-Dema.md index 1fc9836..139c732 100644 --- a/Indicators/Indicator-Dema.md +++ b/Indicators/Indicator-Dema.md @@ -50,7 +50,7 @@ const _: fn(&mut Dema, f64) -> Option = ::update; ``` Python `update` returns `float | None`, `batch` returns a 1-D -`numpy.ndarray` (`float64`, `NaN` for warmup). Node `update` returns +`array.array('d')` (`float64`, `NaN` for warmup). Node `update` returns `number | null`, `batch` returns `Array` with `NaN` placeholders. ## Warmup diff --git a/Indicators/Indicator-DemandIndex.md b/Indicators/Indicator-DemandIndex.md index d257db5..1343d58 100644 --- a/Indicators/Indicator-DemandIndex.md +++ b/Indicators/Indicator-DemandIndex.md @@ -44,7 +44,7 @@ streaming-friendly shape. See `Indicator`. Python: `DemandIndex(period).batch(high, low, close, volume)` returns a -1-D `np.ndarray` with `NaN` warmup. Node: same shape. +`array.array('d')` with `NaN` warmup. Node: same shape. ## Warmup diff --git a/Indicators/Indicator-DerivativeOscillator.md b/Indicators/Indicator-DerivativeOscillator.md index 8e52061..606a38e 100644 --- a/Indicators/Indicator-DerivativeOscillator.md +++ b/Indicators/Indicator-DerivativeOscillator.md @@ -58,7 +58,7 @@ const _: fn(&mut DerivativeOscillator, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-DisparityIndex.md b/Indicators/Indicator-DisparityIndex.md index 3a4c901..2e34e4f 100644 --- a/Indicators/Indicator-DisparityIndex.md +++ b/Indicators/Indicator-DisparityIndex.md @@ -52,7 +52,7 @@ const _: fn(&mut DisparityIndex, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-Doji.md b/Indicators/Indicator-Doji.md index e42550f..88df634 100644 --- a/Indicators/Indicator-Doji.md +++ b/Indicators/Indicator-Doji.md @@ -69,7 +69,7 @@ detector into signed mode and composes with `with_threshold`. ## Inputs / Outputs `Indicator`. Python: -`Doji().batch(open, high, low, close)` returns a 1-D `np.ndarray`. +`Doji().batch(open, high, low, close)` returns an `array.array('d')`. Node: `update(candle)` returns `number | null` (only `null` for a non-finite candle). diff --git a/Indicators/Indicator-DojiStar.md b/Indicators/Indicator-DojiStar.md index 457f8cf..ec62ad7 100644 --- a/Indicators/Indicator-DojiStar.md +++ b/Indicators/Indicator-DojiStar.md @@ -50,7 +50,7 @@ const _: fn(&mut DojiStar, Candle) -> Option = ::upd - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Donchian.md b/Indicators/Indicator-Donchian.md index d76f6c9..d7f53d1 100644 --- a/Indicators/Indicator-Donchian.md +++ b/Indicators/Indicator-Donchian.md @@ -49,7 +49,7 @@ const _: fn(&mut Donchian, Candle) -> Option = Option = Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (`0.0` until a pattern, never - `None`); `batch(open, high, low, close)` → 1-D `ndarray`. + `None`); `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-DownsideGapThreeMethods.md b/Indicators/Indicator-DownsideGapThreeMethods.md index 1a574f7..8d4074a 100644 --- a/Indicators/Indicator-DownsideGapThreeMethods.md +++ b/Indicators/Indicator-DownsideGapThreeMethods.md @@ -53,7 +53,7 @@ const _: fn(&mut DownsideGapThreeMethods, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Dpo.md b/Indicators/Indicator-Dpo.md index 6d652ae..57435e9 100644 --- a/Indicators/Indicator-Dpo.md +++ b/Indicators/Indicator-Dpo.md @@ -52,7 +52,7 @@ const _: fn(&mut Dpo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-DragonflyDoji.md b/Indicators/Indicator-DragonflyDoji.md index 225598d..eb6e687 100644 --- a/Indicators/Indicator-DragonflyDoji.md +++ b/Indicators/Indicator-DragonflyDoji.md @@ -51,7 +51,7 @@ const _: fn(&mut DragonflyDoji, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-DrawdownDuration.md b/Indicators/Indicator-DrawdownDuration.md index 02c256f..6597476 100644 --- a/Indicators/Indicator-DrawdownDuration.md +++ b/Indicators/Indicator-DrawdownDuration.md @@ -34,8 +34,8 @@ None — `DrawdownDuration::new()` takes no arguments. ## Inputs / Outputs `Indicator`. Python: -`DrawdownDuration().batch(equity)` returns a 1-D `np.ndarray` of -`uint32` values (no warmup `NaN`). Node: `update(equity)` returns +`DrawdownDuration().batch(equity)` returns an `array.array('d')` whose +values are whole bar counts (no warmup `NaN`). Node: `update(equity)` returns `number` (always defined after first bar). ## Warmup diff --git a/Indicators/Indicator-DumplingTop.md b/Indicators/Indicator-DumplingTop.md index 2fc3e92..a52b295 100644 --- a/Indicators/Indicator-DumplingTop.md +++ b/Indicators/Indicator-DumplingTop.md @@ -99,7 +99,7 @@ import wickra as ta d = ta.DumplingTop(9) close = np.array([100, 102, 104, 105, 104, 102, 99, 97, 95], float) -print(d.batch(close)[-1]) # -1.0 +print(d.batch(close + 1, close - 1, close)[-1]) # -1.0 ``` ### Node @@ -107,7 +107,8 @@ print(d.batch(close)[-1]) # -1.0 ```javascript const ta = require('wickra'); const d = new ta.DumplingTop(9); -console.log(d.batch([100, 102, 104, 105, 104, 102, 99, 97, 95]).at(-1)); // -1 +const close = [100, 102, 104, 105, 104, 102, 99, 97, 95]; +console.log(d.batch(close.map(c => c + 1), close.map(c => c - 1), close).at(-1)); // -1 ``` ### Streaming diff --git a/Indicators/Indicator-Dx.md b/Indicators/Indicator-Dx.md index 8af0b17..d51c99b 100644 --- a/Indicators/Indicator-Dx.md +++ b/Indicators/Indicator-Dx.md @@ -12,7 +12,7 @@ | Output type | `f64` | | Output range | `[0, 100]` | | Default parameters | `period` is required | -| Warmup period | `period` (first value at candle index `period`) | +| Warmup period | `period + 1` — the first candle only seeds the previous close (first value at candle index `period`) | | Interpretation | How one-sided the directional system is: high = strong trend, near zero = balanced range. | ## Formula @@ -49,13 +49,13 @@ const _: fn(&mut Dx, Candle) -> Option = ::update; `Dx` is a **candle-input** indicator that reads `high`, `low` and `close`. In Python the streaming `update` accepts a candle; the batch helper takes `high`, -`low`, `close` numpy arrays and returns a 1-D `numpy.ndarray` (`NaN` for warmup). +`low`, `close` numpy arrays and returns an `array.array('d')` (`NaN` for warmup). Node and WASM expose `update(high, low, close)` and the matching `batch`. ## Warmup -`Dx::new(period).warmup_period() == period` (the `accessors_report_config` unit -test pins `warmup_period() == 7` for `period = 7`). Because the underlying +`Dx::new(period).warmup_period() == period + 1` (the `accessors_report_config` unit +test pins `warmup_period() == 8` for `period = 7`). Because the underlying directional indicators need the previous bar, the **first emitted value** appears at candle index `period`; `is_ready()` becomes true once the smoothed true range exists. The `strong_trend_drives_dx_high` test pins `out[0] == None` and diff --git a/Indicators/Indicator-DynamicMomentumIndex.md b/Indicators/Indicator-DynamicMomentumIndex.md index 23d703f..cc092ec 100644 --- a/Indicators/Indicator-DynamicMomentumIndex.md +++ b/Indicators/Indicator-DynamicMomentumIndex.md @@ -55,7 +55,7 @@ const _: fn(&mut DynamicMomentumIndex, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-EhlersStochastic.md b/Indicators/Indicator-EhlersStochastic.md index 111ebc6..39f58c2 100644 --- a/Indicators/Indicator-EhlersStochastic.md +++ b/Indicators/Indicator-EhlersStochastic.md @@ -49,7 +49,7 @@ canonical defaults; not user-tunable. `Indicator`. Python: `EhlersStochastic(period).batch(prices)` returns a 1-D -`np.ndarray` with `NaN` in the warmup prefix. Node: same shape; +`array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(value)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-Ehma.md b/Indicators/Indicator-Ehma.md index 171a10a..6d3e7a6 100644 --- a/Indicators/Indicator-Ehma.md +++ b/Indicators/Indicator-Ehma.md @@ -59,7 +59,7 @@ use wickra::{Ehma, Indicator}; const _: fn(&mut Ehma, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-ElderImpulse.md b/Indicators/Indicator-ElderImpulse.md index 162bf2c..d39d316 100644 --- a/Indicators/Indicator-ElderImpulse.md +++ b/Indicators/Indicator-ElderImpulse.md @@ -58,7 +58,7 @@ const _: fn(&mut ElderImpulse, f64) -> Option = A single `f64` close in, an `Option` out that is always one of `{−1.0, 0.0, +1.0}`. Python maps this to `float | None` / a `float64` -`np.ndarray` with `NaN` warmup; Node to `number | null` / `Array`. +`array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-ElderRay.md b/Indicators/Indicator-ElderRay.md index 756670b..4dfd194 100644 --- a/Indicators/Indicator-ElderRay.md +++ b/Indicators/Indicator-ElderRay.md @@ -54,7 +54,7 @@ Two outputs per bar. Node: `update(open, high, low, close)` returns `{ bullPower, bearPower } | null`; `batch(o[], h[], l[], c[])` returns a flat `Array` of length `n*2` (`[bull, bear, bull, bear, …]`, `NaN` for warmup). Python: `update(candle)` returns `(bull, bear) | None`; -`batch(open, high, low, close)` returns an `(n, 2)` `ndarray`. +`batch(open, high, low, close)` returns an `(n, 2)` `Matrix`. ## Warmup @@ -113,7 +113,7 @@ op = np.array([10.0, 12.0, 14.0]) hi = np.array([11.0, 13.0, 16.0]) lo = np.array([9.0, 11.0, 13.0]) cl = np.array([10.0, 12.0, 14.0]) -print(er.batch(op, hi, lo, cl)) # (3, 2): [bull, bear] rows, NaN for warmup +print(er.batch(hi, lo, cl)) # (3, 2): [bull, bear] rows, NaN for warmup ``` Output: @@ -129,13 +129,12 @@ Output: ```javascript const ta = require('wickra'); const er = new ta.ElderRay(3); -const open = [10, 12, 14]; const high = [11, 13, 16]; const low = [9, 11, 13]; const close = [10, 12, 14]; -console.log(er.batch(open, high, low, close)); // flat [bull, bear, …], NaN warmup -const last = er.update(14, 16, 13, 14); -console.log(last); // { bullPower: 4, bearPower: 1 } +console.log(er.batch(high, low, close)); // flat [bull, bear, …], NaN warmup +const last = er.update(16, 13, 14); +console.log(last); // { bullPower: 3, bearPower: 0 } ``` Output: diff --git a/Indicators/Indicator-ElderSafeZone.md b/Indicators/Indicator-ElderSafeZone.md index e119ce1..f377a0e 100644 --- a/Indicators/Indicator-ElderSafeZone.md +++ b/Indicators/Indicator-ElderSafeZone.md @@ -114,7 +114,7 @@ import wickra as ta e = ta.ElderSafeZone(14, 2.0) n = 60 base = np.arange(n, dtype=float) + 100.0 -value, direction = e.batch(base + 2.0, base - 2.0, base + 1.0).T +value, direction = np.asarray(e.batch(base + 2.0, base - 2.0, base + 1.0).tolist()).T print(value[-1], direction[-1]) ``` diff --git a/Indicators/Indicator-Ema.md b/Indicators/Indicator-Ema.md index 0fac4b8..1a5c38a 100644 --- a/Indicators/Indicator-Ema.md +++ b/Indicators/Indicator-Ema.md @@ -55,7 +55,7 @@ use wickra::{Indicator, Ema}; const _: fn(&mut Ema, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-EmpiricalModeDecomposition.md b/Indicators/Indicator-EmpiricalModeDecomposition.md index 2b10322..7559535 100644 --- a/Indicators/Indicator-EmpiricalModeDecomposition.md +++ b/Indicators/Indicator-EmpiricalModeDecomposition.md @@ -62,7 +62,7 @@ appropriate error for invalid `fraction`. `Indicator`. Python: `EmpiricalModeDecomposition(period, fraction).batch(prices)` -returns a 1-D `np.ndarray` with `NaN` in the warmup prefix. +returns an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(value)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-EstimatedLeverageRatio.md b/Indicators/Indicator-EstimatedLeverageRatio.md index c5c5f4f..3b74a8d 100644 --- a/Indicators/Indicator-EstimatedLeverageRatio.md +++ b/Indicators/Indicator-EstimatedLeverageRatio.md @@ -95,7 +95,7 @@ Some(1.0) import wickra as ta e = ta.EstimatedLeverageRatio() -print(e.update(0.0001, 100, 100, 100, 1000, 400, 600, 0, 0, 0, 0)) # 1.0 +print(e.update(1000, 400, 600)) # open_interest, long_size, short_size -> 1.0 ``` ### Node diff --git a/Indicators/Indicator-EveningDojiStar.md b/Indicators/Indicator-EveningDojiStar.md index 63df8b0..728dad0 100644 --- a/Indicators/Indicator-EveningDojiStar.md +++ b/Indicators/Indicator-EveningDojiStar.md @@ -58,7 +58,7 @@ const _: fn(&mut EveningDojiStar, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Evwma.md b/Indicators/Indicator-Evwma.md index 47376db..05f4ca9 100644 --- a/Indicators/Indicator-Evwma.md +++ b/Indicators/Indicator-Evwma.md @@ -49,7 +49,7 @@ const _: fn(&mut Evwma, Candle) -> Option = ::update; Only `close` and `volume` are read. - **Python.** `update(candle)` returns `float | None`; `batch(close, volume)` - returns a 1-D `float64` `np.ndarray` with `NaN` warmup. + returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(close, volume)` returns `number | null`; `batch(close, volume)` returns an `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-EwmaVolatility.md b/Indicators/Indicator-EwmaVolatility.md index cfb983d..61b7c9f 100644 --- a/Indicators/Indicator-EwmaVolatility.md +++ b/Indicators/Indicator-EwmaVolatility.md @@ -57,7 +57,7 @@ const _: fn(&mut EwmaVolatility, f64) -> Option = ` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Expectancy.md b/Indicators/Indicator-Expectancy.md index e89ea91..af75fbf 100644 --- a/Indicators/Indicator-Expectancy.md +++ b/Indicators/Indicator-Expectancy.md @@ -47,7 +47,7 @@ use wickra::{Indicator, Expectancy}; const _: fn(&mut Expectancy, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-FallingThreeMethods.md b/Indicators/Indicator-FallingThreeMethods.md index d9da1ac..cdd4624 100644 --- a/Indicators/Indicator-FallingThreeMethods.md +++ b/Indicators/Indicator-FallingThreeMethods.md @@ -50,7 +50,7 @@ const _: fn(&mut FallingThreeMethods, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Fama.md b/Indicators/Indicator-Fama.md index f8a5827..bfbe6ab 100644 --- a/Indicators/Indicator-Fama.md +++ b/Indicators/Indicator-Fama.md @@ -52,7 +52,7 @@ the canonical `(0.5, 0.05)` factory. ## Inputs / Outputs `Indicator`. Python: `FAMA(fast, slow).batch(prices)` -returns a 1-D `np.ndarray` with `NaN` in the warmup prefix. Node: +returns an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(value)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-FibArcs.md b/Indicators/Indicator-FibArcs.md index 07bd147..04fa8bd 100644 --- a/Indicators/Indicator-FibArcs.md +++ b/Indicators/Indicator-FibArcs.md @@ -44,7 +44,7 @@ const _: fn(&mut wickra::FibArcs, wickra::Candle) -> Option Option Option Option Option ``` - **Python.** `update((o,h,l,c,v,ts))` → `(fan_382, fan_500, fan_618)` or `None`; - `batch(high, low)` → `(n, 3)` `ndarray` (`NaN` warmup). + `batch(high, low)` → `(n, 3)` `Matrix` (`NaN` warmup). - **Node.** `update(high, low)` → `{ fan382, fan500, fan618 }` or `null`; `batch(high, low)` → flat `number[]` length `n*3`. - **WASM.** `update(high, low)` → object (same camelCase keys) or `null`. diff --git a/Indicators/Indicator-FibProjection.md b/Indicators/Indicator-FibProjection.md index f4c3830..1116931 100644 --- a/Indicators/Indicator-FibProjection.md +++ b/Indicators/Indicator-FibProjection.md @@ -41,7 +41,7 @@ const _: fn(&mut wickra::FibProjection, wickra::Candle) -> Option Option Option Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-FisherTransform.md b/Indicators/Indicator-FisherTransform.md index 2782789..cb4900b 100644 --- a/Indicators/Indicator-FisherTransform.md +++ b/Indicators/Indicator-FisherTransform.md @@ -48,7 +48,7 @@ value; lag manually in user code if you need the trigger. ## Inputs / Outputs `Indicator`. Python: -`FisherTransform(period).batch(prices)` returns a 1-D `np.ndarray` +`FisherTransform(period).batch(prices)` returns an `array.array('d')` with `NaN` for the warmup prefix. Node: same shape; `update(close)` returns `number | null`. diff --git a/Indicators/Indicator-FlagPennant.md b/Indicators/Indicator-FlagPennant.md index 94d3501..767e95c 100644 --- a/Indicators/Indicator-FlagPennant.md +++ b/Indicators/Indicator-FlagPennant.md @@ -44,7 +44,7 @@ const _: fn(&mut wickra::FlagPennant, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-FractalChaosBands.md b/Indicators/Indicator-FractalChaosBands.md index bb2054d..869b835 100644 --- a/Indicators/Indicator-FractalChaosBands.md +++ b/Indicators/Indicator-FractalChaosBands.md @@ -56,7 +56,7 @@ const _: fn(&mut FractalChaosBands, Candle) -> Option = - **Python streaming.** `update(candle)` returns `(upper, lower)` or `None`. - **Python batch.** `FractalChaosBands.batch(high, low)` returns an `(n, 2)` - `np.ndarray` with columns `[upper, lower]`; rows before both bands confirm + `Matrix` with columns `[upper, lower]`; rows before both bands confirm are `NaN`. - **Node streaming.** `update(high, low)` returns a `{ upper, lower }` object or `null`. diff --git a/Indicators/Indicator-Frama.md b/Indicators/Indicator-Frama.md index e85c818..b9e51cf 100644 --- a/Indicators/Indicator-Frama.md +++ b/Indicators/Indicator-Frama.md @@ -54,7 +54,7 @@ const _: fn(&mut Frama, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +`float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-FryPanBottom.md b/Indicators/Indicator-FryPanBottom.md index 6b1a639..2f11879 100644 --- a/Indicators/Indicator-FryPanBottom.md +++ b/Indicators/Indicator-FryPanBottom.md @@ -99,7 +99,7 @@ import wickra as ta f = ta.FryPanBottom(9) close = np.array([100, 98, 96, 95, 96, 98, 101, 103, 105], float) -print(f.batch(close)[-1]) # 1.0 +print(f.batch(close + 1, close - 1, close)[-1]) # 1.0 ``` ### Node @@ -107,7 +107,8 @@ print(f.batch(close)[-1]) # 1.0 ```javascript const ta = require('wickra'); const f = new ta.FryPanBottom(9); -console.log(f.batch([100, 98, 96, 95, 96, 98, 101, 103, 105]).at(-1)); // 1 +const close = [100, 98, 96, 95, 96, 98, 101, 103, 105]; +console.log(f.batch(close.map(c => c + 1), close.map(c => c - 1), close).at(-1)); // 1 ``` ### Streaming diff --git a/Indicators/Indicator-FundingImpliedApr.md b/Indicators/Indicator-FundingImpliedApr.md index cc3fa9c..3e7836b 100644 --- a/Indicators/Indicator-FundingImpliedApr.md +++ b/Indicators/Indicator-FundingImpliedApr.md @@ -91,7 +91,7 @@ Output: ```python import wickra as ta f = ta.FundingImpliedApr(1095.0) -print(f.update(0.0001, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0)) # 0.1095 +print(f.update(0.0001)) # funding_rate -> 0.1095 ``` ### Node diff --git a/Indicators/Indicator-FundingRateZScore.md b/Indicators/Indicator-FundingRateZScore.md index 59dafd1..716bd91 100644 --- a/Indicators/Indicator-FundingRateZScore.md +++ b/Indicators/Indicator-FundingRateZScore.md @@ -49,8 +49,10 @@ is streaming-only. - **Flat window.** Zero dispersion (a constant funding series) returns exactly `0` rather than dividing by zero. -- **Precision.** The variance uses `E[x²] − E[x]²` with a non-negative clamp; - compare z-scores with an `1e-9` tolerance, not `1e-12`. +- **Precision.** The variance is accumulated around a shifted origin rather + than around zero, so the cancellation that `E[x²] − E[x]²` suffers on funding + values far from zero does not apply. A non-negative clamp still guards the + square root. ## Examples diff --git a/Indicators/Indicator-GapSideBySideWhite.md b/Indicators/Indicator-GapSideBySideWhite.md index cec9545..566dd00 100644 --- a/Indicators/Indicator-GapSideBySideWhite.md +++ b/Indicators/Indicator-GapSideBySideWhite.md @@ -53,7 +53,7 @@ const _: fn(&mut GapSideBySideWhite, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Garch11.md b/Indicators/Indicator-Garch11.md index 6e3a7e4..90dfe35 100644 --- a/Indicators/Indicator-Garch11.md +++ b/Indicators/Indicator-Garch11.md @@ -55,7 +55,7 @@ const _: fn(&mut Garch11, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-GarmanKlassVolatility.md b/Indicators/Indicator-GarmanKlassVolatility.md index dfdea98..5a959ff 100644 --- a/Indicators/Indicator-GarmanKlassVolatility.md +++ b/Indicators/Indicator-GarmanKlassVolatility.md @@ -55,7 +55,7 @@ const _: fn(&mut GarmanKlassVolatility, Candle) -> Option = ` with `NaN` diff --git a/Indicators/Indicator-Gartley.md b/Indicators/Indicator-Gartley.md index dd4825a..e8d1f31 100644 --- a/Indicators/Indicator-Gartley.md +++ b/Indicators/Indicator-Gartley.md @@ -44,7 +44,7 @@ const _: fn(&mut wickra::Gartley, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-GatorOscillator.md b/Indicators/Indicator-GatorOscillator.md index f68228b..16dfbd5 100644 --- a/Indicators/Indicator-GatorOscillator.md +++ b/Indicators/Indicator-GatorOscillator.md @@ -61,7 +61,7 @@ uniformity and ignored). Node: `update(high, low, close)` returns `{ upper, lower } | null`; `batch(h[], l[], c[])` returns a flat `Array` of length `n*2` (`[upper, lower, upper, lower, …]`, `NaN` for warmup). Python: `update(candle)` returns `(upper, lower) | None`; -`batch(high, low, close)` returns an `(n, 2)` `ndarray`. +`batch(high, low, close)` returns an `(n, 2)` `Matrix`. ## Warmup diff --git a/Indicators/Indicator-GeneralizedDema.md b/Indicators/Indicator-GeneralizedDema.md index 76504a2..818ef50 100644 --- a/Indicators/Indicator-GeneralizedDema.md +++ b/Indicators/Indicator-GeneralizedDema.md @@ -56,7 +56,7 @@ const _: fn(&mut GeneralizedDema, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-GeometricMa.md b/Indicators/Indicator-GeometricMa.md index 60fc881..d537c00 100644 --- a/Indicators/Indicator-GeometricMa.md +++ b/Indicators/Indicator-GeometricMa.md @@ -53,7 +53,7 @@ const _: fn(&mut GeometricMa, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-GoldenPocket.md b/Indicators/Indicator-GoldenPocket.md index ddff715..8781f6f 100644 --- a/Indicators/Indicator-GoldenPocket.md +++ b/Indicators/Indicator-GoldenPocket.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::GoldenPocket, wickra::Candle) -> Option Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-Hammer.md b/Indicators/Indicator-Hammer.md index 8162239..e5f8885 100644 --- a/Indicators/Indicator-Hammer.md +++ b/Indicators/Indicator-Hammer.md @@ -51,7 +51,7 @@ opposite sign. `Indicator`. Python: `Hammer().batch(open, high, low, close)` returns a 1-D -`np.ndarray`. Node: `update(candle)` returns `number | null`. +`array.array('d')`. Node: `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-HeadAndShoulders.md b/Indicators/Indicator-HeadAndShoulders.md index 6a460e1..58f8616 100644 --- a/Indicators/Indicator-HeadAndShoulders.md +++ b/Indicators/Indicator-HeadAndShoulders.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::HeadAndShoulders, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-HeikinAshiOscillator.md b/Indicators/Indicator-HeikinAshiOscillator.md index 4c13755..7c4b977 100644 --- a/Indicators/Indicator-HeikinAshiOscillator.md +++ b/Indicators/Indicator-HeikinAshiOscillator.md @@ -49,7 +49,7 @@ const _: fn(&mut HeikinAshiOscillator, Candle) -> Option = ``` A `Candle` in, an `Option` out. Python `update(candle)` / `batch(open, high, -low, close)` → 1-D ndarray (NaN warmup); Node `update(open, high, low, close)` / +low, close)` → `array.array('d')` (NaN warmup); Node `update(open, high, low, close)` / `batch(...)`. ## Warmup diff --git a/Indicators/Indicator-HiLoActivator.md b/Indicators/Indicator-HiLoActivator.md index 713be29..6c00cce 100644 --- a/Indicators/Indicator-HiLoActivator.md +++ b/Indicators/Indicator-HiLoActivator.md @@ -52,7 +52,7 @@ The first input that fills the SMA window seeds a long. See `Indicator`. Python: `HiLoActivator(period).batch(high, low, close)` returns a 1-D -`np.ndarray` with `NaN` for the warmup prefix. Node: +`array.array('d')` with `NaN` for the warmup prefix. Node: `HiLoActivator(period).batch(...)` returns `Array`; `update(candle)` returns `number | null`. diff --git a/Indicators/Indicator-HighLowIndex.md b/Indicators/Indicator-HighLowIndex.md index 370ea08..8a5504f 100644 --- a/Indicators/Indicator-HighLowIndex.md +++ b/Indicators/Indicator-HighLowIndex.md @@ -52,7 +52,7 @@ This indicator reads the `new_high` / `new_low` flags. The bindings pass a tick four equal-length parallel arrays; the constructor takes the window length: - **Python**: `HighLowIndex(period)`, `update(change, volume, new_high, new_low)`; - `batch(...)` returns a 1-D `ndarray` with `NaN` during warmup. + `batch(...)` returns an `array.array('d')` with `NaN` during warmup. - **Node**: `new HighLowIndex(period)`, `update(change, volume, newHigh, newLow)`; `batch` returns `number[]` with `NaN` during warmup. - **WASM**: `new HighLowIndex(period)`, `update(...)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-HighLowRange.md b/Indicators/Indicator-HighLowRange.md index e37d95b..90e7e22 100644 --- a/Indicators/Indicator-HighLowRange.md +++ b/Indicators/Indicator-HighLowRange.md @@ -44,7 +44,7 @@ const _: fn(&mut HighLowRange, Candle) -> Option = Option = ::upd - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-Hikkake.md b/Indicators/Indicator-Hikkake.md index cc474aa..10d8c7d 100644 --- a/Indicators/Indicator-Hikkake.md +++ b/Indicators/Indicator-Hikkake.md @@ -52,7 +52,7 @@ const _: fn(&mut Hikkake, Candle) -> Option = ::updat - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-HikkakeModified.md b/Indicators/Indicator-HikkakeModified.md index 2fade8c..95129cb 100644 --- a/Indicators/Indicator-HikkakeModified.md +++ b/Indicators/Indicator-HikkakeModified.md @@ -52,7 +52,7 @@ const _: fn(&mut HikkakeModified, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-HilbertDominantCycle.md b/Indicators/Indicator-HilbertDominantCycle.md index 87db180..09c7743 100644 --- a/Indicators/Indicator-HilbertDominantCycle.md +++ b/Indicators/Indicator-HilbertDominantCycle.md @@ -49,7 +49,7 @@ constructed estimator; `Default` is also implemented. ## Inputs / Outputs `Indicator`. Python: -`HilbertDominantCycle().batch(prices)` returns a 1-D `np.ndarray` +`HilbertDominantCycle().batch(prices)` returns an `array.array('d')` with `NaN` in the long warmup prefix. Node: same shape; `update` returns `number | null`. diff --git a/Indicators/Indicator-HistoricalVolatility.md b/Indicators/Indicator-HistoricalVolatility.md index cf613cc..bd7458a 100644 --- a/Indicators/Indicator-HistoricalVolatility.md +++ b/Indicators/Indicator-HistoricalVolatility.md @@ -50,7 +50,7 @@ const _: fn(&mut HistoricalVolatility, f64) -> Option = ` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Hma.md b/Indicators/Indicator-Hma.md index faf10f4..31d3832 100644 --- a/Indicators/Indicator-Hma.md +++ b/Indicators/Indicator-Hma.md @@ -52,7 +52,7 @@ use wickra::{Indicator, Hma}; const _: fn(&mut Hma, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. diff --git a/Indicators/Indicator-HoltWinters.md b/Indicators/Indicator-HoltWinters.md index 2df767d..bf4d270 100644 --- a/Indicators/Indicator-HoltWinters.md +++ b/Indicators/Indicator-HoltWinters.md @@ -59,7 +59,7 @@ const _: fn(&mut HoltWinters, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. The `level()` and `trend()` accessors expose the two internal states. diff --git a/Indicators/Indicator-HomingPigeon.md b/Indicators/Indicator-HomingPigeon.md index 40a7c29..2a6bac0 100644 --- a/Indicators/Indicator-HomingPigeon.md +++ b/Indicators/Indicator-HomingPigeon.md @@ -49,7 +49,7 @@ const _: fn(&mut HomingPigeon, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-HtDcPhase.md b/Indicators/Indicator-HtDcPhase.md index 7a37e68..02dfa33 100644 --- a/Indicators/Indicator-HtDcPhase.md +++ b/Indicators/Indicator-HtDcPhase.md @@ -50,7 +50,7 @@ use wickra::{Indicator, HtDcPhase}; const _: fn(&mut HtDcPhase, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-HtPhasor.md b/Indicators/Indicator-HtPhasor.md index 18a7d47..1415b4b 100644 --- a/Indicators/Indicator-HtPhasor.md +++ b/Indicators/Indicator-HtPhasor.md @@ -51,7 +51,7 @@ const _: fn(&mut HtPhasor, f64) -> Option = ` of length `n · 2`. diff --git a/Indicators/Indicator-HtTrendMode.md b/Indicators/Indicator-HtTrendMode.md index 68872ff..cda13b6 100644 --- a/Indicators/Indicator-HtTrendMode.md +++ b/Indicators/Indicator-HtTrendMode.md @@ -48,7 +48,7 @@ const _: fn(&mut HtTrendMode, f64) -> Option = :: ``` Python streams as `float | None` (`1.0` / `0.0` once ready), batches as a 1-D -`numpy.ndarray` (`NaN` for warmup). Node streams as `number | null`, batches as +`array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. ## Warmup diff --git a/Indicators/Indicator-HurstChannel.md b/Indicators/Indicator-HurstChannel.md index fc86722..2c1877d 100644 --- a/Indicators/Indicator-HurstChannel.md +++ b/Indicators/Indicator-HurstChannel.md @@ -53,7 +53,7 @@ const _: fn(&mut HurstChannel, Candle) -> Option = Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-ImbalanceBars.md b/Indicators/Indicator-ImbalanceBars.md index 283045a..fa9994f 100644 --- a/Indicators/Indicator-ImbalanceBars.md +++ b/Indicators/Indicator-ImbalanceBars.md @@ -118,8 +118,8 @@ import wickra as ta bars = ta.ImbalanceBars(3.0) for p in (10.0, 11.0, 12.0): - bars.update(p) -print(bars.update(13.0)) # [(10.0, 13.0, 10.0, 13.0, 3.0, 1)] + bars.update(p, p, p, p) +print(bars.update(13.0, 13.0, 13.0, 13.0)) # [(10.0, 13.0, 10.0, 13.0, 3.0, 1)] ``` ### Node @@ -127,8 +127,8 @@ print(bars.update(13.0)) # [(10.0, 13.0, 10.0, 13.0, 3.0, 1)] ```javascript const ta = require('wickra'); const bars = new ta.ImbalanceBars(3.0); -[10.0, 11.0, 12.0].forEach((p) => bars.update(p)); -console.log(bars.update(13.0)[0].direction); // 1 +[10.0, 11.0, 12.0].forEach((p) => bars.update(p, p, p, p)); +console.log(bars.update(13.0, 13.0, 13.0, 13.0)[0].direction); // 1 ``` ### Streaming diff --git a/Indicators/Indicator-InNeck.md b/Indicators/Indicator-InNeck.md index 46abddb..da9212c 100644 --- a/Indicators/Indicator-InNeck.md +++ b/Indicators/Indicator-InNeck.md @@ -51,7 +51,7 @@ const _: fn(&mut InNeck, Candle) -> Option = ::update; - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Inertia.md b/Indicators/Indicator-Inertia.md index 6769cd8..793e215 100644 --- a/Indicators/Indicator-Inertia.md +++ b/Indicators/Indicator-Inertia.md @@ -49,7 +49,7 @@ const _: fn(&mut Inertia, Candle) -> Option = ::updat ``` - **Python.** `update(candle)` returns `float | None`; - `batch(open, high, low, close)` returns a 1-D `float64` `np.ndarray` with + `batch(open, high, low, close)` returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(open, high, low, close)` returns `number | null`; `batch(open, high, low, close)` returns an `Array` with `NaN` diff --git a/Indicators/Indicator-InstantaneousTrendline.md b/Indicators/Indicator-InstantaneousTrendline.md index 809fd52..921b56f 100644 --- a/Indicators/Indicator-InstantaneousTrendline.md +++ b/Indicators/Indicator-InstantaneousTrendline.md @@ -47,7 +47,7 @@ the specified period while preserving the trend. See `Indicator`. Python: `InstantaneousTrendline(period).batch(prices)` returns a 1-D -`np.ndarray` with `NaN` in the warmup prefix. Node: same shape; +`array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(value)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-IntradayIntensity.md b/Indicators/Indicator-IntradayIntensity.md index 43334ed..a73f00b 100644 --- a/Indicators/Indicator-IntradayIntensity.md +++ b/Indicators/Indicator-IntradayIntensity.md @@ -57,7 +57,7 @@ const _: fn(&mut IntradayIntensity, Candle) -> Option = ``` Python streams as `float | None` and batches -`IntradayIntensity().batch(high, low, close, volume)` to a 1-D `numpy.ndarray`. +`IntradayIntensity().batch(high, low, close, volume)` to an `array.array('d')`. Node streams as `number | null` via `update(high, low, close, volume)` and batches `batch(high, low, close, volume)`. With `warmup_period == 1` there is no `NaN`/`null` warmup prefix. diff --git a/Indicators/Indicator-IntradayMomentumIndex.md b/Indicators/Indicator-IntradayMomentumIndex.md index 6834474..c39ad27 100644 --- a/Indicators/Indicator-IntradayMomentumIndex.md +++ b/Indicators/Indicator-IntradayMomentumIndex.md @@ -52,7 +52,7 @@ const _: fn(&mut IntradayMomentumIndex, Candle) -> Option = Because the IMI needs the **open** (not just high/low/close), the bindings take the full OHLC. Node: `update(open, high, low, close)` / `batch(o[], h[], l[], c[])`. -Python: `update(candle)` / `batch(open, high, low, close)` → 1-D `ndarray` +Python: `update(candle)` / `batch(open, high, low, close)` → `array.array('d')` (`NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-IntradayVolatilityProfile.md b/Indicators/Indicator-IntradayVolatilityProfile.md index 3f85ca9..effa257 100644 --- a/Indicators/Indicator-IntradayVolatilityProfile.md +++ b/Indicators/Indicator-IntradayVolatilityProfile.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::IntradayVolatilityProfile, wickra::Candle) -> Option::update; ``` -- **Python.** `update((o,h,l,c,v,ts))` → `ndarray` of length `buckets` (or `None`); +- **Python.** `update((o,h,l,c,v,ts))` → `Matrix` of length `buckets` (or `None`); `batch(...)` → `(n, buckets)` array, warmup rows `NaN`. - **Node.** `update(...)` → `number[]` (or `null`); `batch(...)` → flat `number[]` length `n*buckets`. - **WASM.** `update(...)` → `Float64Array` (or `null`). diff --git a/Indicators/Indicator-InverseFisherTransform.md b/Indicators/Indicator-InverseFisherTransform.md index 51f11ba..288bfb2 100644 --- a/Indicators/Indicator-InverseFisherTransform.md +++ b/Indicators/Indicator-InverseFisherTransform.md @@ -47,7 +47,7 @@ or non-positive `scale`. `Indicator`. Python: `InverseFisherTransform(scale).batch(values)` returns a 1-D -`np.ndarray` (no warmup `NaN`s). Node: `update(value)` returns +`array.array('d')` (no warmup `NaN`s). Node: `update(value)` returns `number`. ## Warmup diff --git a/Indicators/Indicator-Jma.md b/Indicators/Indicator-Jma.md index 30c2f35..538ff0e 100644 --- a/Indicators/Indicator-Jma.md +++ b/Indicators/Indicator-Jma.md @@ -56,7 +56,7 @@ const _: fn(&mut Jma, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +`float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-JumpIndicator.md b/Indicators/Indicator-JumpIndicator.md index b9d8ef5..472bfcd 100644 --- a/Indicators/Indicator-JumpIndicator.md +++ b/Indicators/Indicator-JumpIndicator.md @@ -53,7 +53,7 @@ use wickra::{Indicator, JumpIndicator}; const _: fn(&mut JumpIndicator, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-Kama.md b/Indicators/Indicator-Kama.md index f36f01c..484983a 100644 --- a/Indicators/Indicator-Kama.md +++ b/Indicators/Indicator-Kama.md @@ -63,7 +63,7 @@ use wickra::{Indicator, Kama}; const _: fn(&mut Kama, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` (streaming) / `Array` with `NaN` (batch). `warmup_period()` is exposed in Rust and Python but **not** on the Node `KAMA` class (consult diff --git a/Indicators/Indicator-KaseDevStop.md b/Indicators/Indicator-KaseDevStop.md index 8a4a169..2236963 100644 --- a/Indicators/Indicator-KaseDevStop.md +++ b/Indicators/Indicator-KaseDevStop.md @@ -116,7 +116,7 @@ import wickra as ta k = ta.KaseDevStop(30, 1.0) n = 80 base = np.arange(n, dtype=float) + 100.0 -value, direction = k.batch(base + 2.0, base - 2.0, base + 1.0).T +value, direction = np.asarray(k.batch(base + 2.0, base - 2.0, base + 1.0).tolist()).T print(value[-1], direction[-1]) ``` diff --git a/Indicators/Indicator-KasePermissionStochastic.md b/Indicators/Indicator-KasePermissionStochastic.md index 730e545..52ddd4f 100644 --- a/Indicators/Indicator-KasePermissionStochastic.md +++ b/Indicators/Indicator-KasePermissionStochastic.md @@ -59,7 +59,7 @@ Two outputs per bar; the indicator reads high/low/close. Node: `update(high, low, close)` returns `{ fast, slow } | null`; `batch(h[], l[], c[])` returns a flat `Array` of length `n*2` (`[fast, slow, fast, slow, …]`, `NaN` for warmup). Python: `update(candle)` returns `(fast, slow) | None`; -`batch(high, low, close)` returns an `(n, 2)` `ndarray`. +`batch(high, low, close)` returns an `(n, 2)` `Matrix`. ## Warmup diff --git a/Indicators/Indicator-Keltner.md b/Indicators/Indicator-Keltner.md index e33ed35..4b5a2b6 100644 --- a/Indicators/Indicator-Keltner.md +++ b/Indicators/Indicator-Keltner.md @@ -51,7 +51,7 @@ const _: fn(&mut Keltner, Candle) -> Option = Option = ::updat - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-KickingByLength.md b/Indicators/Indicator-KickingByLength.md index 33cb1f9..c5bdb79 100644 --- a/Indicators/Indicator-KickingByLength.md +++ b/Indicators/Indicator-KickingByLength.md @@ -52,7 +52,7 @@ const _: fn(&mut KickingByLength, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Kst.md b/Indicators/Indicator-Kst.md index 0a70a59..a032f48 100644 --- a/Indicators/Indicator-Kst.md +++ b/Indicators/Indicator-Kst.md @@ -54,7 +54,7 @@ const _: fn(&mut Kst, f64) -> Option = ::update; ``` - **Python.** `update(value)` returns `(kst, signal)` or `None`; - `batch(prices)` returns an `(n, 2)` `np.ndarray` with columns + `batch(prices)` returns an `(n, 2)` `Matrix` with columns `[kst, signal]`; warmup rows are `NaN`. - **Node.** `update(value)` returns a `{ kst, signal }` object or `null`; `batch(prices)` returns a flat `Array` of length `2n`, interleaved diff --git a/Indicators/Indicator-Kvo.md b/Indicators/Indicator-Kvo.md index 0daca0c..ef125fc 100644 --- a/Indicators/Indicator-Kvo.md +++ b/Indicators/Indicator-Kvo.md @@ -91,7 +91,7 @@ import wickra as ta n = 120 base = 100 + np.sin(np.linspace(0, 25, n)) * 5 -k = ta.KVO(34, 55, 13) +k = ta.KVO(34, 55) out = k.batch(base + 1, base - 1, base + 0.3, np.full(n, 1000.0)) print(out[80]) ``` diff --git a/Indicators/Indicator-LadderBottom.md b/Indicators/Indicator-LadderBottom.md index 3f6c9ad..41b49f0 100644 --- a/Indicators/Indicator-LadderBottom.md +++ b/Indicators/Indicator-LadderBottom.md @@ -50,7 +50,7 @@ const _: fn(&mut LadderBottom, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-LaguerreRsi.md b/Indicators/Indicator-LaguerreRsi.md index b3f5dfa..36b4f9b 100644 --- a/Indicators/Indicator-LaguerreRsi.md +++ b/Indicators/Indicator-LaguerreRsi.md @@ -64,7 +64,7 @@ returns the `gamma = 0.5` factory (`laguerre_rsi.rs:76-79`). ## Inputs / Outputs `Indicator`. Python: `LaguerreRSI(gamma).batch(prices)` -returns a 1-D `np.ndarray` (no `NaN` warmup prefix beyond bar 0 — the +returns an `array.array('d')` (no `NaN` warmup prefix beyond bar 0 — the indicator seeds on the first input). Node: `LaguerreRSI(gamma).batch(prices)` returns `Array`; `update(value)` returns `number | null` (`null` only for non-finite input on bar 0). diff --git a/Indicators/Indicator-LinRegChannel.md b/Indicators/Indicator-LinRegChannel.md index a85c917..d8cd2aa 100644 --- a/Indicators/Indicator-LinRegChannel.md +++ b/Indicators/Indicator-LinRegChannel.md @@ -55,7 +55,7 @@ const _: fn(&mut LinRegChannel, f64) -> Option = ` of length diff --git a/Indicators/Indicator-LinRegIntercept.md b/Indicators/Indicator-LinRegIntercept.md index 17c7bf0..32f9fae 100644 --- a/Indicators/Indicator-LinRegIntercept.md +++ b/Indicators/Indicator-LinRegIntercept.md @@ -48,7 +48,7 @@ use wickra::{Indicator, LinRegIntercept}; const _: fn(&mut LinRegIntercept, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-LogReturn.md b/Indicators/Indicator-LogReturn.md index 12aacfe..10d076a 100644 --- a/Indicators/Indicator-LogReturn.md +++ b/Indicators/Indicator-LogReturn.md @@ -45,7 +45,7 @@ use wickra::{Indicator, LogReturn}; const _: fn(&mut LogReturn, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-LongLeggedDoji.md b/Indicators/Indicator-LongLeggedDoji.md index df40277..f7d981c 100644 --- a/Indicators/Indicator-LongLeggedDoji.md +++ b/Indicators/Indicator-LongLeggedDoji.md @@ -52,7 +52,7 @@ const _: fn(&mut LongLeggedDoji, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-LongLine.md b/Indicators/Indicator-LongLine.md index 87c0d60..ae66021 100644 --- a/Indicators/Indicator-LongLine.md +++ b/Indicators/Indicator-LongLine.md @@ -57,7 +57,7 @@ const _: fn(&mut LongLine, Candle) -> Option = ::upd - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` while the rolling average fills). + `array.array('d')` (`0.0` while the rolling average fills). ## Warmup diff --git a/Indicators/Indicator-MaEnvelope.md b/Indicators/Indicator-MaEnvelope.md index c679477..77a3c4e 100644 --- a/Indicators/Indicator-MaEnvelope.md +++ b/Indicators/Indicator-MaEnvelope.md @@ -51,7 +51,7 @@ const _: fn(&mut MaEnvelope, f64) -> Option = Option = ::u In Python the constructor takes the three periods interleaved with their TA-Lib MA-type codes — `MacdExt(fast, fast_matype, slow, slow_matype, signal, signal_matype)`; `update` returns a `(macd, signal, histogram)` tuple and `batch` -an `(n, 3)` `numpy.ndarray`. Node mirrors this and returns a `{ macd, signal, +an `(n, 3)` `Matrix`. Node mirrors this and returns a `{ macd, signal, histogram }` object from `update`. ## Warmup diff --git a/Indicators/Indicator-MacdFix.md b/Indicators/Indicator-MacdFix.md index 135970c..811fb48 100644 --- a/Indicators/Indicator-MacdFix.md +++ b/Indicators/Indicator-MacdFix.md @@ -49,7 +49,7 @@ const _: fn(&mut MacdFix, f64) -> Option = ::u ``` In Python `update` returns a `(macd, signal, histogram)` tuple (or `None` during -warmup) and `batch` returns an `(n, 3)` `numpy.ndarray`. In Node `update` returns +warmup) and `batch` returns an `(n, 3)` `Matrix`. In Node `update` returns a `{ macd, signal, histogram }` object and `batch` a flat `Array` of length `n · 3`. diff --git a/Indicators/Indicator-MacdHistogram.md b/Indicators/Indicator-MacdHistogram.md index 80d7275..32cd0ae 100644 --- a/Indicators/Indicator-MacdHistogram.md +++ b/Indicators/Indicator-MacdHistogram.md @@ -53,7 +53,7 @@ const _: fn(&mut MacdHistogram, f64) -> Option = ` out (price-unit histogram). Python -maps this to `float | None` / a `float64` `np.ndarray` with `NaN` warmup; +maps this to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array` with `NaN` warmup. ## Warmup diff --git a/Indicators/Indicator-MarketFacilitationIndex.md b/Indicators/Indicator-MarketFacilitationIndex.md index 0bcda86..6a43b12 100644 --- a/Indicators/Indicator-MarketFacilitationIndex.md +++ b/Indicators/Indicator-MarketFacilitationIndex.md @@ -35,7 +35,7 @@ None. `Indicator`. Python: `MarketFacilitationIndex().batch(high, low, volume)` returns a 1-D -`np.ndarray` with `NaN` for zero-volume bars. Node: same; +`array.array('d')` with `NaN` for zero-volume bars. Node: same; `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-Marubozu.md b/Indicators/Indicator-Marubozu.md index 55d6a77..84122dd 100644 --- a/Indicators/Indicator-Marubozu.md +++ b/Indicators/Indicator-Marubozu.md @@ -56,7 +56,7 @@ occupy a single dimension. ## Inputs / Outputs `Indicator`. Python: `Marubozu(tol).batch(open, high, low, close)` -returns a 1-D `np.ndarray`. Node: same; `update(candle)` returns +returns an `array.array('d')`. Node: same; `update(candle)` returns `number | null`. ## Warmup @@ -98,7 +98,7 @@ h = np.array([110.05]) l = np.array([99.95]) c = np.array([110.0]) -m = ta.Marubozu(0.05) +m = ta.Marubozu() print(m.batch(o, h, l, c)) ``` diff --git a/Indicators/Indicator-MatHold.md b/Indicators/Indicator-MatHold.md index f095210..fa6aeff 100644 --- a/Indicators/Indicator-MatHold.md +++ b/Indicators/Indicator-MatHold.md @@ -58,7 +58,7 @@ const _: fn(&mut MatHold, Candle) -> Option = ::updat - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-MatchingLow.md b/Indicators/Indicator-MatchingLow.md index da1bb15..321af37 100644 --- a/Indicators/Indicator-MatchingLow.md +++ b/Indicators/Indicator-MatchingLow.md @@ -49,7 +49,7 @@ const _: fn(&mut MatchingLow, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-McClellanOscillator.md b/Indicators/Indicator-McClellanOscillator.md index 21f3695..cb41b88 100644 --- a/Indicators/Indicator-McClellanOscillator.md +++ b/Indicators/Indicator-McClellanOscillator.md @@ -56,7 +56,7 @@ const _: fn(&mut McClellanOscillator, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-McClellanSummationIndex.md b/Indicators/Indicator-McClellanSummationIndex.md index 0cc546f..c733130 100644 --- a/Indicators/Indicator-McClellanSummationIndex.md +++ b/Indicators/Indicator-McClellanSummationIndex.md @@ -52,7 +52,7 @@ const _: fn(&mut McClellanSummationIndex, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-McGinleyDynamic.md b/Indicators/Indicator-McGinleyDynamic.md index cdefafe..c354441 100644 --- a/Indicators/Indicator-McGinleyDynamic.md +++ b/Indicators/Indicator-McGinleyDynamic.md @@ -47,7 +47,7 @@ const _: fn(&mut McGinleyDynamic, f64) -> Option = ` out. Python maps this to -`float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +`float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-MedianChannel.md b/Indicators/Indicator-MedianChannel.md index 2e7b92c..ee27221 100644 --- a/Indicators/Indicator-MedianChannel.md +++ b/Indicators/Indicator-MedianChannel.md @@ -57,7 +57,7 @@ const _: fn(&mut MedianChannel, f64) -> Option = - **Python streaming.** `update(value)` returns `(upper, middle, lower)` or `None`. - **Python batch.** `MedianChannel.batch(prices)` returns an `(n, 3)` - `np.ndarray` with columns `[upper, middle, lower]`; warmup rows are `NaN`. + `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(value)` returns a `{ upper, middle, lower }` object or `null`. - **Node batch.** `batch(prices)` returns a flat `Array` of length diff --git a/Indicators/Indicator-MedianMa.md b/Indicators/Indicator-MedianMa.md index 49e917a..3e7856c 100644 --- a/Indicators/Indicator-MedianMa.md +++ b/Indicators/Indicator-MedianMa.md @@ -52,7 +52,7 @@ use wickra::{Indicator, MedianMa}; const _: fn(&mut MedianMa, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-Mfi.md b/Indicators/Indicator-Mfi.md index 0a413bd..abf0534 100644 --- a/Indicators/Indicator-Mfi.md +++ b/Indicators/Indicator-Mfi.md @@ -63,7 +63,7 @@ the indicator with a zero-volume candle is legal (every money flow on that bar is zero), but mass zero-volume bars will dilute the sums. Python's `MFI.batch(high, low, close, volume)` returns a 1-D `float64` -`np.ndarray` (warmup → `NaN`). Node's `MFI.batch(high, low, close, +`array.array('d')` (warmup → `NaN`). Node's `MFI.batch(high, low, close, volume)` returns a flat `number[]` (warmup → `NaN`); only `batch` is exposed on the Node binding. diff --git a/Indicators/Indicator-MidPoint.md b/Indicators/Indicator-MidPoint.md index 1559b63..0f6c275 100644 --- a/Indicators/Indicator-MidPoint.md +++ b/Indicators/Indicator-MidPoint.md @@ -47,7 +47,7 @@ use wickra::{Indicator, MidPoint}; const _: fn(&mut MidPoint, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-MidPrice.md b/Indicators/Indicator-MidPrice.md index e21f656..7ff3b61 100644 --- a/Indicators/Indicator-MidPrice.md +++ b/Indicators/Indicator-MidPrice.md @@ -49,7 +49,7 @@ const _: fn(&mut MidPrice, Candle) -> Option = ::upd `MidPrice` is a **candle-input** indicator that reads `high` and `low`. In Python the streaming `update` accepts a candle (dict or tuple); the batch helper -takes `high`, `low`, `close` numpy arrays and returns a 1-D `numpy.ndarray` +takes `high`, `low`, `close` numpy arrays and returns an `array.array('d')` (`NaN` for warmup). Node and WASM expose `update(open, high, low, close)` and the matching `batch`. @@ -122,7 +122,7 @@ Output: const ta = require('wickra'); const mp = new ta.MIDPRICE(3); const bars = [[12, 8, 10], [14, 9, 11], [16, 10, 12]]; -for (const [h, l, c] of bars) console.log(mp.update(c, h, l, c)); +for (const [h, l, c] of bars) console.log(mp.update(h, l, c)); ``` Output: diff --git a/Indicators/Indicator-MinusDi.md b/Indicators/Indicator-MinusDi.md index 646aef3..8970a83 100644 --- a/Indicators/Indicator-MinusDi.md +++ b/Indicators/Indicator-MinusDi.md @@ -12,7 +12,7 @@ | Output type | `f64` | | Output range | `[0, 100]` | | Default parameters | `period` is required | -| Warmup period | `period` (first value at candle index `period`) | +| Warmup period | `period + 1` — the first candle only seeds the previous close (first value at candle index `period`) | | Interpretation | Strength of downward directional movement, normalised by true range; `> +DI` marks a down-trend. | ## Formula @@ -48,13 +48,13 @@ const _: fn(&mut MinusDi, Candle) -> Option = ::updat `MinusDi` is a **candle-input** indicator that reads `high`, `low` and `close`. In Python the streaming `update` accepts a candle; the batch helper takes `high`, -`low`, `close` numpy arrays and returns a 1-D `numpy.ndarray` (`NaN` for warmup). +`low`, `close` numpy arrays and returns an `array.array('d')` (`NaN` for warmup). Node and WASM expose `update(high, low, close)` and the matching `batch`. ## Warmup -`MinusDi::new(period).warmup_period() == period` (the `accessors_report_config` -unit test pins `warmup_period() == 7` for `period = 7`). Because directional +`MinusDi::new(period).warmup_period() == period + 1` (the `accessors_report_config` +unit test pins `warmup_period() == 8` for `period = 7`). Because directional movement and true range both need the previous bar, the **first emitted value** appears at candle index `period`. The `downtrend_drives_minus_di_high` test pins `out[0] == None` and `out[3].is_some()` for `period = 3`. diff --git a/Indicators/Indicator-MinusDm.md b/Indicators/Indicator-MinusDm.md index 00bc0a7..82aa8e5 100644 --- a/Indicators/Indicator-MinusDm.md +++ b/Indicators/Indicator-MinusDm.md @@ -12,7 +12,7 @@ | Output type | `f64` | | Output range | `>= 0` (a smoothed sum of down-moves) | | Default parameters | `period` is required | -| Warmup period | `period` (first value at candle index `period`) | +| Warmup period | `period + 1` — the first candle only seeds the previous close (first value at candle index `period`) | | Interpretation | The accumulated strength of downward directional movement over the window. | ## Formula @@ -56,13 +56,13 @@ const _: fn(&mut MinusDm, Candle) -> Option = ::updat `MinusDm` is a **candle-input** indicator that reads `high` and `low`. In Python the streaming `update` accepts a candle; the batch helper takes `high`, `low`, -`close` numpy arrays and returns a 1-D `numpy.ndarray` (`NaN` for warmup). Node +`close` numpy arrays and returns an `array.array('d')` (`NaN` for warmup). Node and WASM expose `update(high, low, close)` and the matching `batch`. ## Warmup -`MinusDm::new(period).warmup_period() == period` (the `accessors_report_config` -unit test pins `warmup_period() == 7` for `period = 7`). Because a bar's +`MinusDm::new(period).warmup_period() == period + 1` (the `accessors_report_config` +unit test pins `warmup_period() == 8` for `period = 7`). Because a bar's directional movement needs the previous bar, the **first emitted value** appears at candle index `period` — the `(period + 1)`-th candle. The `seeds_then_smooths_a_constant_minus_dm` test pins this: for `period = 3` the diff --git a/Indicators/Indicator-ModifiedMaStop.md b/Indicators/Indicator-ModifiedMaStop.md index 65510d9..c1ecdac 100644 --- a/Indicators/Indicator-ModifiedMaStop.md +++ b/Indicators/Indicator-ModifiedMaStop.md @@ -106,7 +106,7 @@ import wickra as ta m = ta.ModifiedMaStop(14) close = np.arange(60, dtype=float) + 100.0 -value, direction = m.batch(close).T +value, direction = np.asarray(m.batch(close + 1, close - 1, close).tolist()).T print(value[-1], direction[-1]) ``` diff --git a/Indicators/Indicator-Mom.md b/Indicators/Indicator-Mom.md index c9cc217..de000e5 100644 --- a/Indicators/Indicator-Mom.md +++ b/Indicators/Indicator-Mom.md @@ -45,7 +45,7 @@ const _: fn(&mut Mom, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-MorningDojiStar.md b/Indicators/Indicator-MorningDojiStar.md index 595a266..097c0de 100644 --- a/Indicators/Indicator-MorningDojiStar.md +++ b/Indicators/Indicator-MorningDojiStar.md @@ -57,7 +57,7 @@ const _: fn(&mut MorningDojiStar, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-NewHighsNewLows.md b/Indicators/Indicator-NewHighsNewLows.md index b6d98f6..349186c 100644 --- a/Indicators/Indicator-NewHighsNewLows.md +++ b/Indicators/Indicator-NewHighsNewLows.md @@ -49,7 +49,7 @@ This indicator reads the `new_high` / `new_low` flags (not `change` or `volume`) The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; the flag arrays are numeric (non-zero is true). diff --git a/Indicators/Indicator-NewPriceLines.md b/Indicators/Indicator-NewPriceLines.md index 6dc611f..3d1db4d 100644 --- a/Indicators/Indicator-NewPriceLines.md +++ b/Indicators/Indicator-NewPriceLines.md @@ -107,7 +107,7 @@ import wickra as ta n = ta.NewPriceLines(8) close = np.arange(12, dtype=float) + 100 -print(n.batch(close)[-1]) # -1.0 +print(n.batch(close + 1, close - 1, close)[-1]) # -1.0 ``` ### Node @@ -115,7 +115,8 @@ print(n.batch(close)[-1]) # -1.0 ```javascript const ta = require('wickra'); const n = new ta.NewPriceLines(8); -console.log(n.batch(Array.from({length: 12}, (_, i) => 100 + i)).at(-1)); // -1 +const close = Array.from({ length: 12 }, (_, i) => 100 + i); +console.log(n.batch(close.map(c => c + 1), close.map(c => c - 1), close).at(-1)); // -1 ``` ### Streaming diff --git a/Indicators/Indicator-Nrtr.md b/Indicators/Indicator-Nrtr.md index 4063d60..624dbfb 100644 --- a/Indicators/Indicator-Nrtr.md +++ b/Indicators/Indicator-Nrtr.md @@ -109,7 +109,7 @@ import wickra as ta n = ta.Nrtr(2.0) close = np.arange(40, dtype=float) + 100.0 -value, direction = n.batch(close).T +value, direction = np.asarray(n.batch(close + 1, close - 1, close).tolist()).T print(value[-1], direction[-1]) ``` diff --git a/Indicators/Indicator-Nvi.md b/Indicators/Indicator-Nvi.md index 4f469f0..82abe59 100644 --- a/Indicators/Indicator-Nvi.md +++ b/Indicators/Indicator-Nvi.md @@ -39,7 +39,7 @@ None — `Nvi::new()` takes no arguments. ## Inputs / Outputs `Indicator`. Python: -`Nvi().batch(close, volume)` returns a 1-D `np.ndarray`. Node: +`Nvi().batch(close, volume)` returns an `array.array('d')`. Node: same. ## Warmup diff --git a/Indicators/Indicator-Obv.md b/Indicators/Indicator-Obv.md index f580522..922e924 100644 --- a/Indicators/Indicator-Obv.md +++ b/Indicators/Indicator-Obv.md @@ -46,7 +46,7 @@ const _: fn(&mut Obv, Candle) -> Option = ::update; - **Python streaming.** Accepts a 6-tuple or dict candle; returns `float | None`. - **Python batch.** `OBV.batch(close, volume)` takes two equal-length - 1-D `numpy.ndarray` columns and returns a 1-D `np.ndarray`. The + `array.array('d')` columns and returns an `array.array('d')`. The first value is `0.0`, never `NaN`. - **Node streaming.** Not exposed; the Node binding ships only `batch` for `OBV`. diff --git a/Indicators/Indicator-OiToVolumeRatio.md b/Indicators/Indicator-OiToVolumeRatio.md index 423aba9..58f7a70 100644 --- a/Indicators/Indicator-OiToVolumeRatio.md +++ b/Indicators/Indicator-OiToVolumeRatio.md @@ -92,7 +92,7 @@ Some(5.0) ```python import wickra as ta o = ta.OiToVolumeRatio() -print(o.update(0, 100, 100, 100, 5000, 0, 0, 400, 600, 0, 0)) # 5.0 +print(o.update(5000, 400, 600)) # open_interest, taker buy/sell -> 5.0 ``` ### Node diff --git a/Indicators/Indicator-OnNeck.md b/Indicators/Indicator-OnNeck.md index 40e6a11..54e6907 100644 --- a/Indicators/Indicator-OnNeck.md +++ b/Indicators/Indicator-OnNeck.md @@ -53,7 +53,7 @@ const _: fn(&mut OnNeck, Candle) -> Option = ::update; - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-OpeningMarubozu.md b/Indicators/Indicator-OpeningMarubozu.md index 9eda57b..dd96da3 100644 --- a/Indicators/Indicator-OpeningMarubozu.md +++ b/Indicators/Indicator-OpeningMarubozu.md @@ -52,7 +52,7 @@ const _: fn(&mut OpeningMarubozu, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-OrderFlowImbalance.md b/Indicators/Indicator-OrderFlowImbalance.md index 4c5b1db..4a92d59 100644 --- a/Indicators/Indicator-OrderFlowImbalance.md +++ b/Indicators/Indicator-OrderFlowImbalance.md @@ -52,7 +52,7 @@ const _: fn(&mut OrderFlowImbalance, OrderBook) -> Option = Node `update(bidPx[], bidSz[], askPx[], askSz[])` and `batch(snapshots)`; Python `update(bid_px, bid_sz, ask_px, ask_sz)` and `batch(list_of_snapshots)` → 1-D -`ndarray`. Only the best (first) level of each side is read. +`array.array('d')`. Only the best (first) level of each side is read. ## Warmup diff --git a/Indicators/Indicator-OvernightGap.md b/Indicators/Indicator-OvernightGap.md index 15cadf7..a53e792 100644 --- a/Indicators/Indicator-OvernightGap.md +++ b/Indicators/Indicator-OvernightGap.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::OvernightGap, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float | None`; - `batch(...)` → 1-D `ndarray` (`NaN` warmup). + `batch(...)` → `array.array('d')` (`NaN` warmup). - **Node.** `update(...)` → `number | null`; `batch(...)` → `number[]`. - **WASM.** `update(...)` → `number | undefined`. diff --git a/Indicators/Indicator-PairSpreadZScore.md b/Indicators/Indicator-PairSpreadZScore.md index c324e4e..f412108 100644 --- a/Indicators/Indicator-PairSpreadZScore.md +++ b/Indicators/Indicator-PairSpreadZScore.md @@ -40,7 +40,7 @@ moments. See `crates/wickra-core/src/indicators/pair_spread_zscore.rs`. `Indicator`. Feed positive prices `(a, b)`. Python: `PairSpreadZScore(beta_period, z_period).batch(a, b)` → 1-D -`np.ndarray` with `NaN` warmup. Node and WASM expose `update(a, b)`. +`array.array('d')` with `NaN` warmup. Node and WASM expose `update(a, b)`. ## Warmup diff --git a/Indicators/Indicator-PairwiseBeta.md b/Indicators/Indicator-PairwiseBeta.md index 8243bea..ed0eb6a 100644 --- a/Indicators/Indicator-PairwiseBeta.md +++ b/Indicators/Indicator-PairwiseBeta.md @@ -39,7 +39,7 @@ See `crates/wickra-core/src/indicators/pairwise_beta.rs`. `Indicator`. Feed **raw prices** `(a, b)`; the indicator forms the log-returns for you. Python: -`PairwiseBeta(period).batch(a, b)` returns a 1-D `np.ndarray` with `NaN` +`PairwiseBeta(period).batch(a, b)` returns an `array.array('d')` with `NaN` warmup. Node and WASM expose the same `update(a, b)` / `batch(a, b)` shape. ## Warmup diff --git a/Indicators/Indicator-ParkinsonVolatility.md b/Indicators/Indicator-ParkinsonVolatility.md index e20a7af..2823c79 100644 --- a/Indicators/Indicator-ParkinsonVolatility.md +++ b/Indicators/Indicator-ParkinsonVolatility.md @@ -55,7 +55,7 @@ const _: fn(&mut ParkinsonVolatility, Candle) -> Option = ` with `NaN` warmup. diff --git a/Indicators/Indicator-PearsonCorrelation.md b/Indicators/Indicator-PearsonCorrelation.md index 77fddcf..d1b17be 100644 --- a/Indicators/Indicator-PearsonCorrelation.md +++ b/Indicators/Indicator-PearsonCorrelation.md @@ -38,7 +38,7 @@ Each `update` is O(1) via running sums. See ## Inputs / Outputs `Indicator`. Python: -`PearsonCorrelation(period).batch(x, y)` returns 1-D `np.ndarray`. +`PearsonCorrelation(period).batch(x, y)` returns `array.array('d')`. ## Warmup diff --git a/Indicators/Indicator-PercentAboveMa.md b/Indicators/Indicator-PercentAboveMa.md index 8e58a21..b8de83c 100644 --- a/Indicators/Indicator-PercentAboveMa.md +++ b/Indicators/Indicator-PercentAboveMa.md @@ -52,7 +52,7 @@ members with `Member::with_signals(change, volume, new_high, new_low, above_ma, on_buy_signal)`. - **Python**: `update(change, volume, new_high, new_low, above_ma)`; `batch(...)` - takes five array groups per tick and returns a 1-D `ndarray`. + takes five array groups per tick and returns an `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow, aboveMa)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow, aboveMa)` only; every array is diff --git a/Indicators/Indicator-PercentB.md b/Indicators/Indicator-PercentB.md index 8812c2e..8c1e112 100644 --- a/Indicators/Indicator-PercentB.md +++ b/Indicators/Indicator-PercentB.md @@ -48,7 +48,7 @@ const _: fn(&mut PercentB, f64) -> Option = ::update ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-PercentageTrailingStop.md b/Indicators/Indicator-PercentageTrailingStop.md index 4c5215a..e27f397 100644 --- a/Indicators/Indicator-PercentageTrailingStop.md +++ b/Indicators/Indicator-PercentageTrailingStop.md @@ -48,7 +48,7 @@ for non-finite or non-positive `percent`. `Indicator`. Python: `PercentageTrailingStop(percent).batch(close)` returns a 1-D -`np.ndarray` — no warmup `NaN`s because the indicator emits on the +`array.array('d')` — no warmup `NaN`s because the indicator emits on the first input. Node: same shape; `update(close)` returns `number`. ## Warmup diff --git a/Indicators/Indicator-PerpetualPremiumIndex.md b/Indicators/Indicator-PerpetualPremiumIndex.md index 390c95a..104c019 100644 --- a/Indicators/Indicator-PerpetualPremiumIndex.md +++ b/Indicators/Indicator-PerpetualPremiumIndex.md @@ -89,7 +89,7 @@ Some(0.01) ```python import wickra as ta p = ta.PerpetualPremiumIndex() -print(p.update(0, 101, 100, 101, 0, 0, 0, 0, 0, 0, 0)) # 0.01 +print(p.update(101, 100)) # mark_price, index_price -> 0.01 ``` ### Node @@ -97,7 +97,7 @@ print(p.update(0, 101, 100, 101, 0, 0, 0, 0, 0, 0, 0)) # 0.01 ```javascript const ta = require('wickra'); const p = new ta.PerpetualPremiumIndex(); -console.log(p.update(0, 101, 100, 101, 0, 0, 0, 0, 0, 0, 0)); // 0.01 +console.log(p.update(101, 100)); // markPrice, indexPrice -> 0.01 ``` ### Streaming diff --git a/Indicators/Indicator-Pgo.md b/Indicators/Indicator-Pgo.md index 0931a8d..731d3f8 100644 --- a/Indicators/Indicator-Pgo.md +++ b/Indicators/Indicator-Pgo.md @@ -47,7 +47,7 @@ const _: fn(&mut Pgo, Candle) -> Option = ::update; ``` - **Python.** `update(candle)` returns `float | None`; - `batch(high, low, close)` returns a 1-D `float64` `np.ndarray` with `NaN` + `batch(high, low, close)` returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(high, low, close)` returns `number | null`; `batch(high, low, close)` returns an `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-PlusDi.md b/Indicators/Indicator-PlusDi.md index 05694f8..c9b7a9d 100644 --- a/Indicators/Indicator-PlusDi.md +++ b/Indicators/Indicator-PlusDi.md @@ -12,7 +12,7 @@ | Output type | `f64` | | Output range | `[0, 100]` | | Default parameters | `period` is required | -| Warmup period | `period` (first value at candle index `period`) | +| Warmup period | `period + 1` — the first candle only seeds the previous close (first value at candle index `period`) | | Interpretation | Strength of upward directional movement, normalised by true range; `> −DI` marks an up-trend. | ## Formula @@ -49,13 +49,13 @@ const _: fn(&mut PlusDi, Candle) -> Option = ::update; `PlusDi` is a **candle-input** indicator that reads `high`, `low` and `close` (the last for true range). In Python the streaming `update` accepts a candle; the batch helper takes `high`, `low`, `close` numpy arrays and returns a 1-D -`numpy.ndarray` (`NaN` for warmup). Node and WASM expose `update(high, low, +`array.array('d')` (`NaN` for warmup). Node and WASM expose `update(high, low, close)` and the matching `batch`. ## Warmup -`PlusDi::new(period).warmup_period() == period` (the `accessors_report_config` -unit test pins `warmup_period() == 7` for `period = 7`). Because directional +`PlusDi::new(period).warmup_period() == period + 1` (the `accessors_report_config` +unit test pins `warmup_period() == 8` for `period = 7`). Because directional movement and true range both need the previous bar, the **first emitted value** appears at candle index `period`. The `uptrend_drives_plus_di_high` test pins `out[0] == None` and `out[3].is_some()` for `period = 3`. diff --git a/Indicators/Indicator-PlusDm.md b/Indicators/Indicator-PlusDm.md index 0498b7f..90fa29d 100644 --- a/Indicators/Indicator-PlusDm.md +++ b/Indicators/Indicator-PlusDm.md @@ -12,7 +12,7 @@ | Output type | `f64` | | Output range | `>= 0` (a smoothed sum of up-moves) | | Default parameters | `period` is required | -| Warmup period | `period` (first value at candle index `period`) | +| Warmup period | `period + 1` — the first candle only seeds the previous close (first value at candle index `period`) | | Interpretation | The accumulated strength of upward directional movement over the window. | ## Formula @@ -56,13 +56,13 @@ const _: fn(&mut PlusDm, Candle) -> Option = ::update; `PlusDm` is a **candle-input** indicator that reads `high` and `low`. In Python the streaming `update` accepts a candle; the batch helper takes `high`, `low`, -`close` numpy arrays and returns a 1-D `numpy.ndarray` (`NaN` for warmup). Node +`close` numpy arrays and returns an `array.array('d')` (`NaN` for warmup). Node and WASM expose `update(high, low, close)` and the matching `batch`. ## Warmup -`PlusDm::new(period).warmup_period() == period` (the `accessors_report_config` -unit test pins `warmup_period() == 7` for `period = 7`). Because a bar's +`PlusDm::new(period).warmup_period() == period + 1` (the `accessors_report_config` +unit test pins `warmup_period() == 8` for `period = 7`). Because a bar's directional movement needs the previous bar, the **first emitted value** appears at candle index `period` — the `(period + 1)`-th candle. The `seeds_then_smooths_a_constant_plus_dm` test pins this: for `period = 3` the diff --git a/Indicators/Indicator-Pmo.md b/Indicators/Indicator-Pmo.md index f007e44..dc0038c 100644 --- a/Indicators/Indicator-Pmo.md +++ b/Indicators/Indicator-Pmo.md @@ -55,7 +55,7 @@ const _: fn(&mut Pmo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-PolarizedFractalEfficiency.md b/Indicators/Indicator-PolarizedFractalEfficiency.md index 56d6e4d..8d2677d 100644 --- a/Indicators/Indicator-PolarizedFractalEfficiency.md +++ b/Indicators/Indicator-PolarizedFractalEfficiency.md @@ -60,7 +60,7 @@ const _: fn(&mut PolarizedFractalEfficiency, f64) -> Option = ``` Scalar in, scalar out. Python returns `float | None` (streaming) / -`numpy.ndarray` (batch, `NaN` for warmup). Node returns `number | null` / +`array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-Ppo.md b/Indicators/Indicator-Ppo.md index c5ba5ac..95d3e2a 100644 --- a/Indicators/Indicator-Ppo.md +++ b/Indicators/Indicator-Ppo.md @@ -52,7 +52,7 @@ const _: fn(&mut Ppo, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-PpoHistogram.md b/Indicators/Indicator-PpoHistogram.md index b411abe..2f8023d 100644 --- a/Indicators/Indicator-PpoHistogram.md +++ b/Indicators/Indicator-PpoHistogram.md @@ -53,7 +53,7 @@ const _: fn(&mut PpoHistogram, f64) -> Option = ``` A single `f64` close in, an `Option` out (percentage-point histogram). -Python maps this to `float | None` / a `float64` `np.ndarray` with `NaN` +Python maps this to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array` with `NaN` warmup. ## Warmup diff --git a/Indicators/Indicator-ProjectionBands.md b/Indicators/Indicator-ProjectionBands.md index d47ea21..2277cea 100644 --- a/Indicators/Indicator-ProjectionBands.md +++ b/Indicators/Indicator-ProjectionBands.md @@ -56,7 +56,7 @@ const _: fn(&mut ProjectionBands, Candle) -> Option = - **Python streaming.** `update(candle)` returns `(upper, middle, lower)` or `None`. - **Python batch.** `ProjectionBands.batch(high, low)` returns an `(n, 3)` - `np.ndarray` with columns `[upper, middle, lower]`; warmup rows are `NaN`. + `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(high, low)` returns a `{ upper, middle, lower }` object or `null`. - **Node batch.** `batch(high, low)` returns a flat `Array` of length diff --git a/Indicators/Indicator-ProjectionOscillator.md b/Indicators/Indicator-ProjectionOscillator.md index 7c4a132..65235f8 100644 --- a/Indicators/Indicator-ProjectionOscillator.md +++ b/Indicators/Indicator-ProjectionOscillator.md @@ -50,7 +50,7 @@ const _: fn(&mut ProjectionOscillator, Candle) -> Option = - **Python streaming.** `update(candle)` returns a `float` or `None`. - **Python batch.** `ProjectionOscillator.batch(high, low, close)` returns a - 1-D `np.ndarray`; warmup rows are `NaN`. + `array.array('d')`; warmup rows are `NaN`. - **Node streaming.** `update(high, low, close)` returns a `number` or `null`. - **Node batch.** `batch(high, low, close)` returns a flat `Array`. diff --git a/Indicators/Indicator-Psar.md b/Indicators/Indicator-Psar.md index 2e72326..f0a60d9 100644 --- a/Indicators/Indicator-Psar.md +++ b/Indicators/Indicator-Psar.md @@ -72,7 +72,7 @@ const _: fn(&mut Psar, Candle) -> Option = ::update; - **Python streaming.** `psar.update(candle)` returns `float | None`. - **Python batch.** `PSAR.batch(high, low, close)` returns a 1-D - `np.ndarray`; the first row is `NaN` (warmup) and every subsequent + `array.array('d')`; the first row is `NaN` (warmup) and every subsequent row holds the SAR level for that bar. - **Node streaming.** `psar.update(high, low, close)` returns `number | null`. - **Node batch.** `psar.batch(high, low, close)` returns diff --git a/Indicators/Indicator-Qqe.md b/Indicators/Indicator-Qqe.md index ab6794e..97118e4 100644 --- a/Indicators/Indicator-Qqe.md +++ b/Indicators/Indicator-Qqe.md @@ -65,7 +65,7 @@ Two outputs per bar. Node: `update(value)` returns `{ rsiMa, trailingLine } | null`; `batch(values)` returns a flat `Array` of length `n*2` (`[rsiMa, trailingLine, …]`, `NaN` for warmup). Python: `update(value)` returns `(rsi_ma, trailing_line) | None`; `batch(values)` returns -an `(n, 2)` `ndarray`. +an `(n, 2)` `Matrix`. ## Warmup diff --git a/Indicators/Indicator-Qstick.md b/Indicators/Indicator-Qstick.md index 6f6a247..09feb49 100644 --- a/Indicators/Indicator-Qstick.md +++ b/Indicators/Indicator-Qstick.md @@ -50,7 +50,7 @@ const _: fn(&mut Qstick, Candle) -> Option = ::update; Qstick reads only the **open** and **close** (the candle body), so the batch bindings take those two columns. Node: `update(open, close)` / `batch(open[], close[])`. Python: `update(candle)` (a full candle object) / -`batch(open, close)` → 1-D `ndarray` (`NaN` for warmup). Node returns +`batch(open, close)` → `array.array('d')` (`NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-QuartileBands.md b/Indicators/Indicator-QuartileBands.md index 79dfbba..a79c432 100644 --- a/Indicators/Indicator-QuartileBands.md +++ b/Indicators/Indicator-QuartileBands.md @@ -54,7 +54,7 @@ const _: fn(&mut QuartileBands, f64) -> Option = - **Python streaming.** `update(value)` returns `(upper, middle, lower)` or `None`. - **Python batch.** `QuartileBands.batch(prices)` returns an `(n, 3)` - `np.ndarray` with columns `[upper, middle, lower]`; warmup rows are `NaN`. + `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(value)` returns a `{ upper, middle, lower }` object or `null`. - **Node batch.** `batch(prices)` returns a flat `Array` of length diff --git a/Indicators/Indicator-RangeBars.md b/Indicators/Indicator-RangeBars.md index 1eaa657..5b01b99 100644 --- a/Indicators/Indicator-RangeBars.md +++ b/Indicators/Indicator-RangeBars.md @@ -53,7 +53,7 @@ const _: fn(&mut RangeBars, Candle) -> Vec = A `Candle` in, a `Vec` out (empty until a full `range` is travelled). Bar builders are **close-driven** in the bindings: Python `update(close) -> list[tuple]` -and `batch(closes) -> ndarray (k, 3)`; Node `update(close) -> RangeBar[]`. There is +and `batch(closes) -> Matrix (k, 3)`; Node `update(close) -> RangeBar[]`. There is no `warmupPeriod`/`isReady` — a `BarBuilder` emits whenever a bar completes. ## Edge cases diff --git a/Indicators/Indicator-RealizedVolatility.md b/Indicators/Indicator-RealizedVolatility.md index f732650..e68a037 100644 --- a/Indicators/Indicator-RealizedVolatility.md +++ b/Indicators/Indicator-RealizedVolatility.md @@ -49,7 +49,7 @@ const _: fn(&mut RealizedVolatility, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-RectangleRange.md b/Indicators/Indicator-RectangleRange.md index e9b0b5d..6c1c971 100644 --- a/Indicators/Indicator-RectangleRange.md +++ b/Indicators/Indicator-RectangleRange.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::RectangleRange, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-RegimeLabel.md b/Indicators/Indicator-RegimeLabel.md index 675e87e..95a3b20 100644 --- a/Indicators/Indicator-RegimeLabel.md +++ b/Indicators/Indicator-RegimeLabel.md @@ -53,7 +53,7 @@ use wickra::{Indicator, RegimeLabel}; const _: fn(&mut RegimeLabel, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-RenkoTrailingStop.md b/Indicators/Indicator-RenkoTrailingStop.md index 1dcf58b..7e6cf77 100644 --- a/Indicators/Indicator-RenkoTrailingStop.md +++ b/Indicators/Indicator-RenkoTrailingStop.md @@ -57,7 +57,7 @@ non-finite or non-positive `block_size`. ## Inputs / Outputs `Indicator`. Python: -`RenkoTrailingStop(block).batch(close)` returns a 1-D `np.ndarray` +`RenkoTrailingStop(block).batch(close)` returns an `array.array('d')` without warmup `NaN`s. Node: same shape; `update(close)` returns `number`. diff --git a/Indicators/Indicator-RickshawMan.md b/Indicators/Indicator-RickshawMan.md index 4326562..b8db1ed 100644 --- a/Indicators/Indicator-RickshawMan.md +++ b/Indicators/Indicator-RickshawMan.md @@ -52,7 +52,7 @@ const _: fn(&mut RickshawMan, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-RisingThreeMethods.md b/Indicators/Indicator-RisingThreeMethods.md index eb9ba71..a7bfd22 100644 --- a/Indicators/Indicator-RisingThreeMethods.md +++ b/Indicators/Indicator-RisingThreeMethods.md @@ -52,7 +52,7 @@ const _: fn(&mut RisingThreeMethods, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Rmi.md b/Indicators/Indicator-Rmi.md index 31bc12c..4978d5f 100644 --- a/Indicators/Indicator-Rmi.md +++ b/Indicators/Indicator-Rmi.md @@ -52,7 +52,7 @@ use wickra::{Indicator, Rmi}; const _: fn(&mut Rmi, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-Roc.md b/Indicators/Indicator-Roc.md index 1190ba8..666d43a 100644 --- a/Indicators/Indicator-Roc.md +++ b/Indicators/Indicator-Roc.md @@ -45,7 +45,7 @@ use wickra::{Indicator, Roc}; const _: fn(&mut Roc, f64) -> Option = ::update; ``` -Python's `ROC.batch(prices)` returns a 1-D `float64` `np.ndarray`. Node's +Python's `ROC.batch(prices)` returns an `array.array('d')`. Node's `ROC.batch(prices)` returns a flat `number[]`. Streaming `update(price)` returns a scalar (`float` / `number`) or `None` / `null` during warmup. diff --git a/Indicators/Indicator-Rocp.md b/Indicators/Indicator-Rocp.md index 37cc6bb..ab9bbf9 100644 --- a/Indicators/Indicator-Rocp.md +++ b/Indicators/Indicator-Rocp.md @@ -45,7 +45,7 @@ use wickra::{Indicator, Rocp}; const _: fn(&mut Rocp, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-Rocr.md b/Indicators/Indicator-Rocr.md index 7f067ef..6bcc8b5 100644 --- a/Indicators/Indicator-Rocr.md +++ b/Indicators/Indicator-Rocr.md @@ -45,7 +45,7 @@ use wickra::{Indicator, Rocr}; const _: fn(&mut Rocr, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-Rocr100.md b/Indicators/Indicator-Rocr100.md index c1b7b75..9ae8666 100644 --- a/Indicators/Indicator-Rocr100.md +++ b/Indicators/Indicator-Rocr100.md @@ -45,7 +45,7 @@ use wickra::{Indicator, Rocr100}; const _: fn(&mut Rocr100, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-RogersSatchellVolatility.md b/Indicators/Indicator-RogersSatchellVolatility.md index 3f7350c..bf3c157 100644 --- a/Indicators/Indicator-RogersSatchellVolatility.md +++ b/Indicators/Indicator-RogersSatchellVolatility.md @@ -51,7 +51,7 @@ const _: fn(&mut RogersSatchellVolatility, Candle) -> Option = ` with `NaN` diff --git a/Indicators/Indicator-RollMeasure.md b/Indicators/Indicator-RollMeasure.md index db0b450..075b729 100644 --- a/Indicators/Indicator-RollMeasure.md +++ b/Indicators/Indicator-RollMeasure.md @@ -49,7 +49,7 @@ const _: fn(&mut RollMeasure, Trade) -> Option = ``` Node `update(price, size, isBuy)` and `batch(price[], size[], isBuy[])`; Python -`update(price, size, is_buy)` and `batch(price, size, is_buy)` → 1-D `ndarray`. +`update(price, size, is_buy)` and `batch(price, size, is_buy)` → `array.array('d')`. (Size and side are accepted for a uniform trade API but only the price is used.) ## Warmup diff --git a/Indicators/Indicator-RollingIqr.md b/Indicators/Indicator-RollingIqr.md index 058b2e2..ea32e5a 100644 --- a/Indicators/Indicator-RollingIqr.md +++ b/Indicators/Indicator-RollingIqr.md @@ -44,7 +44,7 @@ use wickra::{Indicator, RollingIqr}; const _: fn(&mut RollingIqr, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-RollingPercentileRank.md b/Indicators/Indicator-RollingPercentileRank.md index a4b5f25..8b29ce5 100644 --- a/Indicators/Indicator-RollingPercentileRank.md +++ b/Indicators/Indicator-RollingPercentileRank.md @@ -46,7 +46,7 @@ const _: fn(&mut RollingPercentileRank, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-RollingQuantile.md b/Indicators/Indicator-RollingQuantile.md index 403efdc..654e5f8 100644 --- a/Indicators/Indicator-RollingQuantile.md +++ b/Indicators/Indicator-RollingQuantile.md @@ -50,7 +50,7 @@ const _: fn(&mut RollingQuantile, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-RollingVwap.md b/Indicators/Indicator-RollingVwap.md index 1926c0c..93e22b3 100644 --- a/Indicators/Indicator-RollingVwap.md +++ b/Indicators/Indicator-RollingVwap.md @@ -40,7 +40,7 @@ is O(1). See ## Inputs / Outputs `Indicator`. Python: `RollingVWAP(period).batch(high, low, close, volume)` -returns a 1-D `np.ndarray` with `NaN` warmup. Node: same; `update(candle)` +returns an `array.array('d')` with `NaN` warmup. Node: same; `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-RoofingFilter.md b/Indicators/Indicator-RoofingFilter.md index 37ac7ba..4a81f6c 100644 --- a/Indicators/Indicator-RoofingFilter.md +++ b/Indicators/Indicator-RoofingFilter.md @@ -48,7 +48,7 @@ and `Error::InvalidPeriod` for `lp_period >= hp_period`. ## Inputs / Outputs `Indicator`. Python: -`RoofingFilter(lp, hp).batch(prices)` returns a 1-D `np.ndarray`. +`RoofingFilter(lp, hp).batch(prices)` returns an `array.array('d')`. Node: same shape; `update(value)` returns `number`. ## Warmup diff --git a/Indicators/Indicator-Rsi.md b/Indicators/Indicator-Rsi.md index d8e8a04..2dfd28b 100644 --- a/Indicators/Indicator-Rsi.md +++ b/Indicators/Indicator-Rsi.md @@ -55,7 +55,7 @@ const _: fn(&mut Rsi, f64) -> Option = ::update; ``` The output is a scalar in `[0, 100]`. In Python `batch(prices)` returns a -1-D `np.ndarray` of `float64`, with `NaN` in the warmup positions. In Node +`array.array('d')`, with `NaN` in the warmup positions. In Node `batch(prices)` returns a flat `number[]`, also `NaN` during warmup. ## Warmup diff --git a/Indicators/Indicator-Rsx.md b/Indicators/Indicator-Rsx.md index ed751aa..7612f60 100644 --- a/Indicators/Indicator-Rsx.md +++ b/Indicators/Indicator-Rsx.md @@ -55,7 +55,7 @@ use wickra::{Indicator, Rsx}; const _: fn(&mut Rsx, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-RunBars.md b/Indicators/Indicator-RunBars.md index b3e1e66..8b86b67 100644 --- a/Indicators/Indicator-RunBars.md +++ b/Indicators/Indicator-RunBars.md @@ -112,8 +112,8 @@ import wickra as ta bars = ta.RunBars(3) for p in (10.0, 11.0, 12.0): - bars.update(p) -print(bars.update(13.0)) # [(10.0, 13.0, 10.0, 13.0, 3, 1)] + bars.update(p, p, p, p) +print(bars.update(13.0, 13.0, 13.0, 13.0)) # [(10.0, 13.0, 10.0, 13.0, 3, 1)] ``` ### Node @@ -121,8 +121,8 @@ print(bars.update(13.0)) # [(10.0, 13.0, 10.0, 13.0, 3, 1)] ```javascript const ta = require('wickra'); const bars = new ta.RunBars(3); -[10.0, 11.0, 12.0].forEach((p) => bars.update(p)); -console.log(bars.update(13.0)[0].direction); // 1 +[10.0, 11.0, 12.0].forEach((p) => bars.update(p, p, p, p)); +console.log(bars.update(13.0, 13.0, 13.0, 13.0)[0].direction); // 1 ``` ### Streaming diff --git a/Indicators/Indicator-Rvi.md b/Indicators/Indicator-Rvi.md index 926f434..4442510 100644 --- a/Indicators/Indicator-Rvi.md +++ b/Indicators/Indicator-Rvi.md @@ -54,7 +54,7 @@ const _: fn(&mut Rvi, Candle) -> Option = ::update; Uses all four OHLC fields. - **Python.** `update(candle)` returns `float | None`; - `batch(open, high, low, close)` returns a 1-D `float64` `np.ndarray` with + `batch(open, high, low, close)` returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(open, high, low, close)` returns `number | null`; `batch(open, high, low, close)` returns an `Array` with `NaN` diff --git a/Indicators/Indicator-RviVolatility.md b/Indicators/Indicator-RviVolatility.md index 0bc8f03..dddebc1 100644 --- a/Indicators/Indicator-RviVolatility.md +++ b/Indicators/Indicator-RviVolatility.md @@ -57,7 +57,7 @@ const _: fn(&mut RviVolatility, f64) -> Option = ` out in `[0, 100]`. Python maps this -to `float | None` (`RVIVolatility.update`) / a `float64` `np.ndarray` with +to `float | None` (`RVIVolatility.update`) / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-Rwi.md b/Indicators/Indicator-Rwi.md index c4061b0..7f796f3 100644 --- a/Indicators/Indicator-Rwi.md +++ b/Indicators/Indicator-Rwi.md @@ -58,7 +58,7 @@ const _: fn(&mut Rwi, Candle) -> Option = ::update; ``` - **Python.** `update(candle)` returns `(high, low)` or `None`; - `batch(high, low, close)` returns an `(n, 2)` `np.ndarray` with columns + `batch(high, low, close)` returns an `(n, 2)` `Matrix` with columns `[high, low]`; warmup rows are `NaN`. - **Node.** `update(high, low, close)` returns a `{ high, low }` object or `null`; `batch(high, low, close)` returns a flat `Array` of length diff --git a/Indicators/Indicator-SeasonalZScore.md b/Indicators/Indicator-SeasonalZScore.md index 215db98..7dd16b7 100644 --- a/Indicators/Indicator-SeasonalZScore.md +++ b/Indicators/Indicator-SeasonalZScore.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::SeasonalZScore, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float | None`; - `batch(...)` → 1-D `ndarray` (`NaN` until a bucket has two priors). + `batch(...)` → `array.array('d')` (`NaN` until a bucket has two priors). - **Node.** `update(...)` → `number | null`; `batch(...)` → `number[]`. - **WASM.** `update(...)` → `number | undefined`. diff --git a/Indicators/Indicator-SeparatingLines.md b/Indicators/Indicator-SeparatingLines.md index cb975b4..8916a90 100644 --- a/Indicators/Indicator-SeparatingLines.md +++ b/Indicators/Indicator-SeparatingLines.md @@ -53,7 +53,7 @@ const _: fn(&mut SeparatingLines, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-SessionVwap.md b/Indicators/Indicator-SessionVwap.md index d8bdd77..5afd8b6 100644 --- a/Indicators/Indicator-SessionVwap.md +++ b/Indicators/Indicator-SessionVwap.md @@ -45,7 +45,7 @@ const _: fn(&mut wickra::SessionVwap, wickra::Candle) -> Option = ``` - **Python.** `SessionVwap(utc_offset_minutes).update((o,h,l,c,v,ts))`; - `batch(open, high, low, close, volume, timestamp)` → 1-D `ndarray`. + `batch(open, high, low, close, volume, timestamp)` → `array.array('d')`. - **Node.** `update(open, high, low, close, volume, timestamp)`; `batch(...)` → `number[]`. - **WASM.** `update(open, high, low, close, volume, timestamp)` (`timestamp` is a `BigInt`). diff --git a/Indicators/Indicator-Shark.md b/Indicators/Indicator-Shark.md index ecb00b1..ab07ebc 100644 --- a/Indicators/Indicator-Shark.md +++ b/Indicators/Indicator-Shark.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::Shark, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-SharpeRatio.md b/Indicators/Indicator-SharpeRatio.md index 990d9e0..2ee731e 100644 --- a/Indicators/Indicator-SharpeRatio.md +++ b/Indicators/Indicator-SharpeRatio.md @@ -43,7 +43,7 @@ annualised Sharpe. See ## Inputs / Outputs `Indicator`. Python: -`SharpeRatio(period, rf).batch(returns)` returns a 1-D `np.ndarray` +`SharpeRatio(period, rf).batch(returns)` returns an `array.array('d')` with `NaN` for the warmup prefix. Node: same shape; `update(return)` returns `number | null`. diff --git a/Indicators/Indicator-ShortLine.md b/Indicators/Indicator-ShortLine.md index 9406023..5f0d8c3 100644 --- a/Indicators/Indicator-ShortLine.md +++ b/Indicators/Indicator-ShortLine.md @@ -55,7 +55,7 @@ const _: fn(&mut ShortLine, Candle) -> Option = ::u - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` while the rolling average fills). + `array.array('d')` (`0.0` while the rolling average fills). ## Warmup diff --git a/Indicators/Indicator-SineWave.md b/Indicators/Indicator-SineWave.md index 451a172..d10b79a 100644 --- a/Indicators/Indicator-SineWave.md +++ b/Indicators/Indicator-SineWave.md @@ -50,7 +50,7 @@ let px = 100.0; let sine = sw.update(px); // Option ``` -Python: `SineWave().batch(prices)` returns a 1-D `np.ndarray` of the +Python: `SineWave().batch(prices)` returns an `array.array('d')` of the sine line. Node and WASM return the same single sine line. ## Warmup diff --git a/Indicators/Indicator-SineWeightedMa.md b/Indicators/Indicator-SineWeightedMa.md index 65685ae..530ca50 100644 --- a/Indicators/Indicator-SineWeightedMa.md +++ b/Indicators/Indicator-SineWeightedMa.md @@ -55,7 +55,7 @@ const _: fn(&mut SineWeightedMa, f64) -> Option = ::update; ``` -Python returns `float | None` (streaming) / `numpy.ndarray` (batch, `NaN` for +Python returns `float | None` (streaming) / `array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-Sma.md b/Indicators/Indicator-Sma.md index d64cc03..db81773 100644 --- a/Indicators/Indicator-Sma.md +++ b/Indicators/Indicator-Sma.md @@ -50,8 +50,8 @@ const _: fn(&mut Sma, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. The Python binding maps -this to `float | None` (streaming) or a `numpy.ndarray` of dtype -`float64` with `NaN` for warmup rows (batch). The Node binding maps it to +this to `float | None` (streaming) or an `array.array('d')` with `NaN` for +warmup rows (batch). The Node binding maps it to `number | null` / `Array` with `NaN` for warmup. ## Warmup diff --git a/Indicators/Indicator-Smi.md b/Indicators/Indicator-Smi.md index e3caa91..e546402 100644 --- a/Indicators/Indicator-Smi.md +++ b/Indicators/Indicator-Smi.md @@ -59,7 +59,7 @@ const _: fn(&mut Smi, Candle) -> Option = ::update; Uses `high`, `low`, `close`. - **Python.** `update(candle)` returns `float | None`; - `batch(high, low, close)` returns a 1-D `float64` `np.ndarray` with `NaN` + `batch(high, low, close)` returns an `array.array('d')` with `NaN` warmup. - **Node.** `update(high, low, close)` returns `number | null`; `batch(high, low, close)` returns an `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-Smma.md b/Indicators/Indicator-Smma.md index e03a649..fc32d5a 100644 --- a/Indicators/Indicator-Smma.md +++ b/Indicators/Indicator-Smma.md @@ -47,7 +47,7 @@ const _: fn(&mut Smma, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` (streaming) or a `numpy.ndarray` with `NaN` warmup rows +`float | None` (streaming) or an `array.array('d')` with `NaN` warmup rows (batch); Node maps it to `number | null` / `Array` with `NaN` warmup. diff --git a/Indicators/Indicator-SpinningTop.md b/Indicators/Indicator-SpinningTop.md index 8cb264c..c19b50a 100644 --- a/Indicators/Indicator-SpinningTop.md +++ b/Indicators/Indicator-SpinningTop.md @@ -102,7 +102,7 @@ h = np.array([103.0]) l = np.array([ 97.0]) c = np.array([100.5]) -st = ta.SpinningTop(0.3) +st = ta.SpinningTop() print(st.batch(o, h, l, c)) ``` diff --git a/Indicators/Indicator-StalledPattern.md b/Indicators/Indicator-StalledPattern.md index 6346561..cdb7dde 100644 --- a/Indicators/Indicator-StalledPattern.md +++ b/Indicators/Indicator-StalledPattern.md @@ -53,7 +53,7 @@ const _: fn(&mut StalledPattern, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-StandardErrorBands.md b/Indicators/Indicator-StandardErrorBands.md index 0506b6b..75eb0ee 100644 --- a/Indicators/Indicator-StandardErrorBands.md +++ b/Indicators/Indicator-StandardErrorBands.md @@ -60,7 +60,7 @@ const _: fn(&mut StandardErrorBands, f64) -> Option = - **Python streaming.** `update(value)` returns `(upper, middle, lower)` or `None`. - **Python batch.** `StandardErrorBands.batch(prices)` returns an `(n, 3)` - `np.ndarray` with columns `[upper, middle, lower]`; warmup rows are `NaN`. + `Matrix` with columns `[upper, middle, lower]`; warmup rows are `NaN`. - **Node streaming.** `update(value)` returns a `{ upper, middle, lower }` object or `null`. - **Node batch.** `batch(prices)` returns a flat `Array` of length diff --git a/Indicators/Indicator-StarcBands.md b/Indicators/Indicator-StarcBands.md index 31cc2b3..fb7b475 100644 --- a/Indicators/Indicator-StarcBands.md +++ b/Indicators/Indicator-StarcBands.md @@ -53,7 +53,7 @@ const _: fn(&mut StarcBands, Candle) -> Option = ` diff --git a/Indicators/Indicator-Stc.md b/Indicators/Indicator-Stc.md index bb20618..e6abd62 100644 --- a/Indicators/Indicator-Stc.md +++ b/Indicators/Indicator-Stc.md @@ -57,7 +57,7 @@ const _: fn(&mut Stc, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out in `[0, 100]`. Python maps -this to `float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +this to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-StdDev.md b/Indicators/Indicator-StdDev.md index 63254fd..284eb0e 100644 --- a/Indicators/Indicator-StdDev.md +++ b/Indicators/Indicator-StdDev.md @@ -19,7 +19,7 @@ ``` mean = (1/n) · Σ price -variance = (1/n) · Σ price² − mean² +variance = (1/n) · Σ (price − mean)² StdDev = √variance ``` @@ -50,7 +50,7 @@ const _: fn(&mut StdDev, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup @@ -84,7 +84,7 @@ fn main() -> Result<(), Box> { Output: ``` -[None, None, Some(1.6329931618554525)] +[None, None, Some(1.632993161855452)] ``` The window `[2, 4, 6]` has mean `4` and variance `(4 + 0 + 4) / 3 = 8/3`, diff --git a/Indicators/Indicator-StepTrailingStop.md b/Indicators/Indicator-StepTrailingStop.md index 89af8e1..3cf37dc 100644 --- a/Indicators/Indicator-StepTrailingStop.md +++ b/Indicators/Indicator-StepTrailingStop.md @@ -53,7 +53,7 @@ non-finite or non-positive `step_size`. ## Inputs / Outputs `Indicator`. Python: -`StepTrailingStop(step).batch(close)` returns a 1-D `np.ndarray` +`StepTrailingStop(step).batch(close)` returns an `array.array('d')` without warmup `NaN`s. Node: same shape; `update(close)` returns `number`. diff --git a/Indicators/Indicator-StickSandwich.md b/Indicators/Indicator-StickSandwich.md index 4e93ce2..860efe9 100644 --- a/Indicators/Indicator-StickSandwich.md +++ b/Indicators/Indicator-StickSandwich.md @@ -52,7 +52,7 @@ const _: fn(&mut StickSandwich, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-StochRsi.md b/Indicators/Indicator-StochRsi.md index 362b5ae..b91b246 100644 --- a/Indicators/Indicator-StochRsi.md +++ b/Indicators/Indicator-StochRsi.md @@ -51,7 +51,7 @@ const _: fn(&mut StochRsi, f64) -> Option = ::update ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-StochasticCci.md b/Indicators/Indicator-StochasticCci.md index e4dec2b..185e85c 100644 --- a/Indicators/Indicator-StochasticCci.md +++ b/Indicators/Indicator-StochasticCci.md @@ -51,7 +51,7 @@ const _: fn(&mut StochasticCci, Candle) -> Option = ``` Node: `update(high, low, close)` / `batch(h[], l[], c[])`. Python: -`update(candle)` / `batch(high, low, close)` → 1-D `ndarray` (`NaN` for warmup). +`update(candle)` / `batch(high, low, close)` → `array.array('d')` (`NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-SuperSmoother.md b/Indicators/Indicator-SuperSmoother.md index 395d3ba..31f4914 100644 --- a/Indicators/Indicator-SuperSmoother.md +++ b/Indicators/Indicator-SuperSmoother.md @@ -49,7 +49,7 @@ and `Error::InvalidPeriod` for `period == 1` (no smoothing possible). ## Inputs / Outputs `Indicator`. Python: -`SuperSmoother(period).batch(prices)` returns a 1-D `np.ndarray` +`SuperSmoother(period).batch(prices)` returns an `array.array('d')` without warmup `NaN`s (Ehlers' "pass through input" initial condition). Node: same shape; `update(value)` returns `number`. diff --git a/Indicators/Indicator-T3.md b/Indicators/Indicator-T3.md index 4f2747d..dde83c8 100644 --- a/Indicators/Indicator-T3.md +++ b/Indicators/Indicator-T3.md @@ -57,7 +57,7 @@ const _: fn(&mut T3, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Takuri.md b/Indicators/Indicator-Takuri.md index 39961e8..25000ba 100644 --- a/Indicators/Indicator-Takuri.md +++ b/Indicators/Indicator-Takuri.md @@ -53,7 +53,7 @@ const _: fn(&mut Takuri, Candle) -> Option = ::update; - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on no-match). + `array.array('d')` (`0.0` on no-match). ## Warmup diff --git a/Indicators/Indicator-TasukiGap.md b/Indicators/Indicator-TasukiGap.md index b524e54..ec7e46a 100644 --- a/Indicators/Indicator-TasukiGap.md +++ b/Indicators/Indicator-TasukiGap.md @@ -62,7 +62,7 @@ const _: fn(&mut TasukiGap, Candle) -> Option = ::u - **Node.** `update(open, high, low, close)` returns `number`; `batch(open, high, low, close)` returns `Array`. - **Python.** `update(candle)` returns `float`; `batch(open, high, low, close)` - returns a 1-D `numpy.ndarray` (`0.0` on warmup / no-match, never `NaN`). + returns an `array.array('d')` (`0.0` on warmup / no-match, never `NaN`). ## Warmup diff --git a/Indicators/Indicator-TdCamouflage.md b/Indicators/Indicator-TdCamouflage.md index 7a04b87..fffad73 100644 --- a/Indicators/Indicator-TdCamouflage.md +++ b/Indicators/Indicator-TdCamouflage.md @@ -50,7 +50,7 @@ const _: fn(&mut TdCamouflage, Candle) -> Option = ` out. Python `update(candle)` / `batch(open, high, -low, close)` → 1-D ndarray (NaN warmup); Node `update(open, high, low, close)` / +low, close)` → `array.array('d')` (NaN warmup); Node `update(open, high, low, close)` / `batch(o[], h[], l[], c[])`. ## Warmup diff --git a/Indicators/Indicator-TdClop.md b/Indicators/Indicator-TdClop.md index 1f69ee1..4ad7a84 100644 --- a/Indicators/Indicator-TdClop.md +++ b/Indicators/Indicator-TdClop.md @@ -50,7 +50,7 @@ const _: fn(&mut TdClop, Candle) -> Option = ::update; ``` A `Candle` in, an `Option` out. Python `update(candle)` / `batch(open, high, -low, close)` → 1-D ndarray; Node `update(open, high, low, close)` / `batch(...)`. +low, close)` → `array.array('d')`; Node `update(open, high, low, close)` / `batch(...)`. ## Warmup diff --git a/Indicators/Indicator-TdCombo.md b/Indicators/Indicator-TdCombo.md index 0c11423..08f21ab 100644 --- a/Indicators/Indicator-TdCombo.md +++ b/Indicators/Indicator-TdCombo.md @@ -56,7 +56,7 @@ The combo count saturates at `target` (DeMark's classic value is ## Inputs / Outputs `Indicator` — signed combo count. -Same shape as TdCountdown. Python: 1-D `np.ndarray` with `NaN` +Same shape as TdCountdown. Python: `array.array('d')` with `NaN` warmup. Node: same. ## Warmup @@ -107,7 +107,7 @@ print('max:', np.nanmax(td.batch(close + 0.3, close - 0.3, close))) ```javascript const wickra = require('wickra'); -const td = new wickra.TDCombo(); +const td = new wickra.TDCombo(4, 9, 2, 13); const close = Array.from({ length: 40 }, (_, i) => 100 - i * 0.6); console.log('max:', Math.max(...td.batch(close.map(c => c + 0.3), close.map(c => c - 0.3), close) diff --git a/Indicators/Indicator-TdCountdown.md b/Indicators/Indicator-TdCountdown.md index 9c4da01..47de692 100644 --- a/Indicators/Indicator-TdCountdown.md +++ b/Indicators/Indicator-TdCountdown.md @@ -61,7 +61,7 @@ argument. `TdCountdown::classic()` returns `(4, 9, 2, 13)`. `Indicator`. Python: `TdCountdown(...).batch(high, low, close)` returns a 1-D -`np.ndarray` with `NaN` for warmup. Node: same shape; +`array.array('d')` with `NaN` for warmup. Node: same shape; `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-TdDWave.md b/Indicators/Indicator-TdDWave.md index 5a56323..ffa6e13 100644 --- a/Indicators/Indicator-TdDWave.md +++ b/Indicators/Indicator-TdDWave.md @@ -100,7 +100,7 @@ import wickra as ta td = ta.TDDWave(2) base = 100 + np.sin(np.arange(200) * 0.5) * 10 -print(td.batch(base + 1, base - 1)[-1]) # 1..8 +print(td.batch(base + 1, base - 1, base)[-1]) # 1..8 ``` ### Node diff --git a/Indicators/Indicator-TdDeMarker.md b/Indicators/Indicator-TdDeMarker.md index 5ecf4c4..a4b68b5 100644 --- a/Indicators/Indicator-TdDeMarker.md +++ b/Indicators/Indicator-TdDeMarker.md @@ -45,7 +45,7 @@ new-low streak; `0.5` = balanced. See ## Inputs / Outputs `Indicator`. Python: -`TdDeMarker(period).batch(high, low)` returns a 1-D `np.ndarray` +`TdDeMarker(period).batch(high, low)` returns an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. diff --git a/Indicators/Indicator-TdDifferential.md b/Indicators/Indicator-TdDifferential.md index 645e617..6cbc745 100644 --- a/Indicators/Indicator-TdDifferential.md +++ b/Indicators/Indicator-TdDifferential.md @@ -54,7 +54,7 @@ None — `TdDifferential::new()` takes no arguments. `Indicator`. Python: `TdDifferential().batch(high, low, close)` returns a 1-D -`np.ndarray` (first bar is `NaN`). Node: same shape; +`array.array('d')` (first bar is `NaN`). Node: same shape; `update(candle)` returns `number | null` (only first bar `null`). ## Warmup diff --git a/Indicators/Indicator-TdMovingAverage.md b/Indicators/Indicator-TdMovingAverage.md index 5bcd13c..5084784 100644 --- a/Indicators/Indicator-TdMovingAverage.md +++ b/Indicators/Indicator-TdMovingAverage.md @@ -101,7 +101,7 @@ import wickra as ta td = ta.TDMovingAverage(5, 13) high = np.arange(40, dtype=float) + 101 low = np.arange(40, dtype=float) + 99 -st1, st2 = td.batch(high, low).T +st1, st2 = np.asarray(td.batch(high, low).tolist()).T print(st1[-1], st2[-1]) ``` diff --git a/Indicators/Indicator-TdOpen.md b/Indicators/Indicator-TdOpen.md index 43e866e..f2b48f8 100644 --- a/Indicators/Indicator-TdOpen.md +++ b/Indicators/Indicator-TdOpen.md @@ -43,7 +43,7 @@ None — `TdOpen::new()` takes no arguments. ## Inputs / Outputs `Indicator`. Python: -`TdOpen().batch(open, high, low)` returns a 1-D `np.ndarray` +`TdOpen().batch(open, high, low)` returns an `array.array('d')` (first bar is `NaN`). Node: same shape; `update(candle)` returns `number | null`. @@ -89,9 +89,10 @@ import wickra as ta o = np.array([100.0, 96.0]) h = np.array([102.0, 99.0]) l = np.array([ 98.0, 95.0]) +c = np.array([101.0, 97.0]) td = ta.TDOpen() -print(td.batch(o, h, l)) +print(td.batch(o, h, l, c)) ``` ### Node @@ -99,7 +100,7 @@ print(td.batch(o, h, l)) ```javascript const wickra = require('wickra'); const td = new wickra.TDOpen(); -console.log(td.batch([100, 96], [102, 99], [98, 95])); +console.log(td.batch([100, 96], [102, 99], [98, 95], [101, 97])); ``` ### Streaming diff --git a/Indicators/Indicator-TdPressure.md b/Indicators/Indicator-TdPressure.md index 9969a9c..1ac5232 100644 --- a/Indicators/Indicator-TdPressure.md +++ b/Indicators/Indicator-TdPressure.md @@ -52,7 +52,7 @@ so the result is bounded by `±100`. See `Indicator`. Python: `TdPressure(period).batch(open, high, low, close, volume)` returns -a 1-D `np.ndarray` with `NaN` in the warmup prefix. Node: same +an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-TdRei.md b/Indicators/Indicator-TdRei.md index 0b61895..01f8e34 100644 --- a/Indicators/Indicator-TdRei.md +++ b/Indicators/Indicator-TdRei.md @@ -53,7 +53,7 @@ The conditional weighting filters out bars that don't represent a ## Inputs / Outputs `Indicator`. Python: -`TdRei(period).batch(high, low, close)` returns a 1-D `np.ndarray` +`TdRei(period).batch(high, low, close)` returns an `array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. @@ -97,8 +97,8 @@ import wickra as ta base = 100 + np.arange(30, dtype=float) r = ta.TDREI(5) -out = r.batch(base + 1, base - 1, base) -print('warmup:', r.warmup_period()) # 12 +out = r.batch(base + 1, base - 1) +print('warmup:', r.warmup_period()) # 11 print('row 20:', out[20]) ``` diff --git a/Indicators/Indicator-TdSequential.md b/Indicators/Indicator-TdSequential.md index 00dea14..bf31c68 100644 --- a/Indicators/Indicator-TdSequential.md +++ b/Indicators/Indicator-TdSequential.md @@ -122,7 +122,7 @@ print('row 30:', out[30]) ```javascript const wickra = require('wickra'); -const td = new wickra.TDSequential(); +const td = new wickra.TDSequential(4, 9, 2, 13); const close = Array.from({ length: 60 }, (_, i) => 100 - i * 0.4); const flat = td.batch(close.map(c => c + 0.3), close.map(c => c - 0.3), close); console.log('row 30: setup =', flat[30 * 2], 'countdown =', flat[30 * 2 + 1]); diff --git a/Indicators/Indicator-TdSetup.md b/Indicators/Indicator-TdSetup.md index 3a81d9c..745465d 100644 --- a/Indicators/Indicator-TdSetup.md +++ b/Indicators/Indicator-TdSetup.md @@ -54,7 +54,7 @@ zero argument. `TdSetup::classic()` returns the `(4, 9)` factory. `Indicator`. The signed value lets a single scalar carry both directions. Python: -`TdSetup(lookback, target).batch(close)` returns a 1-D `np.ndarray` +`TdSetup(lookback, target).batch(close)` returns an `array.array('d')` with `NaN` for the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. diff --git a/Indicators/Indicator-TdTrap.md b/Indicators/Indicator-TdTrap.md index 29efe60..97bd809 100644 --- a/Indicators/Indicator-TdTrap.md +++ b/Indicators/Indicator-TdTrap.md @@ -98,8 +98,9 @@ import numpy as np import wickra as ta td = ta.TDTrap() -h = np.array([110, 108, 112]); l = np.array([90, 95, 100]); c = np.array([100, 102, 109]) -print(td.batch(h, l, c)) # [nan, nan, 1.0] +o = np.array([95, 100, 103]); h = np.array([110, 108, 112]) +l = np.array([90, 95, 100]); c = np.array([100, 102, 109]) +print(td.batch(o, h, l, c)) # [nan, nan, 1.0] ``` ### Node @@ -107,8 +108,8 @@ print(td.batch(h, l, c)) # [nan, nan, 1.0] ```javascript const ta = require('wickra'); const td = new ta.TDTrap(); -td.update(110, 90, 100); td.update(108, 95, 102); -console.log(td.update(112, 100, 109)); // 1 +td.update(95, 110, 90, 100); td.update(100, 108, 95, 102); +console.log(td.update(103, 112, 100, 109)); // 1 ``` ### Streaming diff --git a/Indicators/Indicator-Tema.md b/Indicators/Indicator-Tema.md index 51a45b4..bf6ab91 100644 --- a/Indicators/Indicator-Tema.md +++ b/Indicators/Indicator-Tema.md @@ -51,7 +51,7 @@ const _: fn(&mut Tema, f64) -> Option = ::update; ``` Python `update` returns `float | None`, `batch` returns a 1-D -`numpy.ndarray` (`float64`, `NaN` for warmup). Node `update` returns +`array.array('d')` (`float64`, `NaN` for warmup). Node `update` returns `number | null`, `batch` returns `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-ThreeDrives.md b/Indicators/Indicator-ThreeDrives.md index 5a80040..64fb3cf 100644 --- a/Indicators/Indicator-ThreeDrives.md +++ b/Indicators/Indicator-ThreeDrives.md @@ -43,7 +43,7 @@ const _: fn(&mut wickra::ThreeDrives, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-ThreeLineBreak.md b/Indicators/Indicator-ThreeLineBreak.md index 296c034..611180d 100644 --- a/Indicators/Indicator-ThreeLineBreak.md +++ b/Indicators/Indicator-ThreeLineBreak.md @@ -105,7 +105,7 @@ import wickra as ta t = ta.ThreeLineBreak(3) close = np.arange(20, dtype=float) + 100 -print(t.batch(close)[-1]) # 1.0 +print(t.batch(close + 1, close - 1, close)[-1]) # 1.0 ``` ### Node @@ -114,7 +114,8 @@ print(t.batch(close)[-1]) # 1.0 const ta = require('wickra'); const t = new ta.ThreeLineBreak(3); -console.log(t.batch(Array.from({length: 20}, (_, i) => 100 + i)).at(-1)); // 1 +const close = Array.from({ length: 20 }, (_, i) => 100 + i); +console.log(t.batch(close.map(c => c + 1), close.map(c => c - 1), close).at(-1)); // 1 ``` ### Streaming diff --git a/Indicators/Indicator-ThreeLineStrike.md b/Indicators/Indicator-ThreeLineStrike.md index b08f92d..b61ad37 100644 --- a/Indicators/Indicator-ThreeLineStrike.md +++ b/Indicators/Indicator-ThreeLineStrike.md @@ -54,7 +54,7 @@ const _: fn(&mut ThreeLineStrike, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-ThreeStarsInSouth.md b/Indicators/Indicator-ThreeStarsInSouth.md index 5593599..01989ea 100644 --- a/Indicators/Indicator-ThreeStarsInSouth.md +++ b/Indicators/Indicator-ThreeStarsInSouth.md @@ -57,7 +57,7 @@ const _: fn(&mut ThreeStarsInSouth, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Thrusting.md b/Indicators/Indicator-Thrusting.md index 2494cf4..077a640 100644 --- a/Indicators/Indicator-Thrusting.md +++ b/Indicators/Indicator-Thrusting.md @@ -53,7 +53,7 @@ const _: fn(&mut Thrusting, Candle) -> Option = ::u - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-TickIndex.md b/Indicators/Indicator-TickIndex.md index 9e910ab..7bece70 100644 --- a/Indicators/Indicator-TickIndex.md +++ b/Indicators/Indicator-TickIndex.md @@ -48,7 +48,7 @@ const _: fn(&mut TickIndex, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-Tii.md b/Indicators/Indicator-Tii.md index 77a6a2d..5f79b51 100644 --- a/Indicators/Indicator-Tii.md +++ b/Indicators/Indicator-Tii.md @@ -52,7 +52,7 @@ const _: fn(&mut Tii, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out in `[0, 100]`. Python maps this -to `float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-TimeBasedStop.md b/Indicators/Indicator-TimeBasedStop.md index 6a8b325..99ca7fe 100644 --- a/Indicators/Indicator-TimeBasedStop.md +++ b/Indicators/Indicator-TimeBasedStop.md @@ -99,7 +99,7 @@ import wickra as ta t = ta.TimeBasedStop(4) close = np.full(4, 100.0) # only the length matters -print(t.batch(close)) # [0.25 0.5 0.75 1. ] +print(t.batch(close + 1, close - 1, close)) # array('d', [0.25, 0.5, 0.75, 1.0]) ``` ### Node @@ -108,7 +108,8 @@ print(t.batch(close)) # [0.25 0.5 0.75 1. ] const ta = require('wickra'); const t = new ta.TimeBasedStop(4); -console.log(t.batch([100, 100, 100, 100])); // [0.25, 0.5, 0.75, 1] +const close = [100, 100, 100, 100]; +console.log(t.batch(close.map(c => c + 1), close.map(c => c - 1), close)); // [0.25, 0.5, 0.75, 1] ``` ### Streaming diff --git a/Indicators/Indicator-TimeOfDayReturnProfile.md b/Indicators/Indicator-TimeOfDayReturnProfile.md index e7e1b06..0de2d85 100644 --- a/Indicators/Indicator-TimeOfDayReturnProfile.md +++ b/Indicators/Indicator-TimeOfDayReturnProfile.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::TimeOfDayReturnProfile, wickra::Candle) -> Option::update; ``` -- **Python.** `update((o,h,l,c,v,ts))` → `ndarray` of length `buckets` (or `None`); +- **Python.** `update((o,h,l,c,v,ts))` → `Matrix` of length `buckets` (or `None`); `batch(...)` → `(n, buckets)` array, warmup rows `NaN`. - **Node.** `update(...)` → `number[]` (or `null`); `batch(...)` → flat `number[]` length `n*buckets`. - **WASM.** `update(...)` → `Float64Array` (or `null`). diff --git a/Indicators/Indicator-TpoProfile.md b/Indicators/Indicator-TpoProfile.md index df02500..e3800d0 100644 --- a/Indicators/Indicator-TpoProfile.md +++ b/Indicators/Indicator-TpoProfile.md @@ -54,7 +54,7 @@ const _: fn(&mut TpoProfile, Candle) -> Option = `TpoProfileOutput` carries `price_low: f64`, `price_high: f64` and `counts: Vec` (length `bin_count`, lowest bucket first). -Python `update(candle)` returns `(price_low, price_high, counts_ndarray)` or +Python `update(candle)` returns `(price_low, price_high, counts)` or `None`; `batch(high, low)` returns a `(n, bin_count + 2)` array with columns `[price_low, price_high, count_0, …]` (`NaN` warmup rows). Node `update(high, low)` returns `{ priceLow, priceHigh, counts }` or `null`; `batch` diff --git a/Indicators/Indicator-TrendLabel.md b/Indicators/Indicator-TrendLabel.md index 16a2675..520882f 100644 --- a/Indicators/Indicator-TrendLabel.md +++ b/Indicators/Indicator-TrendLabel.md @@ -46,7 +46,7 @@ use wickra::{Indicator, TrendLabel}; const _: fn(&mut TrendLabel, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-TrendStrengthIndex.md b/Indicators/Indicator-TrendStrengthIndex.md index e0ec233..65aece8 100644 --- a/Indicators/Indicator-TrendStrengthIndex.md +++ b/Indicators/Indicator-TrendStrengthIndex.md @@ -56,7 +56,7 @@ const _: fn(&mut TrendStrengthIndex, f64) -> Option = ``` Scalar in, scalar out. Python returns `float | None` (streaming) / -`numpy.ndarray` (batch, `NaN` for warmup). Node returns `number | null` / +`array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-TreynorRatio.md b/Indicators/Indicator-TreynorRatio.md index 9d7b008..9561b6d 100644 --- a/Indicators/Indicator-TreynorRatio.md +++ b/Indicators/Indicator-TreynorRatio.md @@ -44,7 +44,7 @@ maintain `Σa, Σb, Σb², Σa·b`. See `Indicator`. Python: `TreynorRatio(period, rf).batch(asset_returns, benchmark_returns)` -returns a 1-D `np.ndarray` with `NaN` warmup. Node: same shape; +returns an `array.array('d')` with `NaN` warmup. Node: same shape; `update(asset, benchmark)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-Triangle.md b/Indicators/Indicator-Triangle.md index fa68767..29e6f17 100644 --- a/Indicators/Indicator-Triangle.md +++ b/Indicators/Indicator-Triangle.md @@ -44,7 +44,7 @@ const _: fn(&mut wickra::Triangle, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-Trima.md b/Indicators/Indicator-Trima.md index c1782f0..662e66c 100644 --- a/Indicators/Indicator-Trima.md +++ b/Indicators/Indicator-Trima.md @@ -50,7 +50,7 @@ const _: fn(&mut Trima, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Trin.md b/Indicators/Indicator-Trin.md index 3d52080..2430a06 100644 --- a/Indicators/Indicator-Trin.md +++ b/Indicators/Indicator-Trin.md @@ -52,7 +52,7 @@ const _: fn(&mut Trin, CrossSection) -> Option = ::updat The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-TripleTopBottom.md b/Indicators/Indicator-TripleTopBottom.md index 4d2c6aa..bb7d561 100644 --- a/Indicators/Indicator-TripleTopBottom.md +++ b/Indicators/Indicator-TripleTopBottom.md @@ -40,7 +40,7 @@ const _: fn(&mut wickra::TripleTopBottom, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-Tristar.md b/Indicators/Indicator-Tristar.md index c02317a..e666439 100644 --- a/Indicators/Indicator-Tristar.md +++ b/Indicators/Indicator-Tristar.md @@ -51,7 +51,7 @@ const _: fn(&mut Tristar, Candle) -> Option = ::updat ``` A `Candle` in, an `Option` out. Python `update(candle)` / `batch(open, high, -low, close)` → 1-D ndarray; Node `update(open, high, low, close)` / `batch(...)`. +low, close)` → `array.array('d')`; Node `update(open, high, low, close)` / `batch(...)`. ## Warmup diff --git a/Indicators/Indicator-Trix.md b/Indicators/Indicator-Trix.md index 37afcb8..13c7dcb 100644 --- a/Indicators/Indicator-Trix.md +++ b/Indicators/Indicator-Trix.md @@ -55,7 +55,7 @@ use wickra::{Indicator, Trix}; const _: fn(&mut Trix, f64) -> Option = ::update; ``` -Python's `TRIX.batch(prices)` returns a 1-D `float64` `np.ndarray` +Python's `TRIX.batch(prices)` returns an `array.array('d')` (warmup → `NaN`). Node's `TRIX.batch(prices)` returns a flat `number[]` (warmup → `NaN`). Both also expose streaming `update(price)`. diff --git a/Indicators/Indicator-Tsf.md b/Indicators/Indicator-Tsf.md index fd1305f..4e9257a 100644 --- a/Indicators/Indicator-Tsf.md +++ b/Indicators/Indicator-Tsf.md @@ -49,7 +49,7 @@ use wickra::{Indicator, Tsf}; const _: fn(&mut Tsf, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray` (`NaN` for +Python streams as `float | None`, batches as an `array.array('d')` (`NaN` for warmup). Node streams as `number | null`, batches as `Array` with `NaN` placeholders. diff --git a/Indicators/Indicator-TsfOscillator.md b/Indicators/Indicator-TsfOscillator.md index a024909..7bdaae5 100644 --- a/Indicators/Indicator-TsfOscillator.md +++ b/Indicators/Indicator-TsfOscillator.md @@ -55,7 +55,7 @@ const _: fn(&mut TsfOscillator, f64) -> Option = ` out (a percentage). Python maps -this to `float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +this to `float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array` with `NaN` warmup. ## Warmup diff --git a/Indicators/Indicator-Tsi.md b/Indicators/Indicator-Tsi.md index b3e3780..80e223d 100644 --- a/Indicators/Indicator-Tsi.md +++ b/Indicators/Indicator-Tsi.md @@ -50,7 +50,7 @@ const _: fn(&mut Tsi, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-Tsv.md b/Indicators/Indicator-Tsv.md index 33b6706..b9cd7e2 100644 --- a/Indicators/Indicator-Tsv.md +++ b/Indicators/Indicator-Tsv.md @@ -35,7 +35,7 @@ See `crates/wickra-core/src/indicators/tsv.rs`. ## Inputs / Outputs `Indicator`. Python: -`Tsv(period).batch(close, volume)` returns a 1-D `np.ndarray` with +`Tsv(period).batch(close, volume)` returns an `array.array('d')` with `NaN` warmup. Node: same shape. ## Warmup diff --git a/Indicators/Indicator-TtmSqueeze.md b/Indicators/Indicator-TtmSqueeze.md index 362564a..e636da2 100644 --- a/Indicators/Indicator-TtmSqueeze.md +++ b/Indicators/Indicator-TtmSqueeze.md @@ -59,7 +59,7 @@ const _: fn(&mut TtmSqueeze, Candle) -> Option = ` diff --git a/Indicators/Indicator-TtmTrend.md b/Indicators/Indicator-TtmTrend.md index ddcd213..ac4bfd4 100644 --- a/Indicators/Indicator-TtmTrend.md +++ b/Indicators/Indicator-TtmTrend.md @@ -52,7 +52,7 @@ const _: fn(&mut TtmTrend, Candle) -> Option = ::upd The indicator reads only the high, low and close, so the batch bindings take those three columns. Node: `update(high, low, close)` / `batch(h[], l[], c[])`. Python: `update(candle)` (a full candle object) / `batch(high, low, close)` → -1-D `ndarray` (`NaN` for warmup). Node returns `number | null` / +`array.array('d')` (`NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-TurnOfMonth.md b/Indicators/Indicator-TurnOfMonth.md index ed032c7..86e4f74 100644 --- a/Indicators/Indicator-TurnOfMonth.md +++ b/Indicators/Indicator-TurnOfMonth.md @@ -45,7 +45,7 @@ const _: fn(&mut wickra::TurnOfMonth, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float | None`; - `batch(...)` → 1-D `ndarray` (`NaN` until the first in-window day). + `batch(...)` → `array.array('d')` (`NaN` until the first in-window day). - **Node.** `update(...)` → `number | null`; `batch(...)` → `number[]`. - **WASM.** `update(...)` → `number | undefined`. diff --git a/Indicators/Indicator-Tweezer.md b/Indicators/Indicator-Tweezer.md index b823955..a8e356f 100644 --- a/Indicators/Indicator-Tweezer.md +++ b/Indicators/Indicator-Tweezer.md @@ -96,7 +96,7 @@ h = np.array([101.0, 101.5]) l = np.array([ 99.5, 99.5]) c = np.array([100.0, 101.0]) -tw = ta.Tweezer(0.001) +tw = ta.Tweezer() print(tw.batch(o, h, l, c)) ``` diff --git a/Indicators/Indicator-TwoCrows.md b/Indicators/Indicator-TwoCrows.md index 306e527..89f243c 100644 --- a/Indicators/Indicator-TwoCrows.md +++ b/Indicators/Indicator-TwoCrows.md @@ -51,7 +51,7 @@ const _: fn(&mut TwoCrows, Candle) -> Option = ::upd - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `Array`. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-UlcerIndex.md b/Indicators/Indicator-UlcerIndex.md index 526ee95..f4f4277 100644 --- a/Indicators/Indicator-UlcerIndex.md +++ b/Indicators/Indicator-UlcerIndex.md @@ -50,7 +50,7 @@ const _: fn(&mut UlcerIndex, f64) -> Option = ::up ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-UniqueThreeRiver.md b/Indicators/Indicator-UniqueThreeRiver.md index 2aa0a93..502676d 100644 --- a/Indicators/Indicator-UniqueThreeRiver.md +++ b/Indicators/Indicator-UniqueThreeRiver.md @@ -55,7 +55,7 @@ const _: fn(&mut UniqueThreeRiver, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-UpDownVolumeRatio.md b/Indicators/Indicator-UpDownVolumeRatio.md index 02d0574..a8c91d8 100644 --- a/Indicators/Indicator-UpDownVolumeRatio.md +++ b/Indicators/Indicator-UpDownVolumeRatio.md @@ -49,7 +49,7 @@ const _: fn(&mut UpDownVolumeRatio, CrossSection) -> Option = The bindings pass a tick as four equal-length parallel arrays: - **Python**: `update(change, volume, new_high, new_low)`; `batch(...)` returns a - 1-D `ndarray`. + `array.array('d')`. - **Node**: `update(change, volume, newHigh, newLow)`; `batch` returns `number[]`. - **WASM**: `update(change, volume, newHigh, newLow)` only; flag arrays are numeric. diff --git a/Indicators/Indicator-UpsideGapThreeMethods.md b/Indicators/Indicator-UpsideGapThreeMethods.md index b686acd..0cabf38 100644 --- a/Indicators/Indicator-UpsideGapThreeMethods.md +++ b/Indicators/Indicator-UpsideGapThreeMethods.md @@ -53,7 +53,7 @@ const _: fn(&mut UpsideGapThreeMethods, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-UpsideGapTwoCrows.md b/Indicators/Indicator-UpsideGapTwoCrows.md index 5e94dfe..9ec269f 100644 --- a/Indicators/Indicator-UpsideGapTwoCrows.md +++ b/Indicators/Indicator-UpsideGapTwoCrows.md @@ -53,7 +53,7 @@ const _: fn(&mut UpsideGapTwoCrows, Candle) -> Option = `. - **Python.** `update(candle)` → `float`; `batch(open, high, low, close)` → 1-D - `numpy.ndarray` (`0.0` on warmup / no-match). + `array.array('d')` (`0.0` on warmup / no-match). ## Warmup diff --git a/Indicators/Indicator-Vidya.md b/Indicators/Indicator-Vidya.md index f02d034..9ef07a2 100644 --- a/Indicators/Indicator-Vidya.md +++ b/Indicators/Indicator-Vidya.md @@ -49,7 +49,7 @@ const _: fn(&mut Vidya, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / a `float64` `np.ndarray` with `NaN` warmup; Node to +`float | None` / an `array.array('d')` with `NaN` warmup; Node to `number | null` / `Array`. ## Warmup diff --git a/Indicators/Indicator-VolatilityCone.md b/Indicators/Indicator-VolatilityCone.md index 53915bc..46ea22b 100644 --- a/Indicators/Indicator-VolatilityCone.md +++ b/Indicators/Indicator-VolatilityCone.md @@ -113,7 +113,7 @@ Output: ``` warmup_period = 4 -Some(VolatilityConeOutput { current: 0.20218342336724174, min: 0.0, median: 0.10109171168362087, max: 0.20218342336724174, percentile: 100.0 }) +Some(VolatilityConeOutput { current: 0.20218342336724177, min: 0.0, median: 0.10109171168362088, max: 0.20218342336724177, percentile: 100.0 }) ``` ### Python diff --git a/Indicators/Indicator-VolatilityOfVolatility.md b/Indicators/Indicator-VolatilityOfVolatility.md index 3b8a05d..400b804 100644 --- a/Indicators/Indicator-VolatilityOfVolatility.md +++ b/Indicators/Indicator-VolatilityOfVolatility.md @@ -54,7 +54,7 @@ const _: fn(&mut VolatilityOfVolatility, f64) -> Option = ` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Indicators/Indicator-VoltyStop.md b/Indicators/Indicator-VoltyStop.md index d0542db..e2d0af5 100644 --- a/Indicators/Indicator-VoltyStop.md +++ b/Indicators/Indicator-VoltyStop.md @@ -58,7 +58,7 @@ and `Error::NonPositiveMultiplier` for non-finite or non-positive `Indicator`. Python: `VoltyStop(period, mult).batch(high, low, close)` returns a 1-D -`np.ndarray` with `NaN` in the warmup prefix. Node: same shape; +`array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. ## Warmup diff --git a/Indicators/Indicator-VolumeByTimeProfile.md b/Indicators/Indicator-VolumeByTimeProfile.md index 1cf06e1..61ae09c 100644 --- a/Indicators/Indicator-VolumeByTimeProfile.md +++ b/Indicators/Indicator-VolumeByTimeProfile.md @@ -40,7 +40,7 @@ const _: fn(&mut wickra::VolumeByTimeProfile, wickra::Candle) -> Option::update; ``` -- **Python.** `update((o,h,l,c,v,ts))` → `ndarray` of length `buckets`; +- **Python.** `update((o,h,l,c,v,ts))` → `Matrix` of length `buckets`; `batch(...)` → `(n, buckets)` array. - **Node.** `update(...)` → `number[]`; `batch(...)` → flat `number[]` length `n*buckets`. - **WASM.** `update(...)` → `Float64Array`. diff --git a/Indicators/Indicator-VolumeProfile.md b/Indicators/Indicator-VolumeProfile.md index d97cfaf..4274187 100644 --- a/Indicators/Indicator-VolumeProfile.md +++ b/Indicators/Indicator-VolumeProfile.md @@ -53,7 +53,7 @@ const _: fn(&mut VolumeProfile, Candle) -> Option = `VolumeProfileOutput` carries `price_low: f64`, `price_high: f64` and `bins: Vec` (length `bin_count`, lowest bucket first). -Python `update(candle)` returns `(price_low, price_high, bins_ndarray)` or `None` +Python `update(candle)` returns `(price_low, price_high, bins)` or `None` during warmup; `batch(high, low, volume)` returns a `(n, bin_count + 2)` array whose columns are `[price_low, price_high, bin_0, …]` (warmup rows are `NaN`). Node `update(high, low, volume)` returns `{ priceLow, priceHigh, bins }` or diff --git a/Indicators/Indicator-VolumeRsi.md b/Indicators/Indicator-VolumeRsi.md index 6ed8390..612bc06 100644 --- a/Indicators/Indicator-VolumeRsi.md +++ b/Indicators/Indicator-VolumeRsi.md @@ -116,8 +116,9 @@ import numpy as np import wickra as ta vrsi = ta.VolumeRsi(3) +close = np.array([100, 101, 102, 101, 103, 104], dtype=float) volume = np.array([1000, 1100, 1200, 1300, 1400, 1500], dtype=float) -print(vrsi.batch(volume)) +print(vrsi.batch(close, volume)) ``` Output: @@ -133,8 +134,9 @@ const ta = require('wickra'); const vrsi = new ta.VolumeRsi(14); console.log('warmupPeriod:', vrsi.warmupPeriod()); // 15 +const close = Array.from({ length: 40 }, (_, i) => 100 + i); const volume = Array.from({ length: 40 }, (_, i) => 1000 + i * 100); -console.log(vrsi.batch(volume).at(-1)); // 100 (volume only rises) +console.log(vrsi.batch(close, volume).at(-1)); // 100 (volume only rises) ``` ### Streaming diff --git a/Indicators/Indicator-VolumeWeightedMacd.md b/Indicators/Indicator-VolumeWeightedMacd.md index cec1dd2..3d58d2e 100644 --- a/Indicators/Indicator-VolumeWeightedMacd.md +++ b/Indicators/Indicator-VolumeWeightedMacd.md @@ -114,7 +114,7 @@ import wickra as ta m = ta.VolumeWeightedMacd(12, 26, 9) close = np.cumsum(np.ones(80)) + 100.0 volume = np.full(80, 1000.0) -macd, signal, hist = m.batch(close, volume).T +macd, signal, hist = np.asarray(m.batch(close, volume).tolist()).T print(macd[-1], signal[-1], hist[-1]) ``` diff --git a/Indicators/Indicator-Vpin.md b/Indicators/Indicator-Vpin.md index 08fc816..b89c704 100644 --- a/Indicators/Indicator-Vpin.md +++ b/Indicators/Indicator-Vpin.md @@ -52,7 +52,7 @@ const _: fn(&mut Vpin, Trade) -> Option = ::update; ``` Node `update(price, size, isBuy)` and `batch(price[], size[], isBuy[])`; Python -`update(price, size, is_buy)` and `batch(price, size, is_buy)` → 1-D `ndarray`. +`update(price, size, is_buy)` and `batch(price, size, is_buy)` → `array.array('d')`. ## Warmup diff --git a/Indicators/Indicator-Vwap.md b/Indicators/Indicator-Vwap.md index 70e6a55..4fb82fd 100644 --- a/Indicators/Indicator-Vwap.md +++ b/Indicators/Indicator-Vwap.md @@ -63,7 +63,7 @@ const _: fn(&mut Vwap, Candle) -> Option = ::update; - **Rust input.** A full `Candle`; the indicator multiplies `typical_price() * volume` and accumulates. - **Python batch.** `VWAP.batch(high, low, close, volume)` returns a 1-D - `np.ndarray` with `NaN` for any prefix where the cumulative volume is + `array.array('d')` with `NaN` for any prefix where the cumulative volume is still `0`. - **Node batch.** `vwap.batch(high, low, close, volume)` returns `Array` with `NaN` for the same prefix. diff --git a/Indicators/Indicator-VwapStdDevBands.md b/Indicators/Indicator-VwapStdDevBands.md index 3d93871..1c9f7ce 100644 --- a/Indicators/Indicator-VwapStdDevBands.md +++ b/Indicators/Indicator-VwapStdDevBands.md @@ -59,7 +59,7 @@ const _: fn(&mut VwapStdDevBands, Candle) -> Option = Option = ::update; ``` Scalar in, scalar out. Python returns `float | None` (streaming) / -`numpy.ndarray` (batch, `NaN` for warmup). Node returns `number | null` / +`array.array('d')` (batch, `NaN` for warmup). Node returns `number | null` / `Array` with `NaN`. ## Warmup diff --git a/Indicators/Indicator-WaveTrend.md b/Indicators/Indicator-WaveTrend.md index b5e9f82..85ba404 100644 --- a/Indicators/Indicator-WaveTrend.md +++ b/Indicators/Indicator-WaveTrend.md @@ -55,7 +55,7 @@ const _: fn(&mut WaveTrend, Candle) -> Option = ` of length diff --git a/Indicators/Indicator-Wedge.md b/Indicators/Indicator-Wedge.md index 1a936e7..ede7bc6 100644 --- a/Indicators/Indicator-Wedge.md +++ b/Indicators/Indicator-Wedge.md @@ -42,7 +42,7 @@ const _: fn(&mut wickra::Wedge, wickra::Candle) -> Option = ``` - **Python.** `update((o,h,l,c,v,ts))` → `float` (never `None`); - `batch(open, high, low, close)` → 1-D `ndarray`. + `batch(open, high, low, close)` → `array.array('d')`. - **Node.** `update(open, high, low, close)` → `number`; `batch(open, high, low, close)` → `number[]`. - **WASM.** `update(open, high, low, close)` → `number`. diff --git a/Indicators/Indicator-WickRatio.md b/Indicators/Indicator-WickRatio.md index 58812c6..8c0a578 100644 --- a/Indicators/Indicator-WickRatio.md +++ b/Indicators/Indicator-WickRatio.md @@ -44,7 +44,7 @@ const _: fn(&mut WickRatio, Candle) -> Option = ::u ``` Node `update(open, high, low, close)` / `batch(open[], high[], low[], close[])`; -Python `update(candle)` / `batch(open, high, low, close)` → 1-D `ndarray`. +Python `update(candle)` / `batch(open, high, low, close)` → `array.array('d')`. ## Warmup diff --git a/Indicators/Indicator-WilliamsR.md b/Indicators/Indicator-WilliamsR.md index 497d346..a300c3d 100644 --- a/Indicators/Indicator-WilliamsR.md +++ b/Indicators/Indicator-WilliamsR.md @@ -51,7 +51,7 @@ const _: fn(&mut WilliamsR, Candle) -> Option = ::u ``` Python's `WilliamsR.batch(high, low, close)` returns a 1-D `float64` -`np.ndarray` (warmup → `NaN`). Node's `WilliamsR.batch(high, low, close)` +`array.array('d')` (warmup → `NaN`). Node's `WilliamsR.batch(high, low, close)` returns a flat `number[]` (warmup → `NaN`); only `batch` is exposed on the Node binding. diff --git a/Indicators/Indicator-WinRate.md b/Indicators/Indicator-WinRate.md index 559ade4..377f8ae 100644 --- a/Indicators/Indicator-WinRate.md +++ b/Indicators/Indicator-WinRate.md @@ -45,7 +45,7 @@ use wickra::{Indicator, WinRate}; const _: fn(&mut WinRate, f64) -> Option = ::update; ``` -Python streams as `float | None`, batches as a 1-D `numpy.ndarray`. Node streams +Python streams as `float | None`, batches as an `array.array('d')`. Node streams as `number | null`, batches as `Array`. ## Warmup diff --git a/Indicators/Indicator-Wma.md b/Indicators/Indicator-Wma.md index 955f55b..b48c1bc 100644 --- a/Indicators/Indicator-Wma.md +++ b/Indicators/Indicator-Wma.md @@ -56,7 +56,7 @@ use wickra::{Indicator, Wma}; const _: fn(&mut Wma, f64) -> Option = ::update; ``` -Python returns `float | None` from `update` and a `numpy.ndarray` +Python returns `float | None` from `update` and an `array.array('d')` (`float64`, `NaN` for warmup) from `batch`. Node returns `number | null` and `Array` (with `NaN` placeholders) respectively. diff --git a/Indicators/Indicator-YangZhangVolatility.md b/Indicators/Indicator-YangZhangVolatility.md index 0b5ad4f..a0fd2e4 100644 --- a/Indicators/Indicator-YangZhangVolatility.md +++ b/Indicators/Indicator-YangZhangVolatility.md @@ -58,7 +58,7 @@ const _: fn(&mut YangZhangVolatility, Candle) -> Option = ` with `NaN` diff --git a/Indicators/Indicator-YoyoExit.md b/Indicators/Indicator-YoyoExit.md index e0ade91..837b9ec 100644 --- a/Indicators/Indicator-YoyoExit.md +++ b/Indicators/Indicator-YoyoExit.md @@ -53,7 +53,7 @@ and `Error::NonPositiveMultiplier` for non-finite or non-positive ## Inputs / Outputs `Indicator`. Python: returns a 1-D -`np.ndarray` with `NaN` in the warmup prefix. Node: same shape; +`array.array('d')` with `NaN` in the warmup prefix. Node: same shape; `update(candle)` returns `number | null`. The output is the *trail level*. The active "in vs out" position diff --git a/Indicators/Indicator-ZigZag.md b/Indicators/Indicator-ZigZag.md index 1f7ebdc..4720f51 100644 --- a/Indicators/Indicator-ZigZag.md +++ b/Indicators/Indicator-ZigZag.md @@ -112,7 +112,7 @@ import wickra as ta # Price series with a clear swing p = np.array([100.0, 105.0, 115.0, 100.0, 90.0, 100.0]) zz = ta.ZigZag(0.10) -out = zz.batch(p + 0.5, p - 0.5, p) # high, low, close +out = zz.batch(p + 0.5, p - 0.5) # high, low print(out) # NaN on bars without confirmation ``` diff --git a/Indicators/Indicator-Zlema.md b/Indicators/Indicator-Zlema.md index e18778f..92cd3fc 100644 --- a/Indicators/Indicator-Zlema.md +++ b/Indicators/Indicator-Zlema.md @@ -49,7 +49,7 @@ const _: fn(&mut Zlema, f64) -> Option = ::update; ``` A single `f64` close in, an `Option` out. Python maps this to -`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` / +`float | None` / `array.array('d')` (NaN warmup); Node to `number | null` / `Array` (NaN warmup). ## Warmup diff --git a/Quickstart-C.md b/Quickstart-C.md index 4fee8b9..4ac84cc 100644 --- a/Quickstart-C.md +++ b/Quickstart-C.md @@ -44,7 +44,8 @@ wickra_sma_reset(sma); /* back to a fresh state */ wickra_sma_free(sma); /* exactly once per _new */ ``` -`update` is O(1) per call. There is no RAII across the C boundary, so every +`update` never revisits the history behind the tick. There is no RAII across +the C boundary, so every `wickra__new` must be paired with exactly one `wickra__free`. Every function is NULL-safe: a NULL handle yields `NaN` (or a no-op), never a crash. The alt-chart bar builders (`renko_bars`, `kagi_bars`, …) omit diff --git a/Quickstart-CSharp.md b/Quickstart-CSharp.md index ed1a87e..50a29cb 100644 --- a/Quickstart-CSharp.md +++ b/Quickstart-CSharp.md @@ -38,7 +38,8 @@ The alt-chart bar builders (`RenkoBars`, `KagiBars`, …) have no `WarmupPeriod` / `IsReady` — a candle can complete 0..n bars, so they have no warmup. -`Update` is O(1) per call. Prefer `using` for deterministic cleanup; a +`Update` never revisits the history behind the tick. Prefer `using` for +deterministic cleanup; a `SafeHandle` also frees the handle from the finalizer, so a missed `Dispose` never leaks permanently. diff --git a/Quickstart-Go.md b/Quickstart-Go.md index 733f718..ca39a36 100644 --- a/Quickstart-Go.md +++ b/Quickstart-Go.md @@ -42,7 +42,8 @@ The alt-chart bar builders (`RenkoBars`, `KagiBars`, …) have no `WarmupPeriod` / `IsReady` — a candle can complete 0..n bars, so they have no warmup. -`Update` is O(1) per call. Prefer `defer x.Close()` for prompt cleanup; a +`Update` never revisits the history behind the tick. Prefer `defer x.Close()` +for prompt cleanup; a `runtime.SetFinalizer` also frees the handle, so a missed `Close` never leaks permanently. diff --git a/Quickstart-Java.md b/Quickstart-Java.md index 64f0aee..1932a31 100644 --- a/Quickstart-Java.md +++ b/Quickstart-Java.md @@ -55,7 +55,8 @@ The alt-chart bar builders (`RenkoBars`, `KagiBars`, …) have no `warmupPeriod` / `isReady` — a candle can complete 0..n bars, so they have no warmup. -`update` is O(1) per call. Prefer try-with-resources for deterministic cleanup; +`update` never revisits the history behind the tick. Prefer try-with-resources +for deterministic cleanup; a `Cleaner` also frees the handle once the wrapper becomes unreachable, so a missed `close()` never leaks permanently. diff --git a/Quickstart-Python.md b/Quickstart-Python.md index 202240a..fb5b8da 100644 --- a/Quickstart-Python.md +++ b/Quickstart-Python.md @@ -77,7 +77,8 @@ in `crates/wickra-core/src/indicators/rsi.rs`. ## Streaming: feed one price at a time The same `RSI` instance can be driven tick-by-tick with `update()`. Each call -is O(1) and returns either a `float` or `None` while the indicator is still +never revisits the history behind the tick, and returns either a `float` or +`None` while the indicator is still warming up. ```python @@ -113,7 +114,7 @@ The full set of streaming-state methods is: | Method | Returns | Notes | |-----------------------|----------------|--------------------------------------------| -| `update(price)` | `float`/`None` | O(1) state transition, `None` during warmup | +| `update(price)` | `float`/`None` | incremental state transition, `None` during warmup | | `batch(prices)` | `array.array('d')` | replays `update`, `NaN` during warmup | | `reset()` | `None` | returns to a freshly-constructed state | | `is_ready()` | `bool` | `True` once the first value has been emitted | diff --git a/Quickstart-R.md b/Quickstart-R.md index 5142a84..64108dd 100644 --- a/Quickstart-R.md +++ b/Quickstart-R.md @@ -43,7 +43,8 @@ The alt-chart bar builders (`RenkoBars()`, `KagiBars()`, …) have no `warmup_period()` / `is_ready()` — a candle can complete 0..n bars, so they have no warmup. -`update()` is O(1) per call. Handles are released by a registered finalizer, so +`update()` never revisits the history behind the tick. Handles are released by +a registered finalizer, so there is nothing to free by hand. ## Streaming and batch side by side diff --git a/Quickstart-WASM.md b/Quickstart-WASM.md index f40a766..cf5bd21 100644 --- a/Quickstart-WASM.md +++ b/Quickstart-WASM.md @@ -76,7 +76,7 @@ for (const price of liveFeed) { } ``` -Every indicator is an O(1)-per-update state machine: `update` advances the +Every indicator is an incremental state machine: `update` advances the indicator by exactly one input, so a browser charting app pays no cost for recomputing history on each tick. diff --git a/Streaming-vs-Batch.md b/Streaming-vs-Batch.md index 83f99c7..d91ed8d 100644 --- a/Streaming-vs-Batch.md +++ b/Streaming-vs-Batch.md @@ -83,8 +83,9 @@ import wickra as ta np.random.seed(0) prices = np.cumsum(np.random.randn(100)) + 100.0 -# Batch path. -batch_out = ta.RSI(14).batch(prices) +# Batch path. `batch` hands back an `array.array('d')`, which NumPy reads +# through the buffer protocol; wrap it to index with a boolean mask below. +batch_out = np.asarray(ta.RSI(14).batch(prices)) # Streaming path: same inputs, fresh indicator, fed one at a time. rsi = ta.RSI(14) @@ -110,9 +111,9 @@ input array. To use it inside a streaming loop, you concatenate each new tick onto your history and call `rsi(history)` again. That's `O(n)` work for every new bar, and the gap widens linearly as `n` grows. -Wickra's `update` is the opposite: each new bar is O(1) because the -recursive smoothing state is already inside the indicator. You never carry -history just to recompute it. +Wickra's `update` is the opposite: a new bar costs the same whether it is the +tenth or the ten-millionth, because the state it needs is already inside the +indicator. You never carry history just to recompute it. The project README carries the full, current benchmark tables; `python -m benchmarks.compare_libraries` and `cargo bench -p wickra-bench` are @@ -121,7 +122,7 @@ the source scripts. In summary: - **Python batch** (20 000-bar full pass): Wickra runs each indicator in roughly 22–130 µs — about 6–47× faster than `finta`, the fastest pure-Python peer that installs cleanly on a desktop. -- **Python streaming** (per tick, O(1) `update`): Wickra updates in roughly +- **Python streaming** (one `update` per tick): Wickra updates in roughly 0.06–0.11 µs/tick, about 11–56× faster than `talipp`, the only Python library with a true incremental API. - **Rust core** (vs the other Rust TA crates `kand`, `ta-rs`, `yata`): an diff --git a/Warmup-Periods.md b/Warmup-Periods.md index ffa23e8..c591d57 100644 --- a/Warmup-Periods.md +++ b/Warmup-Periods.md @@ -44,11 +44,11 @@ index" in 0-indexed terms is `warmup_period − 1`. | `Rocp` | `Rocp::new(12)` | `period + 1` | 13 | 13th | | `Rocr` | `Rocr::new(12)` | `period + 1` | 13 | 13th | | `Rocr100` | `Rocr100::new(12)` | `period + 1` | 13 | 13th | -| `PlusDm` | `PlusDm::new(14)` | `period` (1st candle seeds prev) | 14 | 15th | -| `MinusDm` | `MinusDm::new(14)` | `period` (1st candle seeds prev) | 14 | 15th | -| `PlusDi` | `PlusDi::new(14)` | `period` (1st candle seeds prev) | 14 | 15th | -| `MinusDi` | `MinusDi::new(14)` | `period` (1st candle seeds prev) | 14 | 15th | -| `Dx` | `Dx::new(14)` | `period` (1st candle seeds prev) | 14 | 15th | +| `PlusDm` | `PlusDm::new(14)` | `period + 1` (1st seeds prev) | 15 | 15th | +| `MinusDm` | `MinusDm::new(14)` | `period + 1` (1st seeds prev) | 15 | 15th | +| `PlusDi` | `PlusDi::new(14)` | `period + 1` (1st seeds prev) | 15 | 15th | +| `MinusDi` | `MinusDi::new(14)` | `period + 1` (1st seeds prev) | 15 | 15th | +| `Dx` | `Dx::new(14)` | `period + 1` (1st seeds prev) | 15 | 15th | | `WilliamsR` | `WilliamsR::new(14)` | `period` | 14 | 14th | | `Mfi` | `Mfi::new(14)` | `period` | 14 | 14th | | `Trix` | `Trix::new(15)` | `3 * period - 1` | 44 | 44th | diff --git a/index.md b/index.md index 414094a..246569f 100644 --- a/index.md +++ b/index.md @@ -6,7 +6,7 @@ titleTemplate: false hero: name: Wickra text: Streaming-first technical indicators - tagline: One Rust core. The same O(1) update for live ticks and backtests. Native Rust, Python, Node.js and WASM bindings, plus a C ABI reaching C, C++, C#, Go, Java and R — install-free. + tagline: One Rust core. The same incremental update for live ticks and backtests. Native Rust, Python, Node.js and WASM bindings, plus a C ABI reaching C, C++, C#, Go, Java and R — install-free. image: src: /wickra-mark.svg alt: Wickra @@ -31,7 +31,7 @@ features: - title: 514 indicators, 24 families details: Moving averages, momentum, trend, volatility, bands, volume, statistics, Ehlers/DSP, pivots, DeMark, Ichimoku, candlesticks, market profile, risk/performance, microstructure, derivatives, and market breadth. - title: Same code, live and backtest - details: Every indicator is an O(1) state machine. The update call in your live loop is the exact same code path that drives the historical backtest — no drift. + details: Every indicator is an incremental state machine. The update call in your live loop is the exact same code path that drives the historical backtest — no drift. - title: Install-free everywhere details: pip install wickra · cargo add wickra · npm install wickra. No system compilers, no C dependencies, no headers. The Rust core forbids unsafe. - title: Streaming or batch diff --git a/overview.md b/overview.md index 1839e55..2de7dd5 100644 --- a/overview.md +++ b/overview.md @@ -1,7 +1,7 @@ # Wickra Wickra is a streaming-first technical-indicators library. Every indicator is -implemented in Rust as an O(1) state machine that consumes one input at a +implemented in Rust as an incremental state machine that consumes one input at a time, and the same engine is exposed through ergonomic bindings for Python, Node.js, WASM, and Rust itself, plus a C ABI that any C-capable language (C, C++, C#, Go, Java, R) links against. The same `update` call you write inside @@ -73,7 +73,7 @@ Release notes and tagged builds: the tick-to-candle aggregator, the multi-timeframe resampler, and the Binance live feed. - [Streaming vs Batch](Streaming-vs-Batch) — the conceptual difference - between Wickra's O(1) `update` and the recompute-everything loops in + between Wickra's incremental `update` and the recompute-everything loops in batch-only libraries, with the benchmark numbers from the project README. - [Warmup Periods](Warmup-Periods) — a verified table of every indicator's `warmup_period()`, plus the reasoning behind the off-by-one diff --git a/scripts/run-doc-snippets.mjs b/scripts/run-doc-snippets.mjs new file mode 100644 index 0000000..4aca96b --- /dev/null +++ b/scripts/run-doc-snippets.mjs @@ -0,0 +1,66 @@ +// Execute every JavaScript doc snippet and fail on the ones that throw. +// +// Companion to run_doc_snippets.py, and the same argument: `check-doc-examples.mjs` +// validates that every `ta.` reference resolves and deliberately stops +// there, because many blocks are schematic. A snippet can name everything +// correctly and still be wrong -- passing three arguments where `update` takes +// four, ordering them so a candle's high lands below its low, handing an +// indicator the whole derivatives tick when it takes the two fields it uses. +// Five such blocks shipped. +// +// A block that fails on an undefined identifier or a missing module is +// schematic and does not count. The WASM quickstart's blocks are ES modules and +// cannot run under a CommonJS `Function` wrapper, which is the same thing. +// Anything else is a snippet that throws in a reader's hands, and fails here. +// +// Usage: node scripts/run-doc-snippets.mjs +// Exit code 1 if any snippet throws for a reason a reader would hit. + +import { readFileSync, readdirSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { join } from 'node:path'; + +// Resolve `wickra` from the docs repo, not from this file's directory. +const require = createRequire(join(process.cwd(), 'noop.cjs')); + +const BLOCK = /```(?:js|javascript)\r?\n([\s\S]*?)```/g; +const SCHEMATIC = /is not defined|Cannot find module|no such file|import statement outside a module|await is only valid/i; + +const pages = ['.', 'Indicators'].flatMap((dir) => + readdirSync(dir) + .filter((name) => name.endsWith('.md')) + .map((name) => (dir === '.' ? name : `${dir}/${name}`)), +); + +let clean = 0; +let schematic = 0; +const failures = []; + +for (const page of pages) { + const text = readFileSync(page, 'utf8'); + for (const match of text.matchAll(BLOCK)) { + const line = text.slice(0, match.index).split('\n').length + 1; + try { + // Snippets are written as CommonJS and print with `console.log`; give them + // a real `require` and a silent console. + new Function('require', 'console', match[1])(require, { log() {}, error() {}, warn() {} }); + clean += 1; + } catch (err) { + const message = `${err.constructor.name}: ${err.message}`.split('\n')[0]; + if (SCHEMATIC.test(message)) schematic += 1; + else failures.push(` ${page}:${line}\n ${message}`); + } + } +} + +const total = clean + schematic + failures.length; +console.log( + `ran ${total} js snippets: ${clean} clean, ${failures.length} failing, ` + + `${schematic} schematic (undefined feed, missing module, or an ES module block)`, +); + +if (failures.length) { + console.error('\nsnippets that throw when a reader runs them:'); + console.error(failures.join('\n')); + process.exit(1); +} diff --git a/scripts/run_doc_snippets.py b/scripts/run_doc_snippets.py new file mode 100644 index 0000000..4889e5d --- /dev/null +++ b/scripts/run_doc_snippets.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""Execute every Python doc snippet and fail on the ones that raise. + +`check_doc_examples.py` validates that every `ta.` reference resolves, and +deliberately stops there: many blocks are schematic, looping over a feed that +does not exist, so executing them would raise on undefined names. That leaves a +gap. A snippet can name every symbol correctly and still be wrong -- calling +`update` with the eleven derivatives fields when the indicator takes the three it +uses, feeding a close-only series to something that wants high, low and close, +reaching for `.shape` on a type that has none. Twenty-five such blocks shipped. + +This runs them and sorts the failures. A block that fails on an undefined name, +a missing module or a missing file is schematic and does not count. Anything +else -- a wrong argument count, a rejected candle, an attribute the return type +does not have -- is a snippet that raises in a reader's hands, and fails here. + +`...` is Python's `Ellipsis`, so a block that elides part of a series raises a +TypeError mentioning it. That is a placeholder, not a defect. + +Usage: python scripts/run_doc_snippets.py +Exit code 1 if any snippet fails for a reason a reader would hit. +""" + +from __future__ import annotations + +import contextlib +import glob +import io +import re +import sys + +BLOCK = re.compile(r'```(?:python|py)\r?\n([\s\S]*?)```') +# A schematic block reaches for something this process cannot supply. +SCHEMATIC = (NameError, ModuleNotFoundError, FileNotFoundError, ImportError) + + +def pages() -> list[str]: + return sorted(glob.glob('*.md') + glob.glob('Indicators/*.md')) + + +def main() -> int: + clean = schematic = 0 + failures: list[tuple[str, int, str]] = [] + + for path in pages(): + text = io.open(path, encoding='utf-8').read() + for match in BLOCK.finditer(text): + line = text[: match.start()].count('\n') + 2 + source = match.group(1) + try: + with contextlib.redirect_stdout(io.StringIO()): + exec(compile(source, f'{path}:{line}', 'exec'), {'__name__': '__main__'}) + clean += 1 + except SCHEMATIC: + schematic += 1 + except Exception as exc: # noqa: BLE001 - the point is to see them all + if 'ellipsis' in str(exc).lower(): + schematic += 1 + continue + failures.append((path, line, f'{type(exc).__name__}: {exc}')) + + total = clean + schematic + len(failures) + print(f'ran {total} python snippets: {clean} clean, {len(failures)} failing, ' + f'{schematic} schematic (undefined feed, missing file, or an elided `...`)') + + if failures: + print('\nsnippets that raise when a reader runs them:', file=sys.stderr) + for path, line, message in failures: + print(f' {path}:{line}\n {message}', file=sys.stderr) + return 1 + return 0 + + +if __name__ == '__main__': + raise SystemExit(main())