// Band indicators and volume-weighted averaging.
///|
/// Bollinger Bands: upper / middle / lower arrays of equal length. Produced
/// by `bbands`; fields are readable everywhere but the struct is only
/// constructed inside this package.
pub struct BBands {
upper : Array[Double]
middle : Array[Double]
lower : Array[Double]
}
///|
/// Number of leading NaN values produced by `bbands` for the given period.
pub fn bbands_lookback(period : Int32) -> Int32 {
period - 1
}
///|
/// Bollinger Bands over `data` with a moving window of `period` values and
/// `ndev` standard deviations (population stddev, TA-Lib convention).
/// A NaN inside a window makes all three outputs NaN at that position.
pub fn bbands(
data : Array[Double],
period : Int32,
ndev~ : Double,
) -> BBands raise @base.TaError {
@base.validate_series(data, period)
let n = data.length()
let pd = period.to_double()
let upper : Array[Double] = []
let middle : Array[Double] = []
let lower : Array[Double] = []
for i in 0.. Array[Double] raise @base.TaError {
@base.validate_series(price, period)
if volume.length() != price.length() {
raise @base.MismatchedLength("price and volume must have equal lengths")
}
let n = price.length()
let out : Array[Double] = []
for i in 0.. Array[Double] raise @base.TaError {
@base.validate_candles(candles)
let n = candles.close.length()
let out : Array[Double] = []
for i in 0.. hh {
hh = h
}
if l < ll {
ll = l
}
}
}
if valid {
out.push((hh + ll) / 2.0)
} else {
out.push(@base.nan())
}
}
out
}