shape-runtime 0.3.2

Bytecode compiler, builtins, and runtime infrastructure for Shape
Documentation
/// @module std::finance::indicators::volume
/// Volume Indicators
/// Volume analysis tools

from std::core::utils::rolling use { rolling_sum }
from std::core::utils::vector use { select }

/// Compute on-balance volume.
pub @warmup(1) fn obv(close, volume) {
    let prev_close = __intrinsic_shift(close, 1);
    
    // sign: 1 if close > prev, -1 if close < prev, 0 if equal
    let up = close > prev_close;
    let down = close < prev_close;
    
    // sign = up ? 1 : (down ? -1 : 0)
    let sign = select(up, 1.0, select(down, -1.0, 0.0));
    
    let signed_volume = sign * volume;
    
    __intrinsic_cumsum(signed_volume)
}

/// Compute cumulative or rolling VWAP depending on `period`.
///
/// @note `period = 0` selects cumulative VWAP from the start of the series.
pub @warmup(period) fn vwap(price, volume, period = 0) {
    // Standard VWAP is cumulative from start of data (period=0 or omitted)
    // Rolling VWAP uses a window.
    
    if period > 0 {
        // Rolling VWAP
        let pv = price * volume;
        let pv_sum = rolling_sum(pv, period);
        let v_sum = rolling_sum(volume, period);
        pv_sum / v_sum
    } else {
        // Cumulative VWAP (Anchor: Start of data)
        // TODO: Session-anchored VWAP requires time inspection (reset at 00:00)
        let pv = price * volume;
        let pv_cum = __intrinsic_cumsum(pv);
        let v_cum = __intrinsic_cumsum(volume);
        pv_cum / v_cum
    }
}

/// Compute the accumulation/distribution line.
pub @warmup(1) fn ad(high, low, close, volume) {
    // Money Flow Multiplier = ((Close - Low) - (High - Close)) / (High - Low)
    // MFM = (2*Close - Low - High) / (High - Low)
    
    let mfm_num = (2 * close) - low - high;
    let mfm_den = high - low;
    
    // Handle div by zero if High == Low
    let mfm = select(mfm_den > 0.0, mfm_num / mfm_den, 0.0);
    
    let mfv = mfm * volume;
    
    __intrinsic_cumsum(mfv)
}