CASOON Open Source
Indicator math, market regimes and signals, one bar at a time.
kestrel-chartkit is a Rust library for technical analysis. It streams bars through indicators, classifies the market regime, weighs indicator readings into one composite signal and draws the result as static SVG.
cargo add kestrel-chartkit- indicators in the registry, built by name
- 105
- golden-reference test suites
- 28
- market regimes, from fixed and documented rules
- 4
- required dependencies without default features
- 0
What it does
Streaming by design
Every indicator implements one trait, consumes one bar at a time and returns nothing until its warmup is complete.
Built from configuration
<code>catalog()</code> lists every indicator with its default parameters; <code>build_checked</code> rejects invalid periods and thresholds with an error instead of a panic.
Signals you can explain
Regime and composite score follow a handful of fixed thresholds. A direction against the regime is vetoed, and every signal carries its subscores.
Pinned against independent references
Numeric results are checked against values derived outside the crate: a second implementation, exact arithmetic or an unambiguous case.
SVG without a front end
Candles, indicator lines, zones and markers render to a self-contained SVG string. Colours can be CSS variables, so one chart serves light and dark pages.
Generated at build time
All examples →Every chart on this site is an SVG written by the crate's own renderer: cargo run --example site_showcase streams synthetic bars with fixed seeds through the indicators.
examples/site/bollinger-bands.svgQuickstart
Add the crate from the repository, build an indicator by name and feed it bars. The full walkthrough lives in the documentation.
- Add the dependency, pinned to a release tag.
- Build an indicator from the registry with
build_checked. - Stream validated bars through
on_barand read the output.
[dependencies]
kestrel-chartkit = "0.11"use kestrel_chartkit::{build_checked, Bar, Indicator};
use std::collections::HashMap;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut params = HashMap::new();
params.insert("rsi_len".to_string(), 14.0);
let mut rsi = build_checked("rsi", ¶ms)?;
let bar = Bar::try_new(1700000000, 100.0, 105.0, 95.0, 104.0, 1000.0)?;
if let Some(output) = rsi.on_bar(&bar) {
println!("RSI Value: {:.2}", output.value);
}
Ok(())
}