Time for action – fitting to a sine

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.

  1. Define a residuals function based on a sine wave model:
    def residuals(p, y, x):
       A,k,theta,b = p
       err = y-A * np.sin(2* np.pi* k * x + theta) + b
       return err
  2. Transform the filtered signal back to the original domain:
    filtered = -fftpack.irfft(fftpack.ifftshift(amps))
  3. Guess the values of the parameters of which we are trying to estimate a transformation from the time domain into the frequency domain:
    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]
    
  4. Call the 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]
    
  5. Finish the first subplot with detrended data, filtered data, and fit of the filtered data. Use a date format for the horizontal axis and add a legend:
    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'})
  6. Add a second subplot with a legend of the main component of the frequency spectrum:
    ax2 = fig.add_subplot(212)
    plt.plot(f, amps, label="transformed")

    The following are the resulting charts:

    Time for action – fitting to a sine

What just happened?

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()
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset