Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing Kalman Filter for Pair Trading Strategy Enhancement #7

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
42 changes: 42 additions & 0 deletions kalman_filter.q
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Reference
// https://www.quantstart.com/articles/State-Space-Models-and-the-Kalman-Filter/

// Auxiliary functions
// Creates a diagonal matrix
eye:{(2#x)#1f,x#0f}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this shorter version :)

Suggested change
eye:{(2#x)#1f,x#0f}
eye:{{x=/:x}til x}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try that but I dont know if it is going to cause some problems as we need floats and not booleans or integers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't cause problems, try e.g.: 4f*eye 4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation causes problems, I think it has to do with types

// Creates a 0's symetric matrix
zeros: {(x#0f)}
// JUST WORKS FOR 1X2 MATRIXES -> transform a 1x2 matrix to 2x1
transpose: {enlist each x}

// This function implements the Kalman Filter algorithm to estimate the state of a linear dynamic system.
// It takes the following parameters:
/ x: The observation matrix (measurement) at time t.
/ y: The state transition matrix (predicted state) at time t.
/ delta: The observation covariance matrix, representing the uncertainty in the measurements.
/ estimates: The estimated state mean vector at time t-1.
/ covariances: The estimated state covariance matrix at time t-1.

// The function returns:
/ estimates: estimated updated state mean vector at time t
/ covariances: estimated updated state covariance matrix at time t.

kalmanFilter:{[x;y;delta;estimates; covariances]
// Initialize static values
G: eye 2;
W: (delta % (1-delta)) * eye 2;
V: 1f;
m0: estimates;
c0: covariances;
Ft: x, 1f;

alphat: G mmu m0; // a_t = G_t * m_t-1 (EQ 1)
Rt: ((G mmu c0) mmu flip[G]) + W; // R_t = G_t * C_t-1 * T(G) + W_t (EQ 2)
ft: Ft mmu alphat; // f_t = T(F_t) * a_t (EQ 5)
et: y - ft; // e_t = y_t - f_t (EQ 3)
Qt: ((Ft mmu Rt) mmu transpose[Ft]) + V; // Q_t = T(F_t) * R_t * F_t + V_t (EQ 6)
At: ((Rt mmu transpose[Ft]) mmu 1%Qt); // A_t = R_t * F_t * inv(Q_t) (EQ 7)
mt: (At *\: et) + alphat; // m_t = a_t + A_t * e_t (EQ 4)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using each right\:, i think you don't need it

Suggested change
mt: (At *\: et) + alphat; // m_t = a_t + A_t * e_t (EQ 4)
mt: (At * et) + alphat; // m_t = a_t + A_t * e_t (EQ 4)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not remeber right know why I did it exactly. Maybe it is useless i will try to do it without *: and see if it is still the same result

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, as you said it works the same

Ct: (eye[2] - (At mmu Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you review this? I think correct formula is this

Suggested change
Ct: (eye[2] - (At mmu Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8)
Ct: (eye[2] - (flip[enlist At] mmu enlist Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey I will try it as well

(mt;-1*Ct)} // Return new updates
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you negating C? I think that doesnt make sense

Copy link
Contributor

@Kokechacho Kokechacho Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result is correct if I negate C. I think it has to do with the order of the operation. from above.

Ct: ( (At mmu Ft) . eye[2]) mmu Rt; (mt;Ct)} // Return new updates

This should do the trick. I will change it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about this and I think that the best option is to replicate the formula. If my math is correct, what you have without negating it is correct, but hard to understand. So this is quite easier: Ct:Rt-flip[enlist At] mmu enlist first[Qt] * At

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okey this is correct, the spreads works fine now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider returning e_t as well, in order to have your spreads calculated so you save one calculation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I will try that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But returning e_t doesnt save me from any calculations no? It will need to calculate e_t again on the next iteration