basic_indicator/basic_indicator.rs
1//! Minimal streaming-indicator walkthrough: build an indicator from the registry by name,
2//! feed it a series of validated bars one at a time, and read its output as each bar closes.
3//!
4//! Run with:
5//! ```bash
6//! cargo run --example basic_indicator
7//! ```
8
9use kestrel_chartkit::{build_checked, Bar, Indicator};
10use std::collections::HashMap;
11
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13 // `build_checked` validates parameters against the registry's bounds/ordering rules for the
14 // named indicator (see `kestrel_chartkit::catalog()` for the full list of names and their
15 // default parameters) and returns a boxed `Indicator` trait object.
16 let mut params = HashMap::new();
17 params.insert("rsi_len".to_string(), 14.0);
18 let mut rsi = build_checked("rsi", ¶ms)?;
19
20 // A short synthetic closing-price series. Real feeds should validate bars at the ingestion
21 // boundary with `Bar::try_new` (as here) rather than the unchecked `Bar::new`.
22 let closes = [
23 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,
24 46.28, 46.28, 46.00,
25 ];
26
27 for (i, &close) in closes.iter().enumerate() {
28 let bar = Bar::try_new(
29 1_700_000_000 + i as i64 * 60,
30 close,
31 close + 0.5,
32 close - 0.5,
33 close,
34 1_000.0,
35 )?;
36
37 // `on_bar` returns `None` while the indicator is still warming up (fewer bars seen than
38 // its `warmup_period()`); once warmed up it returns `Some` on every subsequent bar.
39 match rsi.on_bar(&bar) {
40 Some(output) => println!("bar {i:>2}: close={close:.2} RSI(14)={:.2}", output.value),
41 None => println!("bar {i:>2}: close={close:.2} RSI(14)=<warming up>"),
42 }
43 }
44
45 Ok(())
46}