fix(core): skip non-positive HV prices and add Error::InvalidTick (R13, R14)
R13 — `HistoricalVolatility::update` previously substituted `0.0` for
the log-return whenever `prev <= 0` or `input <= 0`. The log-return is
undefined there, and silently treating bad ticks as "no movement"
underreports realised volatility on broken data feeds. The fix skips
non-positive prices entirely: `self.last` is returned, state is left
untouched, and the next real tick re-anchors against the previous
*valid* `prev_price`. This matches how every other indicator handles
invalid inputs (SMA / EMA / ROC / Bollinger).
A new test `skips_non_positive_prices` proves the invariant: after a
warmed-up indicator, two consecutive bad ticks (`-5.0` and `0.0`) must
return the baseline value, and a subsequent real positive tick must
produce the same output as a control indicator that simply never saw
the bad ticks.
R14 — `Tick::new` previously returned `Error::InvalidCandle` for
negative volume. A tick is not a candle; downstream tick-stream
pipelines should be able to match on a semantically-correct error. A
new `Error::InvalidTick { message }` variant is added; the existing
test is updated to assert against it. Python's `map_err` is extended
to forward the new variant as `PyValueError`; the Node and WASM
bindings format via `Error::to_string()` and pick the new variant up
automatically without source changes.
This commit is contained in:
@@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- `HistoricalVolatility::update` no longer substitutes a `0.0` log-return on
|
||||
non-positive prices (audit finding R13). Negative or zero prices are
|
||||
semantically invalid for a log-return calculation; silently treating them as
|
||||
"no movement" underreported realised volatility. They are now skipped — the
|
||||
previous valid value is returned and the indicator's state (`prev_price`,
|
||||
window, sums) is left untouched — matching how every other indicator handles
|
||||
invalid inputs.
|
||||
- `Tick::new` now returns the new `Error::InvalidTick` variant for negative
|
||||
volume instead of `Error::InvalidCandle` (audit finding R14). A tick is not
|
||||
a candle, and downstream tick-stream pipelines should be able to match on a
|
||||
semantically-correct error. The Python binding's `map_err` was extended to
|
||||
forward the new variant as a `ValueError`; the Node and WASM bindings format
|
||||
via `Error::to_string()` and pick the new variant up automatically.
|
||||
- `Psar::is_ready` now matches the convention shared by every other indicator:
|
||||
`is_ready() == true` iff a real value has been produced (audit finding R6).
|
||||
The previous implementation returned `self.initialised`, which flipped to
|
||||
|
||||
Reference in New Issue
Block a user