Skip to main content

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", &params)?;
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}