Hey everyone! 👋

After the last two posts on Fourier analysis – and one five extra coffees running through my veins – today I’m diving into the idea of predicting the futuuuuure! Yep, you heard me!

But before I go full preacher mode like the best Jehovah's Witness I know – you know, the one next to supermarket who talks to everyone – let me make something clear: this article won’t revolutionize Wall Street overnight. The goal here is just to show you whether this kind of thing is technically possible. Spoiler: it is. Otherwise, you wouldn’t be reading this.😏

First things first – puts on my best tie and sharpest tuxedo – here are the assumptions I’m working with:

  • I dare to believe that deterministic cycles exist in the markets and that if I’m clever enough, I can take advantage of them. Now... the word “deterministic” is really the core issue here.
  • I know that Fourier analysis can break down pretty much any function into cycles, which could help me identify those sneaky cycles and put them to good use.

To better understand the method, I recommend checking out my article on Fourier analysis in trading. But don’t worry, it’s not a must-read! I’m sure you’ll be able to follow just fine… but hey, a little self-promo never hurts, right? 😄

Here’s the plan for this wild ride :

  1.  Cool Introduction – (check ✔️)
  2.  Using fast fourier transform (FFT) in Python  
    1. Performing an FFT
    2. Analyzing the results (amplitude AND phase)
  3.  Signal Processing via Amplitude
    1. Amplitude filtering
    2. Forecasting using amplitude
  4.  Signal Processing via Frequencies
    1. Frequency filtering
    2. Forecasting using frequencies
  5.  A quick conclusion 
 

Using FFT in Python

Alright... let's get to work!

To put together at least a half-decent case that I'm not completely out of my mind, I'm going to try to show that I can technically predict the daily closing price of the S&P500 for the next 30 days – yes, I know, incredibly original – and I’m going to do it using Fourier theory.

First key point – and already a crucial one – is that I want to perform a DAILY analysis. That means I can’t just import daily data, otherwise I’d be stomping on the heart of our collective father – Nyquist 💖 – because I’d only be able to study phenomena that evolve over 2 days or more. 

So, I need data sampled at least at half the period of what I’m interested in. In other words, two points minimum are required to define a wave, so I need to sample at twice the frequency of interest.

And since I’m not really in the mood to complicate things, I decided to go with hourly data.

import yfinance as yf
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Get the historical data
ticker_symbol = "^GSPC"
ticker = yf.Ticker(ticker_symbol)
data = ticker.history(interval="1h", period="2y")

 

As for the code – nothing revolutionary going on there. And here’s the plot of the closing prices:

S&P Closing price

And now, this is where things start to get a little more complex – read: a whole lot cooler.

 

How to do a FFT in Python ?

We can clearly observe a trend in the signal, which corresponds to a zero-frequency component. And that’s where the trouble begins: it absolutely needs to be removed, otherwise it will mess up our spectrum and ruin the entire analysis because it will show a huge spike at 0 . So take this as your personal mission to make it vanish—kind of like in Hitman, but with more hair—at least for you; I’m already rocking Agent 47’s default skin. 👨‍🦲

In general, we try to model this trend and then subtract it from our signal, but there are several ways to go about it. Let’s walk through the options together, with some use cases to help you choose wisely:

  • Linear modeling over the interval
  • Polynomial modeling over the interval
  • Moving average (like EMA)
  • Differential filter
  • Time series differencing
 

So, how do you choose?

It really depends on your goal:

  • If you're doing analysis or training other models, I think an EMA (Exponential Moving Average) or polynomial modeling is a solid choice. EMA is practical because it stays close to the actual values—just make sure to pick a large enough period so it doesn’t overreact to noise. For instance, an EMA 200 is great for capturing trends while still reflecting price fluctuations. But be careful: slower signals above 200 periods might not be well captured by a Fourier transform later, because you're working with a smoothed average over 200 periods.

Alternatively, a low-degree polynomial as low as possible, thank you Occam’s razor is also a good choice. It's a more "mathematical" approach and can be optimized using least squares. Both methods are valid, but polynomials get a small edge: there's a unique curve that fits your points, whereas with EMA, you get a bunch of possible outcomes—and more ways to screw things up.😑

