// Rate-of-change family: ROC, MOM, CMO, APO and PPO.
///|
/// Number of leading NaN values produced by `roc` for the given period.
pub fn roc_lookback(period : Int32) -> Int32 {
period
}
///|
/// Rate of change in percent: `100 * (x[i] - x[i - period]) / x[i - period]`.
/// A zero base value yields NaN.
pub fn roc(
data : Array[Double],
period : Int32,
) -> Array[Double] raise @base.TaError {
@base.validate_series(data, period)
let n = data.length()
let out : Array[Double] = []
for i in 0.. Int32 {
period
}
///|
/// Momentum: `x[i] - x[i - period]`. NaN inputs yield NaN.
pub fn mom(
data : Array[Double],
period : Int32,
) -> Array[Double] raise @base.TaError {
@base.validate_series(data, period)
let n = data.length()
let out : Array[Double] = []
for i in 0.. Int32 {
period
}
///|
/// Chande Momentum Oscillator:
/// `100 * (sum_up - sum_down) / (sum_up + sum_down)` over the last `period`
/// price changes. A completely flat window reads 0.
pub fn cmo(
data : Array[Double],
period : Int32,
) -> Array[Double] raise @base.TaError {
@base.validate_series(data, period)
let n = data.length()
// Signed per-bar changes split into up/down series; each window then only
// reads two O(n) rolling sums.
let ups : Array[Double] = []
let downs : Array[Double] = []
ups.push(@base.nan())
downs.push(@base.nan())
for j in 1.. 0.0 {
ups.push(d)
downs.push(0.0)
} else {
ups.push(0.0)
downs.push(-d)
}
}
let sum_up = @base.rolling_sum(ups, period)
let sum_down = @base.rolling_sum(downs, period)
let out : Array[Double] = []
for i in 0.. Array[Double] raise @base.TaError {
@base.validate_series(data, slow_period)
if fast_period <= 0 || slow_period <= 0 {
raise @base.InvalidPeriod("all periods must be positive")
}
if fast_period >= slow_period {
raise @base.InvalidPeriod("fast_period must be smaller than slow_period")
}
let fast_ma = @overlap.moving_average(data, fast_period, ma_type~)
let slow_ma = @overlap.moving_average(data, slow_period, ma_type~)
let n = data.length()
let out : Array[Double] = []
for i in 0.. Array[Double] raise @base.TaError {
@base.validate_series(data, slow_period)
if fast_period <= 0 || slow_period <= 0 {
raise @base.InvalidPeriod("all periods must be positive")
}
if fast_period >= slow_period {
raise @base.InvalidPeriod("fast_period must be smaller than slow_period")
}
let fast_ma = @overlap.moving_average(data, fast_period, ma_type~)
let slow_ma = @overlap.moving_average(data, slow_period, ma_type~)
let n = data.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..