Files
wickra/docs/wiki/Quickstart-Rust.md
T
kingchenc 896b71fc62 release(0.1.5): bump versions, finalize CHANGELOG, fail loud on missing platform binaries (R20, Z2)
Versions bumped to 0.1.5 in every authoritative location:

- workspace `Cargo.toml` (`[workspace.package].version`, the
  `wickra-core` path dependency pin).
- `bindings/python/pyproject.toml`.
- `bindings/node/package.json` (main + all six `optionalDependencies`
  pins).
- All six per-platform `bindings/node/npm/<target>/package.json`
  templates.

CHANGELOG: the accumulated `[Unreleased]` block is promoted to
`[0.1.5] - TBD` (date left for the user to set at tag time); the new
`[Unreleased]` header sits empty above it; the compare link table is
extended with `[0.1.5]: …compare/v0.1.4...v0.1.5` and the
`[Unreleased]` link is repointed to `…compare/v0.1.5...HEAD`.

Wiki refresh for 0.1.5 (R20 + Z2):

- `Home.md` version pin table updated; the Quickstart-Node hint replaces
  the "spam filter holding back Windows" caveat with "0.1.5 is the
  first release in which `npm install wickra` works end-to-end on
  Windows" (npm Support released the name on 2026-05-22).
- `Quickstart-Node.md`'s Windows caveat is rewritten to explain the
  history (`0.1.1`–`0.1.4` of `wickra-win32-x64-msvc` are burned) and
  the resolution (0.1.5+ installs cleanly).
- `Quickstart-Rust.md` version mention bumped.
- `Warmup-Periods.md` note bumped + corrected: every Node and WASM
  class — single- and multi-output — now exposes `warmupPeriod()` after
  R3 (this branch), not only the single-output ones.

`release.yml` `publish_dir` no longer silently swallows a
second-attempt platform-package publish failure with a `::warning::`
and `return 0`. A real failure (after the existing 30s retry) now
emits an `::error::` and fails the job. The original mask is exactly
what allowed the `wickra-win32-x64-msvc@0.1.1–0.1.4` spam-filter
rejections to land four times in a row without anyone noticing (audit
finding R20). Failing loud means the next regression of this shape is
caught at the release run, not by a Windows user trying to
`require('wickra')`.

This commit does NOT push, tag, or trigger a release — the user
publishes the 0.1.5 tag themselves once the manual npm-republish
smoke test confirms `wickra-win32-x64-msvc@0.1.5` accepts publish on
the freshly-released name.
2026-05-23 10:58:08 +02:00

143 lines
4.6 KiB
Markdown

# Quickstart: Rust
A five-minute tour of the Wickra Rust crate. By the end you will have run a
batch SMA, fed an RSI tick by tick, and composed two indicators with `Chain`.
## Install
```bash
cargo add wickra
```
The default features pull in `parallel` (rayon-based `batch_parallel`); turn
them off with `cargo add wickra --no-default-features` if you want a leaner
build. The `wickra` crate is a thin façade that re-exports everything from
`wickra-core`; you can also depend on `wickra-core` directly if you want to
skip the façade.
The published crate is at version `0.1.5` on
[crates.io](https://crates.io/crates/wickra).
## The `Indicator` trait in 30 seconds
Every indicator implements the same trait:
```rust
pub trait Indicator {
type Input;
type Output;
fn update(&mut self, input: Self::Input) -> Option<Self::Output>;
fn reset(&mut self);
fn warmup_period(&self) -> usize;
fn is_ready(&self) -> bool;
fn name(&self) -> &'static str;
}
```
`update` is O(1) in the input length. The companion trait `BatchExt` is a
blanket extension that adds a `batch(&[Self::Input])` method to every
indicator — its default implementation is literally a loop over `update`, so
batch and streaming results are bit-for-bit identical.
## Batch and streaming side by side
```rust
use wickra::{BatchExt, Indicator, Rsi, Sma};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Batch: SMA(3) over five prices.
let mut sma = Sma::new(3)?;
let out: Vec<Option<f64>> = sma.batch(&[1.0, 2.0, 3.0, 4.0, 5.0]);
println!("{:?}", out);
// -> [None, None, Some(2.0), Some(3.0), Some(4.0)]
// 2. Streaming: feed Wilder's textbook example into RSI(14).
let mut rsi = Rsi::new(14)?;
let prices = [
44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84, 46.08,
45.89, 46.03, 45.61, 46.28, 46.28, 46.00, 46.03, 46.41,
];
for (tick, price) in prices.iter().enumerate() {
if let Some(v) = rsi.update(*price) {
println!("tick {:2} close={:.2} rsi={:.4}", tick + 1, price, v);
}
}
Ok(())
}
```
The streaming loop prints:
```
tick 15 close=46.28 rsi=70.4641
tick 16 close=46.00 rsi=66.2496
tick 17 close=46.03 rsi=66.4809
tick 18 close=46.41 rsi=69.3469
```
The first value lands on tick 15 because `Rsi::new(14)?.warmup_period() == 15`
(14 diffs to seed Wilder's smoothing, so the 15th input emits the first RSI).
The `70.4641` value matches the textbook value pinned by the unit test
`classic_wilder_textbook_values` in `crates/wickra-core/src/indicators/rsi.rs`.
## Composing indicators with `Chain`
`Chain<A, B>` wires the output of `A` straight into the input of `B`, provided
both stages agree on `f64` as the bridging type. The chain itself is an
`Indicator`, so you can stack three stages with `.then(c)`, or four with
`.then(c).then(d)`.
```rust
use wickra::{Chain, Ema, Indicator, Rsi};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// RSI(7) computed on the output of EMA(14).
let mut chain = Chain::new(Ema::new(14)?, Rsi::new(7)?);
for i in 1..=22 {
if let Some(v) = chain.update(f64::from(i)) {
println!("chain emitted at input #{i}: {v}");
}
}
println!("chain.warmup_period() = {}", chain.warmup_period());
Ok(())
}
```
Output:
```
chain emitted at input #21: 100
chain emitted at input #22: 100
chain.warmup_period() = 22
```
`Ema::new(14)` needs 14 inputs to seed and `Rsi::new(7)` needs 8 more once
the EMA starts flowing, so the chain emits its first value at input 21. The
`warmup_period()` reported by `Chain` is a conservative `first + second` sum
(here `14 + 8 = 22`); see [Indicator Chaining](Indicator-Chaining.md) for the
exact contract.
## A deeper example
`examples/rust/src/bin/backtest.rs` (in the `wickra-examples` workspace
crate) computes a panel of indicators (RSI, EMA, Bollinger, MACD, ATR, ADX,
OBV) over an OHLCV CSV by way of `wickra-data`:
```bash
cargo run --release -p wickra-examples --bin backtest -- path/to/ohlcv.csv
```
For live-data work, `wickra-data` ships a streaming CSV reader, a
tick-to-candle aggregator, a candle resampler, and a Binance kline WebSocket
adapter under the `live-binance` feature. `examples/rust/src/bin/live_binance.rs`
is the canonical example for the latter.
## See also
- [Quickstart: Python](Quickstart-Python.md) — same engine, NumPy-flavoured.
- [Streaming vs Batch](Streaming-vs-Batch.md) — the `batch == repeated update`
contract and the benchmark numbers it buys you.
- [Indicator Chaining](Indicator-Chaining.md) — three-stage chains and the
stacked-warmup rule.
- Source: <https://github.com/kingchenc/wickra>