Files

59 lines
2.0 KiB
Plaintext

// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Inverse Fast Fourier Transform (IFFT)", "IFFT", overlay=true, precision=6)
//@function Spectral filter via forward DFT + frequency zeroing + inverse DFT
//@param source Series to filter
//@param windowSize DFT window size (power of 2: 32, 64, 128)
//@param numHarmonics Number of lowest-frequency harmonics to keep (1..windowSize/2)
//@returns reconstructed (filtered) value at the current bar
//@optimized Forward O(N*H) + inverse O(H); H = numHarmonics
ifft(series float source, simple int windowSize, simple int numHarmonics) =>
if windowSize != 32 and windowSize != 64 and windowSize != 128
runtime.error("Window size must be 32, 64, or 128")
if numHarmonics < 1
runtime.error("Number of harmonics must be >= 1")
int N = windowSize
int halfN = N / 2
int H = math.min(numHarmonics, halfN)
float twoPiOverN = 2.0 * math.pi / N
float dcRe = 0.0
for n = 0 to N - 1
float val = nz(source[n])
float w = 0.5 - 0.5 * math.cos(twoPiOverN * n)
dcRe += val * w
float result = dcRe / N
for k = 1 to H
float re = 0.0
float im = 0.0
float omega_k = twoPiOverN * k
for n = 0 to N - 1
float val = nz(source[n])
float w = 0.5 - 0.5 * math.cos(twoPiOverN * n)
float xw = val * w
float angle = omega_k * n
re += xw * math.cos(angle)
im -= xw * math.sin(angle)
result += 2.0 * re / N
result
// ---------- Main loop ----------
// Inputs
i_source = input.source(close, "Source")
i_window = input.int(64, "Window Size", options=[32, 64, 128], tooltip="DFT window; larger = finer frequency resolution")
i_harmonics = input.int(5, "Harmonics", minval=1, maxval=32, tooltip="Number of lowest-frequency components to keep; fewer = smoother")
// Calculation
float filtered = ifft(i_source, i_window, i_harmonics)
// Plot
plot(filtered, "IFFT", color=color.yellow, linewidth=2)