3
$\begingroup$

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?

$\endgroup$
2
  • 1
    $\begingroup$ I can't run your code due to missing data, but it seems you subtract the trend from your data by doing -p[0]*t, you possibly need to subtract the mean as well. $\endgroup$ Mar 7, 2021 at 14:22
  • $\begingroup$ You are working with stock price levels, not returns, right? I do not know how well you will be able to extrapolate from levels. $\endgroup$ Mar 7, 2021 at 19:35

1 Answer 1

3
$\begingroup$

Here's a working example for python3.

enter image description here

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()
$\endgroup$
1
  • $\begingroup$ Sheet, that's -30% loss. Oof! $\endgroup$
    – NoName
    Nov 6, 2021 at 4:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.