Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Writing a native indicator

Each native plugin is one Rust file in indicators/src/custom/. The build script discovers those files in deterministic filename order and compiles a static registry into the binary.

Contract

Every indicator declares a name, ordered numeric parameters, and a factory. It receives a public Trade and may yield one finite f64 value. Returning None expresses warm-up; it is not an error. The update method must not block or allocate on the hot path.

#![allow(unused)]
fn main() {
use quince_core::types::Trade;
use quince_indicators::{CustomIndicator, CustomIndicatorError};

struct MyIndicator;

impl CustomIndicator for MyIndicator {
    fn on_trade(&mut self, trade: &Trade) -> Option<f64> {
        (trade.price.is_finite() && trade.price > 0.0).then_some(trade.price)
    }
}
}

Use CustomIndicatorRegistration::validate_params in the factory before constructing state. The engine independently validates the exact @using arguments at strategy startup, so malformed configurations fail before any live connection or order intent.

QFL surface

For a descriptor named custom_example with one period parameter:

@using custom_example:20

on trade(t) {
    feature value = quince.get("custom_example")
}

Names are lowercase ASCII identifiers with digits and underscores allowed after the first character. All current plugins consume trades and expose one scalar value. The name in quince.get must exactly match the descriptor name.

Required checks

Add focused deterministic tests for warm-up, expected output, and invalid parameters. Before merging, run:

cargo +nightly fmt --all -- --check
cargo test --workspace --lib --bins --tests --examples --locked
cargo clippy --workspace --all-targets --no-deps -- -D warnings

For a performance-sensitive indicator, add or run a Criterion scenario against the full QFL pipeline, then compare it to the versioned baseline in CI.