Moving average trading rule - Adding filters

Dear all,
I'm trying to code a moving average (crossover) trading rule with some filter rules. However I get stuck with translating the theory to a Matlab code.
This rule generates a buy signal (value "1") when the fast moving average is above the slow moving average and sell signals (value "-1") vice versa. Where a slow moving average (variable "n" days) is calculated over a greater number of days than the fast moving average (variable "m" days). Same procedure goes for the case where only one (slow) moving average is taken (the case where "m=0") and the price index. The data I use are historical data (a vector of 31225x1, consisting of only index prices on trading days).
The Matlab code for the moving average crossover trading rule (without any filters), where it saves all trading signals of each rule (120 rules in total) in one variable "tr_ma" (which consists of 120 "31225x1 vectors"):
%Moving average crossovers
for n=[2 5 10 15 20 25 30 40 50 75 100 125 150 200 250];
ma_slow=tsmovavg(price,'s',n,1);
for m=[0 2 5 10 15 20 25 30 40 50 75 100 125 150 200 250];
if n<=m; continue, end
if m~=0;
ma_fast=tsmovavg(price,'s',m,1);
end
k=k+1; % Increment the counter
if m~=0;
cross=[NaN; diff(sign(ma_fast-ma_slow))]; % Compute diff of signal
elseif m==0;
cross=[NaN; diff(sign(price-ma_slow))]; % compute diff of signal
end
ix=abs(cross)==2;
cross(ix)=cross(ix)/2; % Scale transitions to +/-1
tr_ma(k)={cross}; % Store as cell
end
end
Now I'm trying to add two filters to this rule ( note: only one filter is active at the time. So you need two codes in the end, one for each filter addition):
--------------------------------------------------
1) The time delay filter (d): requires the buy or sell signal to remain valid for a prespecified number of days, d, before action is taken. d=[2 3 4 5]
The problem: The code has to put a trade only when "d" times buy or sell signals uninterrupted has been generated (so when the fast moving average is "d" times above the slow moving average, generate a buy signal after the "d" times etc.). For example if you have in row 1 till 5 the following signals and "d"=2: [0 0 -1 -1 -1], in row 5 the code has to put a trade (sell) signal and replace the "-1" in row 3 and 4 with a zero. So you get [0 0 0 0 -1].
and
2) Holding period filter (c): consider holding a given long or short position for a prespecified number of trading days (ignoring all other signals during that time), c. c=[5 10 25 50]
The problem: The code has to ignore (so give those rows the value zero) for "c" number of trading days (in my case rows) any buy or sell signals after a trade (buy/sell) has been done. And check again after "c" days if it generates a buy or sell signal etc.
--------------------------------------------------
I can't seem to get those two filters working. Adding a for-loop ("for i=1:31225" etc.) where you let the program calculate cell by cell makes it very slow and don't even works in the end. I thought about the "find" function but again I found a death end.
Does anybody have a suggestion how I can tackle those two filters?
Thanks,
Wildman

7 Comments

For 1) look at
for how to look for runs; since you've got a limit you may want to revise this entry a little or mayhaps it would work inside another routine; I've not considered the details...
For the second, it would be reasonably simple to simply enumerate the start time and clear N elements after that; if you also need to restart the computation afresh after the time is up, it would seem most likely will need to recompute from scratch with the skip factor of ignoring the next periods inside the original loop.
Thanks! Those suggestions may do the trick indeed, I'm going to try those out and hopefully solve the puzzle. I owe you something, thanks again!
I managed to successfully add the first filter to the trading rule, the suggested code worked like a charm! Cheers!
I'm sorry to bother you guys again.... but once again I'm struggling with getting the second filter to work. With "enumerate the start time and clear N elements" you mean something like:
....
for c=[5 10 25 50]; %Holding period
for t=1:31225; %Enumerate for cell by cell calculation (31225 data points)
cross(t,:)=sign(ma_fast(t,:)-ma_slow(t,:)); %Create signals cell by cell
etc......
end
end
And afterwards, when a buy or sell signal is created (a "1" or "-1") clear "c" elements.
However this calculation will take (to) long, this alone already has 31225 loop iterations (and in the end it needs to do this for 480 times because of all the combinations of "n", "m" and "c"). Also I don't get it working in all (special) cases. I guess I'm interpreting your suggestions wrong?
I thought about using the suggested code from filter 1, to find the start and stop locations of the signals but it lead me to a death end. I also tried to create/find a command that finds the previous "1" or "-1" and clear "c" elements afterwards, however that brought me again back with the slow cell by cell calculation.
------------------------------------------------------------------------------------------------------------------
  • An example I created to make it more clear for myself:
