/**
* Double Exponential Moving Average (DEMA) Indicator
* Moving average designed to reduce lag
*/
import { calculateEMA } from './moving-averages'
export function calculateDEMA(closes: number[], period: number = 20): number[] {
if (closes.length < 3) return []
// Use adaptive period if data is insufficient
const effectivePeriod = Math.min(period, Math.max(2, Math.floor(closes.length / 2)))
const dema: number[] = []
// Calculate EMA(n)
const ema1 = calculateEMA(closes, effectivePeriod)
if (ema1.length === 0) {
// Fallback: return last close
return [closes[closes.length - 1]]
}
// Calculate EMA(EMA(n))
const ema2 = calculateEMA(ema1, Math.min(effectivePeriod, ema1.length))
if (ema2.length === 0) {
// Fallback: return last EMA value
return [ema1[ema1.length - 1]]
}
// DEMA = 2 × EMA(n) - EMA(EMA(n))
const offset = ema1.length - ema2.length
for (let i = 0; i < ema2.length; i++) {
const ema1Idx = i + offset
if (ema1Idx >= 0 && ema1Idx < ema1.length) {
const demaValue = 2 * ema1[ema1Idx] - ema2[i]
dema.push(demaValue)
}
}
return dema.length > 0 ? dema : [closes[closes.length - 1]]
}