shape-runtime 0.2.0

Bytecode compiler, builtins, and runtime infrastructure for Shape
Documentation
// Average True Range (ATR) Indicator
//
// ATR measures market volatility by decomposing the entire range of an asset price
// for that period. It was developed by J. Welles Wilder Jr.

// Need one extra candle for true range calculation
/// Compute ATR from the implicit `candle` series in candle-scoped indicator code.
///
/// @see std::finance::indicators::volatility::atr
pub @warmup(period + 1) fn atr_candle(period = 14) {
    // Calculate True Range for each candle
    let tr_values = []
    
    // Calculate true range for the period
    for i in range(period) {
        let high = candle[-i].high
        let low = candle[-i].low
        let prev_close = candle[-i-1].close
        
        // True Range is the greatest of:
        // 1. Current High - Current Low
        // 2. |Current High - Previous Close|
        // 3. |Current Low - Previous Close|
        let tr = max(
            high - low,
            abs(high - prev_close),
            abs(low - prev_close)
        )
        
        tr_values = push(tr_values, tr)
    }
    
    // Calculate the average of the true ranges
    if length(tr_values) < period {
        return None  // Not enough data
    }
    
    // Use Wilder's smoothing method (similar to EMA)
    let atr_value = avg(slice(tr_values, 0, period))  // Initial ATR
    
    for i in range(period, length(tr_values)) {
        atr_value = ((atr_value * (period - 1)) + tr_values[i]) / period
    }
    
    return atr_value
}

/// Build ATR-based upper and lower bands around the current close.
pub @warmup(period + 1) fn atr_bands(period = 14, multiplier = 2.0) {
    let atr_value = atr_candle(period)
    
    if atr_value == None {
        return None
    }
    
    let current_close = candle[0].close
    
    return {
        upper: current_close + (atr_value * multiplier),
        middle: current_close,
        lower: current_close - (atr_value * multiplier),
        atr: atr_value
    }
}

/// Express ATR as a percentage of the current close.
pub @warmup(period + 1) fn atr_percent(period = 14) {
    let atr_value = atr_candle(period)
    
    if atr_value == None {
        return None
    }
    
    let current_close = candle[0].close
    
    // Return ATR as percentage of current price
    return (atr_value / current_close) * 100
}