Code covered by the BSD License  

Highlights from
Algorithmic Trading with MATLAB - 2010

image thumbnail

Algorithmic Trading with MATLAB - 2010

by

 

22 Nov 2010 (Updated )

Files from the November 18, 2010 webinar.

Algorithmic Trading with MATLAB®: Moving Average and RSI

Algorithmic Trading with MATLAB®: Moving Average and RSI

This demo extends work done in AlgoTradingDemo1.m and adds an RSI technical indicator to the mix. Copyright 2010, The MathWorks, Inc. All rights reserved.

Contents

Load in some data

This time we'll import Bund data sampled minutely

load bund1min
testPts = floor(0.8*length(data(:,4)));
step = 30; % 30 minute interval
BundClose = data(1:step:testPts,4);
BundCloseV = data(testPts+1:step:end,4);
annualScaling = sqrt(250*60*11/step);
cost = 0.01;

RSI on data series

rs = rsindex(BundClose,14);
plot(rs), title('RSI')

RSI on detrended series

RSI can often be improved by removing the longer term trend. Here's how to run it a detrended series.

rs2 = rsindex(BundClose-movavg(BundClose,30,30),14);
hold on
plot(rs2,'g')
legend('RSI on raw data','RSI on detrended data')
hold off

RSI trading strategy. Note that the trading signal is generated when the RSI value is above/below the upper/lower threshold. We'll use a 65% threshld (for the upper, the lower is 1-0.65 = 35%).

rsi(BundClose,[15*20,20],65,annualScaling,cost)

RSI performance

Let's find the best perfrorming set of parameters. In the interest of time, I'll set the threshold to 55 (found earlier).

range = {1:300,1:300,55}; % replace 55 by this to do the sweep 50:5:100};
rsfun = @(x) rsiFun(x,BundClose,annualScaling,cost);
tic
[~,param] = parameterSweep(rsfun,range);
toc
rsi(BundClose,param(1:2),param(3),annualScaling,cost)
Elapsed time is 118.974686 seconds.

Test on validation set

rsi(BundCloseV,param(1:2),param(3),annualScaling,cost)

MA + RSI

Put the moving average together with the RSI.

N = 10; M = 394; % from previous calibration
[sr,rr,shr] = rsi(BundClose,param(1:2),param(3),annualScaling,cost);
[sl,rl,shl,lead,lag] = leadlag(BundClose,N,M,annualScaling,cost);

s = (sr+sl)/2;
r  = [0; s(1:end-1).*diff(BundClose)-abs(diff(s))*cost/2];
sh = annualScaling*sharpe(r,0);

figure
ax(1) = subplot(2,1,1);
plot([BundClose,lead,lag]); grid on
legend('Close',['Lead ',num2str(N)],['Lag ',num2str(M)],'Location','Best')
title(['MA+RSI Results, Annual Sharpe Ratio = ',num2str(sh,3)])
ax(2) = subplot(2,1,2);
plot([s,cumsum(r)]); grid on
legend('Position','Cumulative Return','Location','Best')
title(['Final Return = ',num2str(sum(r),3),' (',num2str(sum(r)/BundClose(1)*100,3),'%)'])
linkaxes(ax,'x')

MA+RSI model

The model in a single function call.

marsi(BundClose,N,M,param(1:2),param(3),annualScaling,cost)

Best parameters

And the best parameters are? Note that this result is better than the calibration for MA or RSI alone (see AlgoTradingDemo1.m).

range = {1:10, 350:400, 2:10, 100:10:140, 55};
fun = @(x) marsiFun(x,BundClose,annualScaling,cost);

tic
[maxSharpe,param,sh] = parameterSweep(fun,range);
toc

param

marsi(BundClose,param(1),param(2),param(3:4),param(5),annualScaling,cost)
Elapsed time is 49.226492 seconds.

param =

     2   396     2   110    55

Run on validation set

marsi(BundCloseV,param(1),param(2),param(3:4),param(5),annualScaling,cost)

Note that the results are not that good. We're better on the calibration, but not on the validation. What we really need to do is set up a moving window for training and validation windows. For example, we could set up a window that takes up to 24 hours as the training set, and trades over the next say 6 hours, and then slide the window over by 6 hours and repeat This is one approach, but we really should add the window to the parameter sweep, or backtest over our historical data and identify which training/validation window is optimal. I'll leave this as an exercise, and we'll move on to how you can use genetic algorithm (or genetic programming) to find optimal combinations of trading signals that combine to make up a trading strategy (AlgoTradingDemo3.m).

Contact us