In the previous Time for action section, we created a simple filter for detrended data. Now, let's use a more restrictive filter that will leave us only with the main frequency component. We will fit a sinusoidal pattern to it and plot our results. This model has four parameters—amplitude, frequency, phase, and vertical offset.
def residuals(p, y, x): A,k,theta,b = p err = y-A * np.sin(2* np.pi* k * x + theta) + b return err
filtered = -fftpack.irfft(fftpack.ifftshift(amps))
N = len(qqq) f = np.linspace(-N/2, N/2, N) p0 = [filtered.max(), f[amps.argmax()]/(2*N), 0, 0] print("P0", p0)
The initial values appear as follows:
P0 [2.6679532410065212, 0.00099598469163686377, 0, 0]
leastsq()
function:plsq = optimize.leastsq(residuals, p0, args=(filtered, dates)) p = plsq[0] print("P", p)
The final parameter values are as follows:
P [ 2.67678014e+00 2.73033206e-03 -8.00007036e+03 -5.01260321e-03]
plt.plot(dates, y, 'o', label="detrended") plt.plot(dates, filtered, label="filtered") plt.plot(dates, p[0] * np.sin(2 * np.pi * dates * p[1] + p[2]) + p[3], '^', label="fit") fig.autofmt_xdate() plt.legend(prop={'size':'x-large'})
ax2 = fig.add_subplot(212) plt.plot(f, amps, label="transformed")
The following are the resulting charts:
We detrended one year of price data for QQQ. This signal was then filtered until only the main component of the frequency spectrum was left over. We fitted a sine to the filtered signal using the scipy.optimize
module (see optfit.py
):
from __future__ import print_function from matplotlib.finance import quotes_historical_yahoo import numpy as np import matplotlib.pyplot as plt from scipy import fftpack from scipy import signal from matplotlib.dates import DateFormatter from matplotlib.dates import DayLocator from matplotlib.dates import MonthLocator from scipy import optimize start = (2010, 7, 25) end = (2011, 7, 25) quotes = quotes_historical_yahoo("QQQ", start, end) quotes = np.array(quotes) dates = quotes.T[0] qqq = quotes.T[4] y = signal.detrend(qqq) alldays = DayLocator() months = MonthLocator() month_formatter = DateFormatter("%b %Y") fig = plt.figure() fig.subplots_adjust(hspace=.3) ax = fig.add_subplot(211) ax.xaxis.set_minor_locator(alldays) ax.xaxis.set_major_locator(months) ax.xaxis.set_major_formatter(month_formatter) ax.tick_params(axis='both', which='major', labelsize='x-large') amps = np.abs(fftpack.fftshift(fftpack.rfft(y))) amps[amps < amps.max()] = 0 def residuals(p, y, x): A,k,theta,b = p err = y-A * np.sin(2* np.pi* k * x + theta) + b return err filtered = -fftpack.irfft(fftpack.ifftshift(amps)) N = len(qqq) f = np.linspace(-N/2, N/2, N) p0 = [filtered.max(), f[amps.argmax()]/(2*N), 0, 0] print("P0", p0) plsq = optimize.leastsq(residuals, p0, args=(filtered, dates)) p = plsq[0] print("P", p) plt.title('Detrended and filtered signal') plt.plot(dates, y, 'o', label="detrended") plt.plot(dates, filtered, label="filtered") plt.plot(dates, p[0] * np.sin(2 * np.pi * dates * p[1] + p[2]) + p[3], '^', label="fit") fig.autofmt_xdate() plt.legend(prop={'size':'x-large'}) plt.grid() ax2 = fig.add_subplot(212) plt.title('Tranformed signal') ax2.tick_params(axis='both', which='major', labelsize='x-large') plt.plot(f, amps, label="transformed") plt.legend(prop={'size':'x-large'}) plt.grid() plt.tight_layout() plt.show()