Limits of Fourier Extrapolation for Stock Price Forecasting
Summary
The document examines a Fourier-based method for extending historical stock prices and asks why its forecast appears far below the observed price series. One answer provides a revised Python example that uses a linear detrend, transforms the residual series, retains low-frequency components, reconstructs the signal, and adds the trend back. The example offers a way to implement the method, but it does not show that the forecast is reliable.
A second answer explains a core limitation: the Fourier transform represents data through periodic components, so extending a finite input can produce behavior that repeats its training window rather than tracking genuinely new price movements. A reconstruction may therefore fit the historical sample while failing out of sample. The discussion is conceptual and does not report a systematic forecast evaluation; visual alignment or a code adjustment alone is not evidence of predictive value.
Key ideas
- The example detrends prices before applying a Fourier transform and restores the fitted trend afterward.
- Selecting low-frequency components creates a smooth periodic reconstruction of the input series.
- Fourier extrapolation can repeat patterns from the training window instead of forecasting new market behavior.
- A close fit to historical prices does not establish accuracy on future observations.
Tags
Full text
# Fourier transform for stock price forecasting
# Fourier transform for stock price forecasting
I am trying to forecast stock prices using Fast Fourier Transform, and plot historical, "future" (i.e. real) and forecast prices on the same chart to visually compare the accuracy of the forecasting method. However, I am puzzled as to why the output forecast values are much lower than the last input data of the time series itself.
```
import numpy as np
import pylab as pl
from numpy import fft
from pandas_datareader import data
def fourierExtrapolation(x, n_predict):
n = x.size
n_harm = 50
t = np.arange(0, n)
p = np.polyfit(t, x, 1)
x_notrend = x - p[0] * t
x_freqdom = fft.fft(x_notrend)
f = fft.fftfreq(n)
indexes = list(range(n))
indexes.sort(key=lambda i: np.absolute(f[i]))
t = np.arange(0, n + n_predict)
restored_sig = np.zeros(t.size)
for i in indexes[:1 + n_harm * 2]:
ampli = np.absolute(x_freqdom[i]) / n
phase = np.angle(x_freqdom[i])
restored_sig += ampli * np.cos(2 * np.pi * f[i] * t + phase)
return restored_sig + p[0] * t
df = data.DataReader('AAPL', 'yahoo', '2017-01-01', '2021-02-28')
hist_prices = df.loc[:'2020-11-01','Adj Close']
fut_prices = df.loc['2020-11-01':,'Adj Close']
extrapolation = fourierExtrapolation(hist_prices, len(fut_prices)-len(hist_prices))
```
Now when I print the extrapolated values, they are very low compared to `hist_prices` and `fut_prices` which becomes very apparent by running the below code:
```
pl.plot(fut_prices.index, extrapolation, 'r', label='extrapolation')
pl.plot(hist_prices.index, hist_prices, 'b', label='x_hist', linewidth=1)
pl.plot(fut_prices.index, fut_prices, 'g', label='x_real', linewidth=1)
pl.legend()
pl.show()
```
What am I missing? Why isn't my forecast series in the same order of magnitude with the input prices?
## Answer by Sergei Rodionov (score 3)
https://quant.stackexchange.com/a/61577
Here's a working example for python3.
```
import numpy as np
import pylab as pl
from numpy import fft
from datetime import datetime
from pandas_datareader import data as pdr
"""
https://gist.github.com/tartakynov/83f3cd8f44208a1856ce
"""
def fourierExtrapolation(x, n_predict):
n = x.size
n_harm = 50
t = np.arange(0, n)
p = np.polyfit(t, x, 1)
x_notrend = x - p[0] * t
x_freqdom = fft.fft(x_notrend)
f = fft.fftfreq(n)
indexes = list(range(n))
indexes.sort(key=lambda i: np.absolute(f[i]))
#indexes.sort(key=lambda i: np.absolute(x_freqdom[i]))
#indexes.reverse()
t = np.arange(0, n + n_predict)
restored_sig = np.zeros(t.size)
for i in indexes[:1 + n_harm * 2]:
ampli = np.absolute(x_freqdom[i]) / n
phase = np.angle(x_freqdom[i])
restored_sig += ampli * np.cos(2 * np.pi * f[i] * t + phase)
return restored_sig + p[0] * t
data = pdr.get_data_yahoo('AAPL', datetime(2017, 1, 1), datetime(2022, 1, 1))
hist = data.loc[:,'Adj Close'].values
train = data.loc[:'2020-11-01','Adj Close'].values
n_predict = len(hist) - len(train)
extrapolation = fourierExtrapolation(train, n_predict)
pl.plot(np.arange(0, hist.size), hist, 'b', label = 'Data', linewidth = 3)
pl.plot(np.arange(0, train.size), train, 'c', label = 'Train', linewidth = 2)
pl.plot(np.arange(0, extrapolation.size), extrapolation, 'r', label = 'Predict', linewidth = 1)
pl.legend()
pl.show()
```
## Answer by qwertydotplus (score 1)
https://quant.stackexchange.com/a/85850
because the Fourier Transform takes as input one period of a periodic waveform, thus an extrapolation from any modification of the FT will "try to be" periodic with a period equal to your input data (the "extrapolation" will end up being approximately a shifted copy of your input regardless of how you massage the data). you should read up on how the FT works and try to make your model look further into the future. your "extrapolation" will almost certainly better match the "training" data than the future data.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.