Holding period filter (c): consider holding a given long or short position for a prespecified number of trading days (ignoring all other signals during that time), c. c=[5 10 25 50]
Example (for "c=5"): The signal data (row 1 till 15):
Row: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
Signals: [0 1 1 1 -1 1 1 1 -1 -1 -1 1 1 1 1 ]
The program has to do the following:
- In row 1: It encounters a zero (or NaN value, because of the moving average of "n" days), keep that value and do nothing with it.
- In row 2: It encounters a buy signal ("1"), hold this position for "c" days and ignore all signals during that period. So in this case put 4 zeros in row 3-6. After row 6 (so in row 7 and onwards) check when for the first time the the position is eliminated (so in this case when a sell signal, a "-1", shows up).
- In row 9: It encounters a sell signal ("-1"), the position has to be eliminated. And again hold this position for "c" days and ignore all signals during that period. So put 4 zeros in row 10-13.
- In row 14: It encounters a buy signal ("1"), the position has to be eliminated. And again hold this position for "c" days and ignore all signals during that period. So put 4 zeros in row 15-18.
etc.
Concluded the output should be:
Row: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
Signals: [0 1 0 0 0 0 0 0 -1 0 0 0 0 1 0 ]
------------------------------------------------------------------------------------------------------------------
In all my efforts I ended up using a cell by cell calculation (using a for loop, something like "for t=1:31225;"). However this made the code very slow and didn't even did the trick in all cases. I guess this should also be possible by calculating everything at once (using the whole matrix).
Any suggestions for commands/codes how to get the filter part (see example) working?
Since it appears that there's not any additional actual trade until the next change in action, once you find the first trade (buy or sell), then it doesn't matter what the length of the hold period is on the upper end, only the minimum. Hence, find() the next trade beyond the point (day 2 above until day 9 is opposite sign, that's >= the hold period so clear that whole region and move to that day as the next.
Seems like that loop shouldn't be too slow. What wasn't clear prior was whether there was a need to recompute; with the above example the answer to that is "no"; no decision point will change.
In actuality if one were to try to implement such a strategy it seems as though that wouldn't be the way one would actually operate, however.
Wildman
Wildman on 25 Aug 2015
Edited: Wildman on 25 Aug 2015
Indeed, the hold period has a minimum of "c" days with no upper bound and no recomputation is needed because you already have all the signals (the data/moving averages crossovers stays the same).
This filter is added to the standard moving average crossover trading rule to prevent excessive trading, to lower the transaction costs. However of course this has a potential threat of taking a bad position for to long and lose more money than the benefit of the lower transaction costs. This will be a nice thing to investigate later on.
The key is indeed translating the following into Matlab code: "Hence, find() the next trade beyond the point (day 2 above until day 9 is opposite sign, that's >= the hold period so clear that whole region and move to that day as the next.".
I will give it another try (with the "for loop" and "find" functions). I guess I made some mistakes in my previous attempts which made it slow/made it not work. I got some fresh input/new ideas now which I need to try out. Thanks again!
i1=find(S,1); % first move, buy or sell (non-zero)
i2=find(S(i1+1:end)~=S(i1),1)+i1; % first change in action afterwards
If i2-i1>=C, that's one looking for, if <C then find the next starting at i2.
This is all the testing needed if, as the above shows, you've cleared all "hold" signals, otherwise you need a second test to ensure it's not 0. Oh, just dawned on me, don't use "~=S(i1)" as the test, use "==-S(i1)"; that guarantees it's the opposite sign or the other trade action.
That is actually almost the same thing what I have coded, after you gave me some fresh ideas!
Before the while loop I generated a variable "cross" with zeros for length(price), so I don't need to clear any rows/give any rows the value zero (because they are already there). After that I generated a start buy/sell signal at "t=n" and run the while loop (which takes the "filtered" signals out of the standard "index_cross" variable and put them in the "cross" variable).
The code for the filter part (the while loop):
.....
t=n;
while t<=length(price);
if cross(t,:)==1 || cross(t,:)==-1; %Check if a buy/sell signal is generated
prev_signal=cross(t,:); %Store the buy/sell signal
t=t+c-1; %Holding period of c days (including current day)
else index_1=find(index_cross(t+1:end,:)==-prev_signal,1,'first'); %Find first opposite sign
cross(t+index_1,:)=index_cross(t+index_1,:); %Store in the matrix
t=t+index_1; %Move on
end
end
.....
It seems this code does the trick!
--------------------------------------------
"Oh, just dawned on me, don't use "~=S(i1)" as the test, use "==-S(i1)"; that guarantees it's the opposite sign or the other trade action."
--------------------------------------------
Good point! I changed that part in my code, indeed it guarantees it only takes the opposite sign.
Thanks for everything, have a great day!

Sign in to comment.

Answers (0)

Asked:

on 19 Aug 2015

Commented:

on 26 Aug 2015

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!