Average True Range in Quant Charts. This Rust indicator computes ATR on TBBO ticks. It is a complete, runnable file.
Quant Charts ATR Indicator Example (Rust, TBBO)
Rust (TBBO): atr.rs
//! qc-api: 1.0.8
// DISCLAIMER: This software is for educational and informational purposes only and does not constitute
// financial advice, investment advice, or trading advice. Past performance is not indicative of future
// results. Trading futures and other financial instruments involves substantial risk of loss. You are
// solely responsible for your own trading decisions. Quant Charts LLC assumes no liability for any
// losses incurred. All rights reserved. (c) Quant Charts LLC
//! ATR (Rust / OHLC bars).
//!
//! Required columns: high, low, close. Data mode: OHLC bars.
//!
//! Wilder ATR over `period` bars. The chart timeframe pill picks the bar
//! cadence (1m, 5m, ...). Three regime tags fire based on ATR vs the day's
//! median bar-ATR. Renders only in OHLC chart views.
use qc_strategy_api::prelude::*;
#[indicator(
name = "ATR",
description = "Wilder ATR with low/medium/high regime tags. OHLC-mode.",
overlay = false,
data_mode = "ohlc",
timeframe = "1m"
)]
#[tag(name = "low_atr", label = "Low ATR", color = "#7AA2F7", description = "Bar ATR below low_mult x median")]
#[tag(name = "medium_atr", label = "Medium ATR", color = "#A1A1AA", description = "Bar ATR between low_mult and high_mult x median")]
#[tag(name = "high_atr", label = "High ATR", color = "#F7768E", description = "Bar ATR above high_mult x median")]
#[derive(Default)]
pub struct Atr {
#[param(default = 14, min = 2, max = 500, label = "ATR Period (bars)",
tooltip = "ATR lookback in bars at the indicator's declared timeframe.")]
pub period: usize,
#[param(default = 0.7, min = 0.0, max = 10.0, step = 0.05, label = "Low Threshold (x median)",
tooltip = "Bar ATR below this many medians = low_atr.")]
pub low_mult: f64,
#[param(default = 1.4, min = 0.0, max = 10.0, step = 0.05, label = "High Threshold (x median)",
tooltip = "Bar ATR above this many medians = high_atr.")]
pub high_mult: f64,
}
impl OhlcIndicator for Atr {
fn calculate(&self, data: &BarData, _prep: &DayPrep) -> IndicatorOutput {
let n = data.len();
if n == 0 || self.period < 2 {
return IndicatorOutput::new().with_overlay(false);
}
// Wilder ATR over bar high/low/close.
let mut atr = vec![f64::NAN; n];
if n > self.period {
let mut tr = vec![0.0; n];
tr[0] = (data.high[0] - data.low[0]).max(0.0);
for i in 1..n {
let h = data.high[i];
let l = data.low[i];
let pc = data.close[i - 1];
tr[i] = (h - l).max((h - pc).abs()).max((l - pc).abs());
}
let p = self.period as f64;
let seed: f64 = tr[..self.period].iter().sum::<f64>() / p;
atr[self.period - 1] = seed;
for i in self.period..n {
atr[i] = (atr[i - 1] * (p - 1.0) + tr[i]) / p;
}
}
// Regime thresholds from the day's median bar ATR.
let mut finite: Vec<f64> = atr.iter().copied().filter(|v| v.is_finite()).collect();
let median_atr = if finite.is_empty() {
f64::NAN
} else {
finite.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
finite[finite.len() / 2]
};
let low_thresh = median_atr * self.low_mult;
let high_thresh = median_atr * self.high_mult;
let mut low_atr = vec![false; n];
let mut medium_atr = vec![false; n];
let mut high_atr = vec![false; n];
for i in 0..n {
let v = atr[i];
if !v.is_finite() {
continue;
}
if v < low_thresh {
low_atr[i] = true;
} else if v > high_thresh {
high_atr[i] = true;
} else {
medium_atr[i] = true;
}
}
IndicatorOutput::new()
.with_overlay(false)
.plot_line("ATR", atr, "#E0AF68")
.with_tag("low_atr", low_atr)
.with_tag("medium_atr", medium_atr)
.with_tag("high_atr", high_atr)
}
}
Machine-readable: full API at /llms-full.txt · examples on GitHub.