Discrete Fourier Transform Overlay [wbburgin]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © wbburgin

//@version=5
indicator('Discrete Fourier Transform Overlay [wbburgin]', shorttitle='DFT Overlay [wbburgin]', overlay=true, 
 max_bars_back=2000, max_lines_count=500)

import jdehorty/KernelFunctions/2 as kernel

DFT(x, y, Nx, _dir) =>
    float _arg = 0.0
    float _cos = 0.0
    float _sin = 0.0
    float xArr_i = 0.0
    float yArr_i = 0.0
    xArr = array.new_float(array.size(x))
    yArr = array.new_float(array.size(y))

    for i = 0 to Nx - 1 by 1
        xArr_i := 0.0
        yArr_i := 0.0
        kx = float(i) / float(Nx)
        _arg := -_dir * 2 * math.pi * kx
        for k = 0 to Nx - 1 by 1
            _cos := math.cos(k * _arg)
            _sin := math.sin(k * _arg)
            xArr_i += array.get(x, k) * _cos - array.get(y, k) * _sin
            yArr_i += array.get(x, k) * _sin + array.get(y, k) * _cos
            yArr_i
        array.set(xArr, i, xArr_i)
        array.set(yArr, i, yArr_i)

    if _dir == 1
        for i = 0 to Nx - 1 by 1
            array.set(x, i, array.get(xArr, i) / float(Nx))
            array.set(y, i, array.get(yArr, i) / float(Nx))
    else
        for i = 0 to Nx - 1 by 1
            array.set(x, i, array.get(xArr, i))
            array.set(y, i, array.get(yArr, i))

//======================================================================================================================
//                                                  INPUTS
//======================================================================================================================

N = input.int(20,"Fourier Period")
xval = input.source(close,"Fourier X Series",tooltip = "i.e. the source of the discrete Fourier"+
 " transform (with the Y Series being the bars through time.)")
highlighting = input.bool(true,"Highlighting")
smoothing = input.int(10,"Kernel Smoothing")


//======================================================================================================================
//                                                  CALCULATIONS
//======================================================================================================================

// Fourier transform
x = array.new_float(N, 0.0)
y = array.new_float(N, 0.0)
for i = 0 to N - 1
    array.set(x, i, xval[i])
    array.set(y, i, 0.0)

DFT(x, y, N, 1)

mag = array.new_float(N, 0.0)
for i = 0 to N - 1
    mag_i = math.sqrt(math.pow(array.get(x, i), 2) + math.pow(array.get(y, i), 2))
    array.set(mag, i, mag_i)

dft = array.get(mag,0)
dfts = kernel.rationalQuadratic(dft,25,1,smoothing)

//======================================================================================================================
//                                                  DISPLAY
//======================================================================================================================

ft = plot(dft, "DFT", color= color.white)
fts = plot(dfts, "Smoothing", color = dfts > dft ? color.red : color.lime)

fill(ft,fts,color = highlighting and dfts > dft ? color.new(color.red,75) : highlighting and dfts < dft ? color.new(color.lime,75) : na)