-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Conversation
I've uploaded a new temporary file named kf.q, which contains the initial implementation of the Kalman Filter function.
Additionally, I'm still figuring out the best approach for returning the values from the function. One idea I'm considering is to return an array containing all the matrices concatenated together.
I'll continue to work on refining the Kalman Filter function and addressing these issues. Once I have made further progress and resolved the existing challenges, I'll provide another update. |
Why are you flattening your matrix (,/) Ct? We should preserve the full matrix in its original format, so something like Yes, we need to consider how to approach this. I've thought that perhaps we could use |
Okey I will return everything as a dictionary, but then, It does not makes sense to give to the function previous estimations and covariances because it ill never use them inside. The function works fine I think so far, I need to test if it gives same results as in python. |
Fixed covariances Results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review the formulas; this is quite important
kalman_filter.q
Outdated
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) |
There was a problem hiding this comment.
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
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) | |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
kalman_filter.q
Outdated
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) | ||
Ct: (eye[2] - (At mmu Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8) |
There was a problem hiding this comment.
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
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) | |
There was a problem hiding this comment.
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
kalman_filter.q
Outdated
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) | ||
Ct: (eye[2] - (At mmu Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8) | ||
(mt;-1*Ct)} // Return new updates |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
|
||
// Auxiliary functions | ||
// Creates a diagonal matrix | ||
eye:{(2#x)#1f,x#0f} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider this shorter version :)
eye:{(2#x)#1f,x#0f} | |
eye:{{x=/:x}til x} | |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
kalman_filter.q
Outdated
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) | ||
Ct: (eye[2] - (At mmu Ft)) mmu Rt; // C_t = R_t - A_t * Q_t * T(A_t) (EQ 8) | ||
(mt;-1*Ct)} // Return new updates |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
I found this repository, very similar to ours https://github.com/nicholasferguson/kdb.q.kalman.filter.beta.ETFs/blob/master/beta.kalman.q |
Updated some mstakes on EQ 8 and EQ 4
Overview
This pull request introduces the implementation of the Kalman Filter to dynamically adjust hedge ratios between trading pairs, aiming to enhance the accuracy and profitability of our pair trading strategy. The Kalman Filter, a recursive algorithm, is used to estimate the state of a linear dynamic system from a series of noisy measurements. In the context of pair trading, it allows for more adaptive and responsive hedge ratio adjustments based on the evolving price movements of the stock pairs.
Solves: /issues/3
Changes Made
kalman_filter.q
which encapsulates the Kalman Filter logic applied to pair trading.