08-28-2025, 11:41 AM
Code:
//@version=5
indicator("FFT Top Components (Individual Curves)", overlay=false)
int n = input.int(128, title="Sample Size", minval=32, maxval=512)
int topComponents = input.int(6, title="Top Components", minval=1, maxval=20)
var float[] priceBuffer = array.new_float(n, 0.0)
var int bufferIndex = 0
if bar_index >= n
array.set(priceBuffer, bufferIndex, close)
bufferIndex := (bufferIndex + 1) % n
var float[] amplitudes = array.new_float(n, 0.0)
var float[] phases = array.new_float(n, 0.0)
if bar_index >= n
for k = 0 to n - 1
float re = 0.0
float im = 0.0
for t = 0 to n - 1
float val = array.get(priceBuffer, (bufferIndex + t) % n)
float angle = 2.0 * math.pi * k * t / n
re += val * math.cos(angle)
im -= val * math.sin(angle)
float amp = math.sqrt(re * re + im * im) / n
float phase = re != 0 ? math.atan(im / re) : 0
array.set(amplitudes, k, amp)
array.set(phases, k, phase)
var float[] sortableAmps = array.new_float(0)
var int[] sortableIndices = array.new_int(0)
if bar_index >= n
array.clear(sortableAmps)
array.clear(sortableIndices)
for i = 0 to n - 1
array.push(sortableAmps, array.get(amplitudes, i))
array.push(sortableIndices, i)
int arraySize = array.size(sortableAmps)
for i = 0 to arraySize - 2
for j = i + 1 to arraySize - 1
if array.get(sortableAmps, j) > array.get(sortableAmps, i)
float tempAmp = array.get(sortableAmps, i)
int tempIdx = array.get(sortableIndices, i)
array.set(sortableAmps, i, array.get(sortableAmps, j))
array.set(sortableIndices, i, array.get(sortableIndices, j))
array.set(sortableAmps, j, tempAmp)
array.set(sortableIndices, j, tempIdx)
// Predefine component series
var float comp0 = na
var float comp1 = na
var float comp2 = na
var float comp3 = na
var float comp4 = na
var float comp5 = na
if bar_index >= n
int maxComp = math.min(topComponents - 1, array.size(sortableIndices) - 1)
// Get the current time index within the buffer
float currentTimeIndex = float(bufferIndex)
for i = 0 to maxComp
int idx = array.get(sortableIndices, i)
float amp = array.get(amplitudes, idx)
float phase = array.get(phases, idx)
// Reconstruct component using cosine with corrected phase
float angle = 2.0 * math.pi * idx * (currentTimeIndex - 1) / n
float component = amp * math.cos(angle + phase)
if i == 0
comp0 := component
if i == 1
comp1 := component
if i == 2
comp2 := component
if i == 3
comp3 := component
if i == 4
comp4 := component
if i == 5
comp5 := component
// Plots (global scope)
//plot(comp0, title="Component 0", color=color.blue)
plot(comp1, title="Component 1", color=color.green)
plot(comp2, title="Component 2", color=color.red)
plot(comp3, title="Component 3", color=color.orange)
plot(comp4, title="Component 4", color=color.purple)
plot(comp5, title="Component 5", color=color.aqua)
Code:
//@version=5
indicator(title="Spectrometr", shorttitle="Spectrometr", overlay=false, format=format.price, precision=2)
// ——— Input Parameters
iPeriod = input.int(240, title="Period")
iStartFrom = input.int(1, title="Start From")
AddToObjName = input.string("1", title="Object Name Suffix")
HandlerColor = input.color(color.new(color.gray, 50), title="Handler Line Color")
TextColor = input.color(color.new(color.gray, 50), title="Text Color")
// ——— Custom Variables
ObjNPref = "Spectrometr_" + AddToObjName
LastLeftBar = iStartFrom + iPeriod - 1
LastRightBar = iStartFrom
// ——— Fourier Analysis Function
fFurie(arr) =>
tN = array.size(arr)
tM = int(tN / 2)
aA = array.new<float>(tM, 0.0)
aB = array.new<float>(tM, 0.0)
aR = array.new<float>(tM, 0.0)
for ti = 1 to tM - 1
sumA = 0.0
sumB = 0.0
for tj = 0 to tN - 1
val = array.get(arr, tj)
sumA += val * math.sin(ti * 6.28 * tj / tN)
sumB += val * math.cos(ti * 6.28 * tj / tN)
array.set(aA, ti, 2 * sumA / tN)
array.set(aB, ti, 2 * sumB / tN)
array.set(aR, ti, math.sqrt(math.pow(array.get(aA, ti), 2) + math.pow(array.get(aB, ti), 2)))
[aA, aB, aR]
// ——— Residuals and Fourier Component Calculation
residuals = array.new<float>()
fVals = array.new<float>(8, na)
if bar_index >= iPeriod
// Collect price data
prices = array.new<float>()
for i = 0 to iPeriod - 1
array.push(prices, close[i])
// Estimate linear regression slope and intercept
linreg_slope = ta.sma(ta.change(close), iPeriod)
linreg_val = ta.linreg(close, iPeriod, 0)
// Compute residuals
for i = 0 to iPeriod - 1
lin_val = linreg_val + (iPeriod - 1 - i) * linreg_slope
residual = close[i] - lin_val
array.push(residuals, residual)
// Apply Fourier transform
[A, B, R] = fFurie(residuals)
// Precompute 8 Fourier components
for k = 1 to 8
val = array.get(A, k) * math.sin(k * 6.28 * iPeriod / (iPeriod - 1)) +
array.get(B, k) * math.cos(k * 6.28 * iPeriod / (iPeriod - 1))
array.set(fVals, k - 1, val)
// ——— Plotting Fourier Components (Global Scope)
plot(array.get(fVals, 0), title="F_1", color=color.red, linewidth=2)
plot(array.get(fVals, 1), title="F_2", color=color.orange, linewidth=2)
plot(array.get(fVals, 2), title="F_3", color=color.yellow, linewidth=2)
plot(array.get(fVals, 3), title="F_4", color=color.lime, linewidth=2)
plot(array.get(fVals, 4), title="F_5", color=color.blue, linewidth=2)
plot(array.get(fVals, 5), title="F_6", color=color.new(color.blue, 50), linewidth=2)
plot(array.get(fVals, 6), title="F_7", color=color.new(color.purple, 50), linewidth=2)
plot(array.get(fVals, 7), title="F_8", color=color.gray, linewidth=2)
// ——— Drawing Line and Labels
if bar_index >= iPeriod
line.new(x1=bar_index - LastLeftBar, y1=0, x2=bar_index - LastRightBar, y2=0,
color=HandlerColor, style=line.style_dashed, width=3)
// label.new(x=bar_index, y=0, text="Period: " + str.tostring(iPeriod),
// xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_left,
// color=color.white, textcolor=TextColor)
//label.new(x=bar_index, y=0, text="StartFrom: " + str.tostring(iStartFrom),
// xloc=xloc.bar_index, yloc=yloc.price, style=label.style_label_right,
// color=color.white, textcolor=TextColor)