For the signal processing nerds, a differential filter is also an option. Fancy! But beware of artifacts and the extra cleanup work they require. So unless you're comfy with that, stick with simpler tools. Trust me, just being able to say "I apply Fourier theory to trading" gives you a digital ego boost big enough—you don’t need to go further.😌

  • If you're doing prediction (which, let’s admit it, is the exciting part), you want simple methods that make the fewest assumptions. So forget EMA and high-degree polynomials—they're not built for forecasting, and extrapolation with them can get messy fast. Instead, go for linear models or differentiation. Linear models are easy to extend forward, and differentiation is the simplest way to remove trends. Though it often strips the "personality" of the curve—yes, not a math concept, more of a psychological one. But you’ll get it after spending 20 hours a day talking to your charts.

In this article, I want to make predictions as simply as possible, so I opted for differentiation. Here's what’s commonly referred to as "returns":

S&P hourly Returns

Once the signal is detrended, we want to apply the FFT. But here again, keep in mind that we used hourly data to analyze daily trends. Since there are 7 trading hours in a day, our time step is 1/7 (dt).

And that’s the only thing you need to remember—after that, we just let numpy do its magic!👍

# Returns
x = data['Close'].diff().dropna().values

# Sampling parameters
dt = 1 / 7  # Assuming 1 data point per day, so 1/7 weeks between samples
n = len(x) # Number of point in the signal

# FFT 
freqs = np.fft.fftfreq(n, d=dt) # create a frequency axis
spectrum = np.fft.fft(x, n) # n is for good practice here !
 
Anyway, as you already know, our resulting spectrum is made of a real part and an imaginary part. We usually plot the amplitude of the spectrum because we care about the absolute impact of each frequency. Also, remember that when plotting, we only use the positive frequencies. Here’s how we display the amplitude:
plt.plot(freqs[:n//2], np.abs(spectrum[:n//2]))  # positive half
 
Now, let’s talk about phase. Yes, the Phase.
She’s the elegant one. The mysterious one. The one people plot just to say they did, then move on to the magnitude like that’s the only thing that matters.

Phase isn’t just a pretty curve—it’s full of emotion too. Once you take the time to open it up, you’ll find it’s brimming with beauty and affection. And no, I'm not making any weird metaphors about women, this is strictly signal processing.😏

To truly appreciate it, we need to look at the unwrapped phase. That’s right: no more jumps and sudden flips like a hyperactive squirrel. We reveal its full poetic form with this line:

unwrapped_phase = np.unwrap(np.angle(spectrum)) 

 

Unwrapping it. Slowly. Gently. Respectfully, of course...Like every beautiful present deserves on Christmas morning.

What I trully want to unwrap !
Oops. Too vivid?
But hey, I bet some of you have way filthier minds — prove me right, the floor’s yours 👇
Anyway, here are the amplitude and unwrapped phase of our spectrum:

Amplitude Spectrum

Phase Spectrum
From the amplitude spectrum, we can see that all frequencies are present and none really stand out. Which is logical because, unfortunately, we’re looking at the classic amplitude spectrum of white noise!

This spectrum aligns with the idea that returns don’t have any structure and carry very little information. For the curious minds out there, we could look into fractional differencing to preserve some information while removing the DC component.

But this doesn’t invalidate the method—far from it. We can now move on to phase analysis.
Here, the phase seems linear judging by the R² value, which suggests all the frequency components remain synchronized with each other, without distortion i.e., long cycles don’t suddenly turn into short ones—which is pretty convenient, you’d agree. 😉

In short, this is reassuring because:
  • The signal is stable: each frequency stays consistent, and the signal transitions smoothly from one time point to another without distortion.
  • Predictability improves: no distortion means you can extrapolate without warping the signal—so you can just extend the existing components without having to worry about distortion, chirps, or other headaches. 
 

Intermission 1

You now know how to apply an FFT using NumPy!
For the group in the back, here’s the method:

  1. Choose a sampling frequency at least twice as high as the highest frequency you want to analyze (shoutout to Father Nyquist).
  2. Remove the DC component (mean value) from the signal.
  3. Be mindful of the sampling frequency.
  4. Apply np.fft.fftfreq and np.fft.fft.
  5. Only display the positive frequencies.
  6. Analyze both the amplitude spectrum AND the phase.

Now go grab some popcorn and a glass of water — we’re about to dive into filtering and prediction.
Next part coming up! 🍿💧📈

 

Don’t hesitate to comment, share, and most importantly, code! 
I wish you an excellent day and lots of success in your trading projects!  
La Bise et à très vite! ✌️