This commit is contained in:
oleg
2025-06-05 08:48:33 +02:00
commit 283d1195e4
160 changed files with 1857138 additions and 0 deletions
BIN
View File
Binary file not shown.
+51
View File
@@ -0,0 +1,51 @@
clear;
lookback=20;
load('inputData_AUDCAD_20120426', 'hhmm', 'tday', 'cl');
idx=find(hhmm==1659);
dailyCl=cl(idx);
tday=tday(idx);
% Annualized interest rates in percent, updated monthly
aud=load('AUD_interestRate', 'yyyy', 'mm', 'rates');
cad=load('CAD_interestRate', 'yyyy', 'mm', 'rates');
aud_dailyRates=zeros(size(tday));
for i=1:length(aud.mm)
idx=find(aud.mm(i)==month(num2str(tday), 'yyyymmdd') & aud.yyyy(i)==year(num2str(tday), 'yyyymmdd'));
if (~isempty(idx))
aud_dailyRates(idx)=aud.rates(i);
end
end
aud_dailyRates=aud_dailyRates/365/100;
% Triple rollover interest on Wednesdays for AUD
isWednesday=weekday(datenum(num2str(tday), 'yyyymmdd'))==4;
aud_dailyRates(isWednesday)=3*aud_dailyRates(isWednesday);
cad_dailyRates=zeros(size(tday));
for i=1:length(cad.mm)
idx=find(cad.mm(i)==month(num2str(tday), 'yyyymmdd') & cad.yyyy(i)==year(num2str(tday), 'yyyymmdd'));
if (~isempty(idx))
cad_dailyRates(idx)=cad.rates(i);
end
end
cad_dailyRates=cad_dailyRates/365/100;
% Triple rollover interest on Thursdays for CAD
isThursday=weekday(datenum(num2str(tday), 'yyyymmdd'))==5;
cad_dailyRates(isThursday)=3*cad_dailyRates(isThursday);
ma=movingAvg(dailyCl, lookback);
mstd=movingStd(dailyCl, lookback);
z=(dailyCl-ma)./mstd;
% Unlevered return of a linear mean-reverting strategy.
ret=lag(-sign(z), 1).*(log(dailyCl)+lag(-log(dailyCl)+log(1+aud_dailyRates)-log(1+cad_dailyRates), 1));
% ret=lag(-sign(z), 1).*(log(dailyCl)+lag(-log(dailyCl), 1));
ret(isnan(ret))=0;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.061564 Sharpe=0.541802
+69
View File
@@ -0,0 +1,69 @@
clear;
usdcad=load('../Data/inputData_USDCAD_20120426', 'tday', 'hhmm', 'cl');
audusd=load('../Data/inputData_AUDUSD_20120426', 'tday', 'hhmm', 'cl');
firstDate=20090101;
idx=find(usdcad.tday>firstDate & usdcad.hhmm==1659);
usdcad.tday=usdcad.tday(idx);
usdcad.hhmm=usdcad.hhmm(idx);
usdcad.cl=usdcad.cl(idx);
idx=find(audusd.tday>firstDate & audusd.hhmm==1659);
audusd.tday=audusd.tday(idx);
audusd.hhmm=audusd.hhmm(idx);
audusd.cl=audusd.cl(idx);
tday=audusd.tday;
% Need to invert currency pair so that each unit has same capital in local
% currency
cad=1./usdcad.cl;
aud=audusd.cl;
y=[ aud cad ];
trainlen=250;
lookback=20;
hedgeRatio=NaN(size(y));
numUnits=NaN(size(y, 1), 1);
for t=trainlen+1:size(y, 1)
res=johansen(y(t-trainlen:t-1, :), 0, 1);
hedgeRatio(t, :)=res.evec(:, 1)';
% yport is the market value of a unit portfolio of AUDUSD and CADUSD expressed in US$.
yport=sum(y(t-lookback+1:t, :).*repmat(hedgeRatio(t, :), [lookback 1]), 2);
ma=mean(yport);
mstd=std(yport);
zScore=(yport(end)-ma)/mstd;
% numUnits are number of units of unit portfolio of AUDUSD and CADUSD
numUnits(t)=-(yport(end)-ma)/mstd;
end
% positions are market values of AUDUSD and CADUSD in portfolio expressed
% in US$.
positions=repmat(numUnits, [1 size(y, 2)]).*hedgeRatio.*y;
% daily P&L of portfolio in US$.
pnl=sum(lag(positions, 1).*(y-lag(y, 1))./lag(y, 1), 2);
ret=pnl./sum(abs(lag(positions, 1)), 2);
ret(isnan(ret))=0;
plot(cumprod(1+ret(trainlen+1:end))-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret(trainlen+1:end)).^(252/length(ret(trainlen+1:end)))-1, sqrt(252)*mean(ret(trainlen+1:end))/std(ret(trainlen+1:end)));
% APR=0.112410 Sharpe=1.610890
% Kelly leverage
f=mean(ret(trainlen+1:end))/std(ret(trainlen+1:end))^2;
fprintf(1, 'f=%f\n', f);
% f=23.845328
ret=ret(trainlen+1:end);
save('../Data/AUDCAD_unequal_ret', 'ret');
Binary file not shown.
Binary file not shown.
Binary file not shown.
+78
View File
@@ -0,0 +1,78 @@
clear;
lookback1=30;
lookback2=40;
load('inputDataOHLCDaily_20120504', 'syms', 'tday', 'cl');
cl=cl(:, strcmp('CL', syms));
% longs= cl < lag(cl, lookback1) & cl > lag(movingAvg(cl, lookback2), 1);
% shorts=cl > lag(cl, lookback1) & cl < lag(movingAvg(cl, lookback2), 1);
% longs= cl > lag(cl, lookback2);
% shorts= cl < lag(cl, lookback2);
longs= cl < backshift(lookback1, cl) & cl > backshift(lookback2, cl);
shorts=cl > backshift(lookback1, cl) & cl < backshift(lookback2, cl);
% longs= cl < lag(cl, lookback1) ;
% shorts=cl > lag(cl, lookback1) ;
positions=zeros(size(cl));
positions(longs)=1;
positions(shorts)=-1;
% ret=lag(positions, 1).*(cl-lag(cl, 1))./lag(cl, 1);
ret=backshift(1, positions).*(cl-backshift(1, cl))./backshift(1, cl);
ret(isnan(ret))=0;
plot(cumprod(1+ret)-1, 'r'); % Cumulative compounded return
dateaxis('X', 12, datenum(num2str(tday(1)), 'yyyymmdd'));
hold on;
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.117600 Sharpe=1.100368
% Momentum only
longs= cl > backshift(lookback2, cl);
shorts=cl < backshift(lookback2, cl);
positions=zeros(size(cl));
positions(longs)=1;
positions(shorts)=-1;
ret=backshift(1, positions).*(cl-backshift(1, cl))./backshift(1, cl);
ret(isnan(ret))=0;
plot(cumprod(1+ret)-1, 'g'); % Cumulative compounded return
% Reversal only
longs= cl < backshift(lookback1, cl);
shorts=cl > backshift(lookback1, cl);
positions=zeros(size(cl));
positions(longs)=1;
positions(shorts)=-1;
ret=backshift(1, positions).*(cl-backshift(1, cl))./backshift(1, cl);
ret(isnan(ret))=0;
plot(cumprod(1+ret)-1, 'k'); % Cumulative compounded return
legend('Combo', 'Momentum', 'Reversal');
longs= cl < backshift(lookback1, cl) | cl > backshift(lookback2, cl);
shorts=cl > backshift(lookback1, cl) | cl < backshift(lookback2, cl);
% longs= cl < lag(cl, lookback1) ;
% shorts=cl > lag(cl, lookback1) ;
positions=zeros(size(cl));
positionsL=zeros(size(cl));
positionsS=zeros(size(cl));
positionsL(longs)=1;
positionsS(shorts)=-1;
positions=positionsL+positionsS;
% ret=lag(positions, 1).*(cl-lag(cl, 1))./lag(cl, 1);
ret=backshift(1, positions).*(cl-backshift(1, cl))./backshift(1, cl);
ret(isnan(ret))=0;
plot(cumprod(1+ret)-1, 'c'); % Cumulative compounded return
legend('ComboAND', 'Momentum', 'Reversal', 'ComboOR');
hold off;
+31
View File
@@ -0,0 +1,31 @@
clear;
% gc=load('//dellquad/Futures_data/inputData_GC_1600_20100802', 'tday', 'hhmm', 'cl');
gc=load('inputData_GC_1600_20100802', 'tday', 'hhmm', 'cl');
gld=load('inputData_ETF');
gld.cl=gld.cl(:, strcmp('GLD', gld.syms));
[tday idx1 idx2]=intersect(gc.tday, gld.tday);
gc.cl=gc.cl(idx1);
gld.cl=gld.cl(idx2);
% Long GLD and short GC
ret=(gld.cl-lag(gld.cl, 1))./lag(gld.cl, 1)-(gc.cl-lag(gc.cl, 1))./lag(gc.cl, 1);
ret(isnan(ret))=0;
cumret=cumprod(1+ret)-1;
plot(cumret);
riskFreeRate=0.02/252;
fprintf(1, 'Avg Ann Ret=%7.4f Sharpe ratio=%4.2f \n',252*smartmean(ret), sqrt(252)*smartmean(ret-riskFreeRate)/smartstd(ret-riskFreeRate));
fprintf(1, 'APR=%10.4f\n', prod(1+ret).^(252/length(ret))-1);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
%
% Avg Ann Ret= 0.0190 Sharpe ratio=-.07
% APR= 0.0191
% Max DD =-0.008247 Max DDD in days=91
+102
View File
@@ -0,0 +1,102 @@
clear;
% Daily data on EWA-EWC
load('inputData_ETF', 'tday', 'syms', 'cl');
idxA=find(strcmp('EWA', syms));
idxC=find(strcmp('EWC', syms));
x=cl(:, idxA);
y=cl(:, idxC);
% Augment x with ones to accomodate possible offset in the regression
% between y vs x.
x=[x ones(size(x))];
delta=0.0001; % delta=1 gives fastest change in beta, delta=0.000....1 allows no change (like traditional linear regression).
yhat=NaN(size(y)); % measurement prediction
e=NaN(size(y)); % measurement prediction error
Q=NaN(size(y)); % measurement prediction error variance
% For clarity, we denote R(t|t) by P(t).
% initialize R, P and beta.
R=zeros(2);
P=zeros(2);
beta=NaN(2, size(x, 1));
Vw=delta/(1-delta)*eye(2);
Ve=0.001;
% Initialize beta(:, 1) to zero
beta(:, 1)=0;
% Given initial beta and R (and P)
for t=1:length(y)
if (t > 1)
beta(:, t)=beta(:, t-1); % state prediction. Equation 3.7
R=P+Vw; % state covariance prediction. Equation 3.8
end
yhat(t)=x(t, :)*beta(:, t); % measurement prediction. Equation 3.9
Q(t)=x(t, :)*R*x(t, :)'+Ve; % measurement variance prediction. Equation 3.10
% Observe y(t)
e(t)=y(t)-yhat(t); % measurement prediction error
K=R*x(t, :)'/Q(t); % Kalman gain
beta(:, t)=beta(:, t)+K*e(t); % State update. Equation 3.11
P=R-K*x(t, :)*R; % State covariance update. Euqation 3.12
end
plot(beta(1, :)');
figure;
plot(beta(2, :)');
figure;
plot(e(3:end), 'r');
hold on;
plot(sqrt(Q(3:end)));
y2=[x(:, 1) y];
longsEntry=e < -sqrt(Q); % a long position means we should buy EWC
longsExit=e > -sqrt(Q);
shortsEntry=e > sqrt(Q);
shortsExit=e < sqrt(Q);
numUnitsLong=NaN(length(y2), 1);
numUnitsShort=NaN(length(y2), 1);
numUnitsLong(1)=0;
numUnitsLong(longsEntry)=1;
numUnitsLong(longsExit)=0;
numUnitsLong=fillMissingData(numUnitsLong); % fillMissingData can be downloaded from epchan.com/book2. It simply carry forward an existing position from previous day if today's positio is an indeterminate NaN.
numUnitsShort(1)=0;
numUnitsShort(shortsEntry)=-1;
numUnitsShort(shortsExit)=0;
numUnitsShort=fillMissingData(numUnitsShort);
numUnits=numUnitsLong+numUnitsShort;
positions=repmat(numUnits, [1 size(y2, 2)]).*[-beta(1, :)' ones(size(beta(1, :)'))].*y2; % [hedgeRatio -ones(size(hedgeRatio))] is the shares allocation, [hedgeRatio -ones(size(hedgeRatio))].*y2 is the dollar capital allocation, while positions is the dollar capital in each ETF.
pnl=sum(lag(positions, 1).*(y2-lag(y2, 1))./lag(y2, 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.262252 Sharpe=2.361162
+38
View File
@@ -0,0 +1,38 @@
clear;
% 1 minute data on EWA-EWC
load('inputData_ETF', 'tday', 'syms', 'cl');
idxG=find(strcmp('GLD', syms));
idxU=find(strcmp('USO', syms));
x=cl(:, idxG);
y=cl(:, idxU);
% lookback period for calculating the dynamically changing hedge ratio
lookback=20; % Lookback set arbitrarily short
hedgeRatio=NaN(size(x, 1), 1);
for t=lookback:size(hedgeRatio, 1)
regression_result=ols(log(y(t-lookback+1:t)), [log(x(t-lookback+1:t)) ones(lookback, 1)]);
hedgeRatio(t)=regression_result.beta(1);
end
y2=[x y];
yport=sum([-hedgeRatio ones(size(hedgeRatio))].*log(y2), 2); % The net market value of the portfolio is same as the "spread"
hedgeRatio(1:lookback)=[]; % Removed because hedge ratio is indterminate
yport(1:lookback)=[];
y2(1:lookback, :)=[];
plot(yport);
%
numUnits=-(yport-movingAvg(yport, lookback))./movingStd(yport, lookback); % units invested in portfolio. movingAvg and movingStd are functions from epchan.com/book2
positions=repmat(numUnits, [1 size(y2, 2)]).*[-hedgeRatio ones(size(hedgeRatio))]; % [hedgeRatio -ones(size(hedgeRatio))] is the dollar capital allocation, while positions is the dollar capital in each ETF.
pnl=sum(lag(positions, 1).*(y2-lag(y2, 1))./lag(y2, 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.088863 Sharpe=0.504153
+40
View File
@@ -0,0 +1,40 @@
clear;
% 1 minute data on GLD-USO
load('inputData_ETF', 'tday', 'syms', 'cl');
idxG=find(strcmp('GLD', syms));
idxU=find(strcmp('USO', syms));
x=cl(:, idxG);
y=cl(:, idxU);
% lookback period for calculating the dynamically changing hedge ratio
lookback=20; % Lookback set arbitrarily short
hedgeRatio=NaN(size(x, 1), 1);
for t=lookback:size(hedgeRatio, 1)
regression_result=ols(y(t-lookback+1:t), [x(t-lookback+1:t) ones(lookback, 1)]);
hedgeRatio(t)=regression_result.beta(1);
end
y2=[x y];
yport=sum([-hedgeRatio ones(size(hedgeRatio))].*y2, 2); % The net market value of the portfolio is same as the "spread"
hedgeRatio(1:lookback)=[]; % Removed because hedge ratio is indterminate
yport(1:lookback)=[];
y2(1:lookback, :)=[];
plot(yport);
% Apply a simple linear mean reversion strategy to GLD-USO
numUnits=-(yport-movingAvg(yport, lookback))./movingStd(yport, lookback); % movingAvg and movingStd are functions from epchan.com/book2
positions=repmat(numUnits, [1 size(y2, 2)]).*[-hedgeRatio ones(size(hedgeRatio))].*y2; % [hedgeRatio -ones(size(hedgeRatio))] is the shares allocation, [hedgeRatio -ones(size(hedgeRatio))].*y2 is the dollar capital allocation, while positions is the dollar capital in each ETF.
pnl=sum(lag(positions, 1).*(y2-lag(y2, 1))./lag(y2, 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.108335 Sharpe=0.589651
Binary file not shown.
+32
View File
@@ -0,0 +1,32 @@
clear;
% 1 minute data on EWA-EWC
load('inputData_ETF', 'tday', 'syms', 'cl');
idxG=find(strcmp('GLD', syms));
idxU=find(strcmp('USO', syms));
x=cl(:, idxG);
y=cl(:, idxU);
lookback=20; % Lookback is set arbitrarily
ratio=y./x;
ratio(1:lookback)=[]; % Removed to have same test set as price spread and log price spread strategies
x(1:lookback)=[];
y(1:lookback)=[];
plot(ratio);
%
% Apply a simple linear mean reversion strategy to GLD-USO
numUnits=-(ratio-movingAvg(ratio, lookback))./movingStd(ratio, lookback); % units invested in the portfolio. movingAvg and movingStd are functions from epchan.com/book2
positions=repmat(numUnits, [1 2]).*[-ones(size(x, 1), 1) ones(size(x, 1), 1)]; % positions in dollar invested
pnl=sum(lag(positions, 1).*([x y]-lag([x y], 1))./lag([x y], 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2);
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=-0.141522 Sharpe=-0.746663
+86
View File
@@ -0,0 +1,86 @@
clear;
load('../Data/inputDataOHLCDaily_20120511', 'syms', 'tday', 'cl');
% load('//dellquad/Futures_data/inputDataOHLCDaily_20120815', 'syms', 'tday', 'cl');
idx=strmatch('TU', syms, 'exact');
tday=tday(:, idx);
cl=cl(:, idx);
% Correlation tests
for lookback=[1 5 10 25 60 120 250]
for holddays=[1 5 10 25 60 120 250]
ret_lag=(cl-backshift(lookback, cl))./backshift(lookback, cl);
ret_fut=(fwdshift(holddays, cl)-cl)./cl;
badDates=any([isnan(ret_lag) isnan(ret_fut)], 2);
ret_lag(badDates)=[];
ret_fut(badDates)=[];
if (lookback >= holddays)
indepSet=[1:holddays:length(ret_lag)];
else
indepSet=[1:lookback:length(ret_lag)];
end
ret_lag=ret_lag(indepSet);
ret_fut=ret_fut(indepSet);
[cc, pval]=corrcoef(ret_lag, ret_fut);
% fprintf(1, 'lookback=%3i holddays=%3i cc=%7.4f pval=%6.4f\n', lookback, holddays, cc(1, 2), pval(1, 2));
fprintf(1, '%3i\t%3i\t%7.4f\t%6.4f\n', lookback, holddays, cc(1, 2), pval(1, 2));
end
end
% Hurst exponent and Variance ratio test
H=genhurst(log(cl), 2);
fprintf(1, 'H2=%f\n', H);
% Variance ratio test from Matlab Econometrics Toolbox
[h,pValue]=vratiotest(log(cl));
fprintf(1, 'h=%i\n', h); % h=1 means rejection of random walk hypothesis, 0 means it is a random walk.
fprintf(1, 'pValue=%f\n', pValue); % pValue is essentially the probability that the null hypothesis (random walk) is true.
lookback=250;
holddays=25;
longs=cl > backshift(lookback, cl) ;
shorts=cl < backshift(lookback, cl) ;
pos=zeros(length(cl), 1);
for h=0:holddays-1
long_lag=backshift(h, longs);
long_lag(isnan(long_lag))=false;
long_lag=logical(long_lag);
short_lag=backshift(h, shorts);
short_lag(isnan(short_lag))=false;
short_lag=logical(short_lag);
pos(long_lag)=pos(long_lag)+1;
pos(short_lag)=pos(short_lag)-1;
end
ret=(backshift(1, pos).*(cl-backshift(1, cl))./backshift(1, cl))/holddays;
ret(isnan(ret))=0;
idx=find(tday==20090102);
% idx=1;
cumret=cumprod(1+ret(idx:end))-1;
plot(cumret);
fprintf(1, 'Avg Ann Ret=%7.4f Ann Volatility=%7.4f Sharpe ratio=%4.2f \n',252*smartmean(ret(idx:end)), sqrt(252)*smartstd(ret(idx:end)), sqrt(252)*smartmean(ret(idx:end))/smartstd(ret(idx:end)));
fprintf(1, 'APR=%10.4f\n', prod(1+ret(idx:end)).^(252/length(ret(idx:end)))-1);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
fprintf(1, 'Kelly f=%f\n', mean(ret(idx:end))/std(ret(idx:end))^2);
% Avg Ann Ret= 0.0167 Sharpe ratio=1.04
% APR= 0.0167
% Max DD =-0.024847 Max DDD in days=343
% Kelly f=64.919535
+113
View File
@@ -0,0 +1,113 @@
clear;
% load('../Data/inputDataOHLCDaily_20120511', 'syms', 'tday', 'cl');
load('inputDataOHLCDaily_20120511', 'syms', 'tday', 'cl');
idx=strmatch('TU', syms, 'exact');
tday=tday(:, idx);
cl=cl(:, idx);
lookback=250;
holddays=25;
longs=cl > backshift(lookback, cl) ;
shorts=cl < backshift(lookback, cl) ;
pos=zeros(length(cl), 1);
for h=0:holddays-1
long_lag=backshift(h, longs);
long_lag(isnan(long_lag))=false;
long_lag=logical(long_lag);
short_lag=backshift(h, shorts);
short_lag(isnan(short_lag))=false;
short_lag=logical(short_lag);
pos(long_lag)=pos(long_lag)+1;
pos(short_lag)=pos(short_lag)-1;
end
marketRet=(cl-backshift(1, cl))./backshift(1, cl);
marketRet(~isfinite(marketRet))=0;
ret=backshift(1, pos).*marketRet/holddays;
ret(isnan(ret))=0;
% Gaussian hypothesis test
fprintf(1, 'Gaussian Test statistic=%4.2f\n', mean(ret)/std(ret)*sqrt(length(ret)));
% Gaussian Test statistic=2.93
% Randomized market returns hypothesis test
moments={mean(marketRet), std(marketRet), skewness(marketRet), kurtosis(marketRet)};
numSampleAvgretBetterOrEqualObserved=0;
for sample=1:10000
marketRet_sim=pearsrnd(moments{:}, length(marketRet), 1);
cl_sim=cumprod(1+marketRet_sim)-1;
longs_sim=cl_sim > backshift(lookback, cl_sim) ;
shorts_sim=cl_sim < backshift(lookback, cl_sim) ;
pos_sim=zeros(length(cl_sim), 1);
for h=0:holddays-1
long_sim_lag=backshift(h, longs_sim);
long_sim_lag(isnan(long_sim_lag))=false;
long_sim_lag=logical(long_sim_lag);
short_sim_lag=backshift(h, shorts_sim);
short_sim_lag(isnan(short_sim_lag))=false;
short_sim_lag=logical(short_sim_lag);
pos_sim(long_sim_lag)=pos_sim(long_sim_lag)+1;
pos_sim(short_sim_lag)=pos_sim(short_sim_lag)-1;
end
ret_sim=backshift(1, pos_sim).*marketRet_sim/holddays;
ret_sim(~isfinite(ret_sim))=0;
if (mean(ret_sim)>= mean(ret))
numSampleAvgretBetterOrEqualObserved=numSampleAvgretBetterOrEqualObserved+1;
end
end
fprintf(1, 'Randomized prices: p-value=%f\n', numSampleAvgretBetterOrEqualObserved/10000);
% p-value=0.027500
% Randomized entry trades hypothesis test
numSampleAvgretBetterOrEqualObserved=0;
for sample=1:100000
P=randperm(length(longs));
longs_sim=longs(P);
shorts_sim=shorts(P);
pos_sim=zeros(length(cl), 1);
for h=0:holddays-1
long_sim_lag=backshift(h, longs_sim);
long_sim_lag(isnan(long_sim_lag))=false;
long_sim_lag=logical(long_sim_lag);
short_sim_lag=backshift(h, shorts_sim);
short_sim_lag(isnan(short_sim_lag))=false;
short_sim_lag=logical(short_sim_lag);
pos(long_sim_lag)=pos(long_sim_lag)+1;
pos(short_sim_lag)=pos(short_sim_lag)-1;
end
ret_sim=backshift(1, pos_sim).*marketRet/holddays;
ret_sim(isnan(ret_sim))=0;
if (mean(ret_sim)>= mean(ret))
numSampleAvgretBetterOrEqualObserved=numSampleAvgretBetterOrEqualObserved+1;
end
end
fprintf(1, 'Randomized trades: p-value=%f\n', numSampleAvgretBetterOrEqualObserved/100000);
Binary file not shown.
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
clear;
load('inputDataOHLCDaily_20120517', 'syms', 'tday', 'cl');
idxV=find(strcmp('VX', syms));
idxE=find(strcmp('ES', syms));
VX=cl(:, idxV);
tdayV=tday(:, idxV);
ES=cl(:, idxE);
tdayE=tday(:, idxE);
[tday idxV idxE]=intersect(tdayV, tdayE);
VX=VX(idxV);
ES=ES(idxE);
scatter(VX, ES);
post200808=find(tday>=20080801);
hedgeRatio=regress(50*ES(post200808), [1000*VX(post200808) ones(length(post200808), 1)]);
+88
View File
@@ -0,0 +1,88 @@
clear;
entryThreshold=0.1;
onewaytcost=1/10000;
load('inputDataDaily_VX_20120507', 'tday', 'contracts', 'cl');
% VIX Index
[num txt]=xlsread('../Data/VIX.csv');
VIX=num(:, end);
tday_VIX=str2double(cellstr(datestr(datenum(txt(2:end, 1), 'yyyy-mm-dd'), 'yyyymmdd')));
[tday idx1 idx2]=intersect(tday_VIX, tday);
VIX=VIX(idx1);
VX=cl(idx2, :);
es=load('inputDataOHLCDaily_20120507', 'syms', 'tday', 'cl');
ES=es.cl(:, strcmp('ES', es.syms));
tday_ES=es.tday(:, strcmp('ES', es.syms));
[tday idx1 idx2]=intersect(tday, tday_ES);
VIX=VIX(idx1);
VX=VX(idx1, :);
ES=ES(idx2);
isExpireDate=false(size(VX));
isExpireDate=isfinite(VX) & ~isfinite(fwdshift(1, VX));
% Define front month as 40 days to 10 days before expiration
numDaysStart=40;
numDaysEnd=10;
positions=[zeros(size(VX)) zeros(size(ES))];
for c=1:length(contracts)-1
expireIdx=find(isExpireDate(:, c));
if (c==1)
startIdx=expireIdx-numDaysStart;
endIdx=expireIdx-numDaysEnd;
else % ensure next front month contract doesn't start until current one ends
startIdx=max(endIdx+1, expireIdx-numDaysStart);
endIdx=expireIdx-numDaysEnd;
end
if (~isempty(expireIdx))
idx=startIdx:endIdx;
% dailyRoll=(VX(idx, c)-VIX(idx))./[expireIdx-startIdx:-1:expireIdx-endIdx]';
dailyRoll=(VX(idx, c)-VIX(idx))./[expireIdx-startIdx+1:-1:expireIdx-endIdx+1]';
% positions(idx(dailyRoll > entryThreshold), c)=-1*0.3906;
positions(idx(dailyRoll > entryThreshold), c)=-1;
positions(idx(dailyRoll > entryThreshold), end)=-1;
% Entry level filter
% positions(idx(dailyRoll > entryThreshold & VX(idx, c) > 21), c)=-1*0.3906;
% positions(idx(dailyRoll > entryThreshold & VX(idx, c) > 21), end)=-1;
% positions(idx(dailyRoll < -entryThreshold), c)=1*0.3906;
positions(idx(dailyRoll < -entryThreshold), c)=1;
positions(idx(dailyRoll < -entryThreshold), end)=1;
% Entry level filter
% positions(idx(dailyRoll < -entryThreshold & VX(idx, c) < 34), c)=1*0.3906;
% positions(idx(dailyRoll < -entryThreshold & VX(idx, c) < 34), end)=1;
end
end
y=[VX*1000 ES*50];
ret=smartsum(lag(positions).*(y-lag(y, 1)), 2)./smartsum(abs(lag(positions.*y)), 2)-...
onewaytcost*smartsum(abs(positions.*y-lag(positions.*y)), 2)./smartsum(abs(lag(positions.*y)), 2);
ret(isnan(ret))=0;
idx=find(tday >= 20080804);
cumret=cumprod(1+ret(idx(501:end)))-1;
plot(cumret); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret(idx(501:end))).^(252/length(ret(idx(501:end))))-1, sqrt(252)*mean(ret(idx(501:end)))/std(ret(idx(501:end))));
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'maxDD=%f maxDDD=%i\n', maxDD, maxDDD);
% APR=0.069065 Sharpe=1.002020
% maxDD=-0.075683 maxDDD=259
%
%
% If use hedge ratio [1, 1]
% APR=0.293906 Sharpe=3.263952
% maxDD=-0.035798 maxDDD=59
+71
View File
@@ -0,0 +1,71 @@
clear;
load('inputData_ETF', 'syms', 'tday', 'cl');
uso=cl(:, strcmp('USO', syms));
xle=cl(:, strcmp('XLE', syms));
tday_ETF=tday;
load('inputDataDaily_CL_20120502', 'tday', 'contracts', 'cl');
ratioMatrix=(fwdshift(1, cl')./cl')'; % back/front
ratio=NaN(size(ratioMatrix, 1), 1);
isExpireDate=false(size(ratio));
isExpireDate=isfinite(cl) & ~isfinite(fwdshift(1, cl));
% Define front month as 40 days to 10 days before expiration
numDaysStart=40;
numDaysEnd=10;
for c=1:length(contracts)-1
expireIdx=find(isExpireDate(:, c));
if (c==1)
startIdx=expireIdx-numDaysStart;
endIdx=expireIdx-numDaysEnd;
else % ensure next front month contract doesn't start until current one ends
startIdx=max(endIdx+1, expireIdx-numDaysStart);
endIdx=expireIdx-numDaysEnd;
end
if (~isempty(expireIdx))
ratio(startIdx:endIdx)=ratioMatrix(startIdx:endIdx, c);
end
end
[tday idxA idxB]=intersect(tday_ETF, tday);
uso=uso(idxA);
xle=xle(idxA);
ratio=ratio(idxB);
positions=zeros(length(tday), 2);
% Contango, negative roll return, buy spot, short future
contango=find(ratio > 1);
positions(contango, :)=repmat([-1 1], [length(contango) 1]);
% Backwardation, positive roll return, short spot, long future
backwardation=find(ratio < 1);
positions(backwardation, :)=repmat([1 -1], [length(backwardation) 1]);
ret=smartsum(lag(positions, 1).*([uso xle]-lag([uso xle], 1))./lag([uso xle], 1), 2)/2;
ret(isnan(ret))=0;
cumret=cumprod(1+ret)-1;
plot(cumret);
fprintf(1, 'Avg Ann Ret=%7.4f Sharpe ratio=%4.2f \n',252*smartmean(ret), sqrt(252)*smartmean(ret)/smartstd(ret));
fprintf(1, 'APR=%10.4f\n', prod(1+ret).^(252/length(ret))-1);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
% Avg Ann Ret= 0.1592 Sharpe ratio=1.05
% APR= 0.1591
% Max DD =-0.192321 Max DDD in days=487
% isContango=zeros(size(ratio));
% isContango(ratio > 1)=1;
%
% hold on; plot(isContango, 'r'); hold on;
+74
View File
@@ -0,0 +1,74 @@
%port_trade.m
clear;
load('../Data/inputDataOHLCDaily_20120424');
idxStart=find(tday==20070103);
idxEnd=find(tday==20111230);
tday=tday(idxStart:idxEnd);
cl=cl(idxStart:idxEnd, :);
op=op(idxStart:idxEnd, :);
% cl is a TxN array of closing prices, where T is the number of trading
% days, and N is the number of stocks in the S&P 500
ret=(cl-lag(cl, 1))./lag(cl, 1); % daily returns
marketRet=smartmean(ret, 2); % equal weighted market index return
weights=-(ret-repmat(marketRet, [1 size(ret, 2)]));
weights=weights./repmat(smartsum(abs(weights), 2), [1 size(weights, 2)]);
dailyret=smartsum(backshift(1, weights).*ret, 2); % Capital is always one
dailyret(isnan(dailyret))=0;
plot(cumprod(1+dailyret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+dailyret).^(252/length(dailyret))-1, sqrt(252)*mean(dailyret)/std(dailyret));
% APR=13.7%, Sharpe=1.3
% daily pnl with transaction costs deducted
% onewaytcost=0.0005; % assume 5 basis points
%
% dailyretMinustcost=dailyret - ...
% smartsum(abs(weights./cl-backshift(1, weights)./backshift(1, cl)).*backshift(1, cl), 2).*onewaytcost./smartsum(abs(weights), 2); % transaction costs are only incurred when the weights change
%
% annavgretMinustcost=252*smartmean(dailyretMinustcost, 1)*100
%
% sharpeMinustcost=sqrt(252)*smartmean(dailyretMinustcost, 1)/smartstd(dailyretMinustcost, 1)
%
% % switch to use open prices
%
ret=(op-backshift(1, cl))./backshift(1, cl); % daily returns
marketRet=smartmean(ret, 2); % equal weighted market index return
weights=-(ret-repmat(marketRet, [1 size(ret, 2)])); % weight of a stock is proportional to the negative distance to the market index.
weights=weights./repmat(smartsum(abs(weights), 2), [1 size(weights, 2)]);
dailyret=smartsum(weights.*(cl-op)./op, 2)./smartsum(abs(weights), 2);
dailyret(isnan(dailyret))=0;
plot(cumprod(1+dailyret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+dailyret).^(252/length(dailyret))-1, sqrt(252)*mean(dailyret)/std(dailyret));
% APR=0.731553 Sharpe=4.713284
% annavgret=252*smartmean(dailyret, 1)*100
%
% sharpe=sqrt(252)*smartmean(dailyret, 1)/smartstd(dailyret,1) % Sharpe ratio should be about 0.25
%
% % daily pnl with transaction costs deducted
% onewaytcost=0.0005; % assume 5 basis points
%
% dailyretMinustcost=dailyret - ...
% smartsum(abs(weights./cl-backshift(1, weights)./backshift(1, cl)).*backshift(1, cl), 2).*onewaytcost./smartsum(abs(weights), 2); % transaction costs are only incurred when the weights change
%
% annavgretMinustcost=252*smartmean(dailyretMinustcost, 1)*100
%
% sharpeMinustcost=sqrt(252)*smartmean(dailyretMinustcost, 1)/smartstd(dailyretMinustcost, 1)
%
% % kelly optimal leverage
%
% f=smartmean(dailyretMinustcost, 1)/smartstd(dailyretMinustcost, 1)^2
+4
View File
@@ -0,0 +1,4 @@
function y=backshift(day,x)
% y=backshift(day,x)
assert(day>=0);
y=[NaN(day,size(x,2), size(x, 3));x(1:end-day,:, :)];
+43
View File
@@ -0,0 +1,43 @@
clear;
topN=10; % Max number of positions
entryZscore=1;
lookback=20; % for MA
load('../Data/inputDataOHLCDaily_20120424', 'stocks', 'tday', 'op', 'hi', 'lo', 'cl');
stdretC2C90d=backshift(1, smartMovingStd(calculateReturns(cl, 1), 90));
buyPrice=backshift(1, lo).*(1-entryZscore*stdretC2C90d);
retGap=(op-backshift(1, lo))./backshift(1, lo);
pnl=zeros(length(tday), 1);
positionTable=zeros(size(cl));
ma=backshift(1, smartMovingAvg(cl, lookback));
for t=2:size(cl, 1)
hasData=find(isfinite(retGap(t, :)) & op(t, :) < buyPrice(t, :) & op(t, :) > ma(t, :));
[foo idxSort]=sort(retGap(t, hasData), 'ascend');
positionTable(t, hasData(idxSort(1:min(topN, length(idxSort)))))=1;
end
retO2C=(cl-op)./op;
pnl=smartsum(positionTable.*(retO2C), 2);
ret=pnl/topN;
ret(isnan(ret))=0;
fprintf(1, '%i - %i\n', tday(1), tday(end));
fprintf(1, 'APR=%10.4f\n', prod(1+ret).^(252/length(ret))-1);
fprintf(1, 'Sharpe=%4.2f\n', mean(ret)*sqrt(252)/std(ret));
% APR=8.7%, Sharpe=1.5
cumret=cumprod(1+ret)-1; % compounded ROE
plot(cumret);
+65
View File
@@ -0,0 +1,65 @@
clear;
% 1 minute data on GLD-USO
load('inputData_ETF', 'tday', 'syms', 'cl');
idxG=find(strcmp('GLD', syms));
idxU=find(strcmp('USO', syms));
x=cl(:, idxG);
y=cl(:, idxU);
lookback=20; % Lookback set arbitrarily short
hedgeRatio=NaN(size(x, 1), 1);
for t=lookback:size(hedgeRatio, 1)
regression_result=ols(y(t-lookback+1:t), [x(t-lookback+1:t) ones(lookback, 1)]);
hedgeRatio(t)=regression_result.beta(1);
end
y2=[x y];
yport=sum([-hedgeRatio ones(size(hedgeRatio))].*y2, 2); % The net market value of the portfolio is same as the "spread"
hedgeRatio(1:lookback)=[]; % Removed because hedge ratio is indterminate
yport(1:lookback)=[];
y2(1:lookback, :)=[];
% Bollinger band strategy
entryZscore=1;
exitZscore=0;
MA=movingAvg(yport, lookback);
MSTD=movingStd(yport, lookback);
zScore=(yport-MA)./MSTD;
longsEntry=zScore < -entryZscore; % a long position means we should buy EWC
longsExit=zScore > -exitZscore;
shortsEntry=zScore > entryZscore;
shortsExit=zScore < exitZscore;
numUnitsLong=NaN(length(yport), 1);
numUnitsShort=NaN(length(yport), 1);
numUnitsLong(1)=0;
numUnitsLong(longsEntry)=1;
numUnitsLong(longsExit)=0;
numUnitsLong=fillMissingData(numUnitsLong); % fillMissingData can be downloaded from epchan.com/book2. It simply carry forward an existing position from previous day if today's positio is an indeterminate NaN.
numUnitsShort(1)=0;
numUnitsShort(shortsEntry)=-1;
numUnitsShort(shortsExit)=0;
numUnitsShort=fillMissingData(numUnitsShort);
numUnits=numUnitsLong+numUnitsShort;
positions=repmat(numUnits, [1 size(y2, 2)]).*[-hedgeRatio ones(size(hedgeRatio))].*y2; % [hedgeRatio -ones(size(hedgeRatio))] is the shares allocation, [hedgeRatio -ones(size(hedgeRatio))].*y2 is the dollar capital allocation, while positions is the dollar capital in each ETF.
pnl=sum(lag(positions, 1).*(y2-lag(y2, 1))./lag(y2, 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.178249 Sharpe=0.964673
% Save this for future use
% save('bollinger', 'hedgeRatio', 'MA', 'MSTD');
+33
View File
@@ -0,0 +1,33 @@
function [maxDD maxDDD]=calculateMaxDD(cumret)
% [maxDD maxDDD]=calculateMaxDD(cumret)
% calculation of maximum drawdown and maximum drawdown duration based on
% cumulative COMPOUNDED returns. cumret must be a compounded cumulative return.
% Same as calculateMaxDD_cpd for backward compatibility.
% written by:
% Ernest Chan
%
% Author of Quantitative Trading:
% How to Start Your Own Algorithmic Trading Business
%
% ernest@epchan.com
% www.epchan.com
highwatermark=zeros(size(cumret)); % initialize high watermarks to zero.
drawdown=zeros(size(cumret)); % initialize drawdowns to zero.
drawdownduration=zeros(size(cumret)); % initialize drawdown duration to zero.
for t=2:length(cumret)
highwatermark(t)=max(highwatermark(t-1), cumret(t));
drawdown(t)=(1+cumret(t))./(1+highwatermark(t))-1; % drawdown on each day
if (drawdown(t)==0)
drawdownduration(t)=0;
else
drawdownduration(t)=drawdownduration(t-1)+1;
end
end
maxDD=min(drawdown); % maximum drawdown
maxDDD=max(drawdownduration); % maximum drawdown duration
+9
View File
@@ -0,0 +1,9 @@
function rlag=calculateReturns(prices, lag)
% rlag=calculateReturns(prices, lag) returns the lagged returns based on
% the price series
% rlag=log(prices)-backshift(lag, log(prices));
prevPrices=backshift(lag, prices);
rlag=(prices-prevPrices)./prevPrices;
+125
View File
@@ -0,0 +1,125 @@
clear;
% load('inputDataDaily_VX_20120507', 'tday', 'contracts', 'cl');
load('//dellquad/Futures_data/inputDataDaily_CL_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_TU_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_BR_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_HG_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_C2_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_HO2_20120813', 'tday', 'contracts', 'cl');
% Find spot prices
spotIdx=find(strcmp(contracts, '0000$'));
spot=cl(:, spotIdx);
cl(:, spotIdx)=[];
contracts(spotIdx)=[];
% T=[1:length(spot)]';
% isBadData=~isfinite(spot);
% spot(isBadData)=[];
% T(isBadData)=[];
% res=ols(log(spot), [T ones(size(T, 1), 1)]);
%
% fprintf(1, 'Average annualized spot return=%f\n', 252*smartmean(res.beta(1)));
% Fitting gamma to forward curve
gamma=NaN(size(tday));
for t=1:length(tday)
FT=cl(t, :)';
idx=find(isfinite(FT));
idxDiff=fwdshift(1, idx)-idx; % ensure consecutive months futures
if (length(idx) >= 5 && all(idxDiff(1:4)==1))
FT=FT(idx(1:5)); % only uses the nearest 5 contracts
T=[1:length(FT)]';
% scatter(T, log(FT));
res=ols(log(FT), [T ones(size(T, 1), 1)]);
gamma(t)=-12*res.beta(1);
end
end
gamma=fillMissingData(gamma);
% plot(gamma);
%print -r300 -djpeg fig5_4
% hold on;
% fprintf(1, 'Average annualized roll return=%f\n', smartmean(gamma));
isGoodData=find(isfinite(gamma));
results=adf(gamma(isGoodData), 0, 1);
prt(results);
gammalag=lag(gamma(isGoodData), 1);
deltaGamma=gamma(isGoodData)-gammalag;
deltaGamma(1)=[];
gammalag(1)=[];
regress_results=ols(deltaGamma, [gammalag ones(size(gammalag))]);
halflife=-log(2)/regress_results.beta(1);
fprintf(1, 'halflife=%f days\n', halflife);
% halflife=36.394034 days
lookback=round(halflife);
ma=movingAvg(gamma, lookback);
mstd=movingStd(gamma, lookback);
zScore=(gamma-ma)./mstd;
% linear mean reversion strategy
isExpireDate=false(size(cl));
positions=zeros(size(cl));
isExpireDate=isfinite(cl) & ~isfinite(fwdshift(1, cl));
holddays=3*21;
numDaysStart=holddays+10;
numDaysEnd=10;
spreadMonth=12; % No. months between far and near contracts.
for c=1:length(contracts)-spreadMonth
expireIdx=find(isExpireDate(:, c));
expireIdx=expireIdx(end); % There may be some missing data earlier on
if (c==1)
startIdx=max(1, expireIdx-numDaysStart);
endIdx=expireIdx-numDaysEnd;
else % ensure next front month contract doesn't start until current one ends
myStartIdx=endIdx+1;
myEndIdx=expireIdx-numDaysEnd;
if (myEndIdx-myStartIdx >= holddays)
startIdx=myStartIdx;
endIdx=myEndIdx;
else
startIdx=NaN;
end
end
if (~isempty(expireIdx) & endIdx > startIdx)
positions(startIdx:endIdx, c)=-1; % Presume we long spread (long back contract, short front contract)
positions(startIdx:endIdx, c+spreadMonth)=1;
end
end
positions(isnan(zScore), :)=0;
positions(zScore > 0, :)=-positions(zScore > 0, :);
% positions(zScore > 1, :)=-positions(zScore > 1, :);
ret=smartsum(lag(positions).*(cl-lag(cl, 1))./lag(cl, 1), 2)/2;
ret(isnan(ret))=0;
idx=find(tday==20080102);
% idx=1;
cumret=cumprod(1+ret(idx:end))-1;
plot(cumret); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret(idx:end)).^(252/length(ret(idx:end)))-1, sqrt(252)*mean(ret(idx:end))/std(ret(idx:end)));
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'maxDD=%f maxDDD=%i\n', maxDD, maxDDD);
% APR=0.083406 Sharpe=1.288661
% maxDD=-0.053222 maxDDD=206
+125
View File
@@ -0,0 +1,125 @@
clear;
% 1 minute data on EWA-EWC
load('inputData_ETF', 'tday', 'syms', 'cl');
idxA=find(strcmp('EWA', syms));
idxC=find(strcmp('EWC', syms));
x=cl(:, idxA);
y=cl(:, idxC);
plot(x);
hold on;
plot(y, 'g');
legend('EWA', 'EWC');
figure;
scatter(x, y);
figure;
regression_result=ols(y, [x ones(size(x))]);
hedgeRatio=regression_result.beta(1);
plot(y-hedgeRatio*x);
% Assume a non-zero offset but no drift, with lag=1.
results=cadf(y, x, 0, 1); % cadf is a function in the jplv7 (spatial-econometrics.com) package. We pick y to be the dependent variable again.
% Print out results
prt(results);
% Output:
% Augmented DF test for co-integration variables: variable 1,variable 2
% CADF t-statistic # of lags AR(1) estimate
% -3.64346635 1 -0.020411
%
% 1% Crit Value 5% Crit Value 10% Crit Value
% -3.880 -3.359 -3.038
% Combine the two time series into a matrix y2 for input into Johansen test
y2=[y, x];
results=johansen(y2, 0, 1); % johansen test with non-zero offset but zero drift, and with the lag k=1.
% Print out results
prt(results);
% Output:
% Johansen MLE estimates
% NULL: Trace Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 19.983 13.429 15.494 19.935
% r <= 1 variable 2 3.983 2.705 3.841 6.635
%
% NULL: Eigen Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 16.000 12.297 14.264 18.520
% r <= 1 variable 2 3.983 2.705 3.841 6.635
% Adding IGE to the portfolio
idxI=find(strcmp('IGE', syms));
z=cl(:, idxI);
y3=[y2, z];
results=johansen(y3, 0, 1); % johansen test with non-zero offset but zero drift, and with the lag k=1.
% Print out results
prt(results);
% Output:
% Johansen MLE estimates
% NULL: Trace Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 34.429 27.067 29.796 35.463
% r <= 1 variable 2 17.532 13.429 15.494 19.935
% r <= 2 variable 3 4.471 2.705 3.841 6.635
%
% NULL: Eigen Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 16.897 18.893 21.131 25.865
% r <= 1 variable 2 13.061 12.297 14.264 18.520
% r <= 2 variable 3 4.471 2.705 3.841 6.635
results.eig % Display the eigenvalues
% ans =
%
% 0.0112
% 0.0087
% 0.0030
results.evec % Display the eigenvectors
% ans =
%
% -1.0460 -0.5797 -0.2647
% 0.7600 -0.1120 -0.0790
% 0.2233 0.5316 0.0952
yport=sum(repmat(results.evec(:, 1)', [size(y3, 1) 1]).*y3, 2); % (net) market value of portfolio
% Find value of lambda and thus the halflife of mean reversion by linear regression fit
ylag=lag(yport, 1); % lag is a function in the jplv7 (spatial-econometrics.com) package.
deltaY=yport-ylag;
deltaY(1)=[]; % Regression functions cannot handle the NaN in the first bar of the time series.
ylag(1)=[];
regress_results=ols(deltaY, [ylag ones(size(ylag))]); % ols is a function in the jplv7 (spatial-econometrics.com) package.
halflife=-log(2)/regress_results.beta(1);
fprintf(1, 'halflife=%f days\n', halflife);
% halflife=22.662578 days
%
% Apply a simple linear mean reversion strategy to EWA-EWC-IGE
lookback=round(halflife); % setting lookback to the halflife found above
numUnits =-(yport-movingAvg(yport, lookback))./movingStd(yport, lookback); % capital invested in portfolio in dollars. movingAvg and movingStd are functions from epchan.com/book2
positions=repmat(numUnits, [1 size(y3, 2)]).*repmat(results.evec(:, 1)', [size(y3, 1) 1]).*y3; % results.evec(:, 1)' can be viewed as the capital allocation, while positions is the dollar capital in each ETF.
pnl=sum(lag(positions, 1).*(y3-lag(y3, 1))./lag(y3, 1), 2); % daily P&L of the strategy
ret=pnl./sum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.125739 Sharpe=1.391310
+32
View File
@@ -0,0 +1,32 @@
clear;
load('inputDataOHLCDaily_20120517', 'tday', 'syms', 'cl');
idx=strmatch('TU', syms, 'exact');
tday=tday(:, idx);
cl=cl(:, idx);
% Correlation tests
for lookback=[1 5 10 25 60 120 250]
for holddays=[1 5 10 25 60 120 250]
ret_lag=(cl-backshift(lookback, cl))./backshift(lookback, cl);
ret_fut=(fwdshift(holddays, cl)-cl)./cl;
badDates=any([isnan(ret_lag) isnan(ret_fut)], 2);
ret_lag(badDates)=[];
ret_fut(badDates)=[];
if (lookback >= holddays)
indepSet=[1:holddays:length(ret_lag)];
else
indepSet=[1:lookback:length(ret_lag)];
end
ret_lag=ret_lag(indepSet);
ret_fut=ret_fut(indepSet);
[cc, pval]=corrcoef(ret_lag, ret_fut);
% fprintf(1, 'lookback=%3i holddays=%3i cc=%7.4f pval=%6.4f\n', lookback, holddays, cc(1, 2), pval(1, 2));
fprintf(1, '%3i\t%3i\t%7.4f\t%6.4f\n', lookback, holddays, cc(1, 2), pval(1, 2));
end
end
Binary file not shown.
+55
View File
@@ -0,0 +1,55 @@
clear;
% load('inputDataDaily_VX_20120507', 'tday', 'contracts', 'cl');
load('//dellquad/Futures_data/inputDataDaily_CL_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_TU_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_BR_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_HG_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_C2_20120813', 'tday', 'contracts', 'cl');
% load('inputDataDaily_C2_20120813', 'tday', 'contracts', 'cl');
% load('//dellquad/Futures_data/inputDataDaily_HO2_20120813', 'tday', 'contracts', 'cl');
% Find spot prices
spotIdx=find(strcmp(contracts, '0000$'));
spot=cl(:, spotIdx);
cl(:, spotIdx)=[];
contracts(spotIdx)=[];
T=[1:length(spot)]';
isBadData=~isfinite(spot);
spot(isBadData)=[];
T(isBadData)=[];
res=ols(log(spot), [T ones(size(T, 1), 1)]);
fprintf(1, 'Average annualized spot return=%f\n', 252*smartmean(res.beta(1)));
% Fitting gamma to forward curve
gamma=NaN(size(tday));
for t=1:length(tday)
FT=cl(t, :)';
idx=find(isfinite(FT));
idxDiff=fwdshift(1, idx)-idx; % ensure consecutive months futures
if (length(idx) >= 5 && all(idxDiff(1:4)==1))
FT=FT(idx(1:5)); % only uses the nearest 5 contracts
T=[1:length(FT)]';
% scatter(T, log(FT));
res=ols(log(FT), [T ones(size(T, 1), 1)]);
gamma(t)=-12*res.beta(1);
end
end
isBadData=find(isnan(gamma));
gamma(isBadData)=[];
tday(isBadData)=[];
plot(gamma);
%print -r300 -djpeg fig5_4
% hold on;
fprintf(1, 'Average annualized roll return=%f\n', smartmean(gamma));
% save('C2_gamma', 'tday', 'gamma');
+36
View File
@@ -0,0 +1,36 @@
function my_prices=fillMissingData(prices, varargin)
% my_prices=fillMissingData(prices) fills missing price with previous
% day's price
% my_prices=fillMissingData(prices, tday, cday) fills missing prices with previous day's price including non-trading days
% as specified in cday
if (nargin == 1)
my_prices=prices;
for t=2:size(my_prices, 1)
missData=~isfinite(my_prices(t, :, :));
my_prices(t, missData)=my_prices(t-1, missData);
end
else
% We deal only with 2 dim prices array here.
tday=varargin{1};
cday=varargin{2};
my_prices=NaN*zeros(size(cday, 1), size(prices, 2));
tdayIdx=find(tday==cday(1));
if (~isempty(tdayIdx))
my_prices(1, :)=prices(tdayIdx, :);
end
for t=2:size(my_prices, 1)
tdayIdx=find(tday==cday(t));
if (~isempty(tdayIdx))
my_prices(t, :)=prices(tdayIdx, :);
missData=find(~isfinite(my_prices(t, :)));
my_prices(t, missData)=my_prices(t-1, missData);
else
my_prices(t, :)=my_prices(t-1, :);
end
end
end
+5
View File
@@ -0,0 +1,5 @@
function y=fwdshift(day,x)
assert(day>=0);
y=[x(day+1:end,:, :); NaN*ones(day,size(x,2), size(x, 3))];
+35
View File
@@ -0,0 +1,35 @@
clear;
entryZscore=0.1;
data=load('inputDataOHLCDaily_20120517', 'syms', 'tday', 'op', 'hi', 'lo', 'cl');
idx=find(strcmp('FSTX', data.syms));
op=data.op(:, idx);
hi=data.hi(:, idx);
lo=data.lo(:, idx);
cl=data.cl(:, idx);
stdretC2C90d=backshift(1, smartMovingStd(calculateReturns(cl, 1), 90));
longs= op >= backshift(1, hi).*(1+entryZscore*stdretC2C90d);
shorts=op <= backshift(1, lo).*(1-entryZscore*stdretC2C90d);
positions=zeros(size(cl));
positions(longs)=1;
positions(shorts)=-1;
ret=positions.*(op-cl)./op;
ret(isnan(ret))=0;
fprintf(1, '%s APR=%10.4f Sharpe=%4.2f\n', data.syms{idx}, prod(1+ret).^(252/length(ret))-1, mean(ret)*sqrt(252)/std(ret));
% APR= 0.1327 Sharpe=1.44
cumret=cumprod(1+ret)-1; % compounded ROE
plot(cumret);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
+83
View File
@@ -0,0 +1,83 @@
clear;
stks=load('../Data/inputDataOHLCDaily_20120424', 'stocks', 'tday','cl');
etf=load('../Data/inputData_ETF', 'tday', 'syms', 'cl');
% Ensure data have same dates
[tday idx1 idx2]=intersect(stks.tday, etf.tday);
stks.cl=stks.cl(idx1, :);
etf.cl=etf.cl(idx2, :);
% Use SPY
idxS=find(strcmp('SPY', etf.syms));
etf.cl=etf.cl(:, idxS);
trainDataIdx=find(tday>=20070101 & tday<=20071231);
testDataIdx=find(tday > 20071231);
isCoint=false(size(stks.stocks));
for s=1:length(stks.stocks)
% Combine the two time series into a matrix y2 for input into Johansen test
y2=[stks.cl(trainDataIdx, s), etf.cl(trainDataIdx)];
badData=any(isnan(y2), 2);
y2(badData, :)=[]; % remove any missing data
if (size(y2, 1) > 250)
results=johansen(y2, 0, 1); % johansen test with non-zero offset but zero drift, and with the lag k=1.
if (results.lr1(1) > results.cvt(1, 1))
isCoint(s)=true;
end
end
end
length(find(isCoint))
% 98: there are 98 stocks that are cointegrating with SPY
% Form a long-only portfolio with all stocks that cointegrate with SPY, with equal
% capital allocation
yN=stks.cl(trainDataIdx, isCoint);
logMktVal_long=sum(log(yN), 2); % The net market value of the long-only portfolio is same as the "spread"
% Confirm that the portfolio cointegrates with SPY
ytest=[logMktVal_long, log(etf.cl(trainDataIdx))];
results=johansen(ytest, 0, 1); % johansen test with non-zero offset but zero drift, and with the lag k=1.
prt(results);
% Output:
% Johansen MLE estimates
% NULL: Trace Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 15.869 13.429 15.494 19.935
% r <= 1 variable 2 6.197 2.705 3.841 6.635
%
% NULL: Eigen Statistic Crit 90% Crit 95% Crit 99%
% r <= 0 variable 1 9.671 12.297 14.264 18.520
% r <= 1 variable 2 6.197 2.705 3.841 6.635
results.evec
%
% ans =
%
% 1.0939 -0.2799
% -105.5600 56.0933
% Apply linear mean-reversion model on test set
yNplus=[stks.cl(testDataIdx, isCoint), etf.cl(testDataIdx)]; % Array of stock and ETF prices
weights=[repmat(results.evec(1, 1), size(stks.cl(testDataIdx, isCoint))), ...
repmat(results.evec(2, 1), size(etf.cl(testDataIdx)))]; % Array of log market value of stocks and ETF's
logMktVal=smartsum(weights.*log(yNplus), 2); % Log market value of long-short portfolio
lookback=5;
numUnits=-(logMktVal-movingAvg(logMktVal, lookback))./movingStd(logMktVal, lookback); % capital invested in portfolio in dollars. movingAvg and movingStd are functions from epchan.com/book2
positions=repmat(numUnits, [1 size(weights, 2)]).*weights; % positions is the dollar capital in each stock or ETF.
pnl=smartsum(lag(positions, 1).*(log(yNplus)-lag(log(yNplus), 1)), 2); % daily P&L of the strategy
ret=pnl./smartsum(abs(lag(positions, 1)), 2); % return is P&L divided by gross market value of portfolio
ret(isnan(ret))=0;
figure;
plot(cumprod(1+ret)-1); % Cumulative compounded return
fprintf(1, 'APR=%f Sharpe=%f\n', prod(1+ret).^(252/length(ret))-1, sqrt(252)*mean(ret)/std(ret));
% APR=0.044930 Sharpe=1.319397
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+61
View File
@@ -0,0 +1,61 @@
clear;
load('inputDataOHLCDaily_stocks_20120424');
lookback=252;
holddays=25;
topN=50;
% idxStart=find(tday==20100104);
% idxEnd=find(tday==20120424);
idxStart=find(tday==20070515);
idxEnd=find(tday==20071231);
% idxStart=find(tday==20080102);
% idxEnd=find(tday==20091231);
% tday=tday(idxStart:idxEnd);
% cl=cl(idxStart:idxEnd, :);
% op=op(idxStart:idxEnd, :);
% cl is a TxN array of closing prices, where T is the number of trading
% days, and N is the number of stocks in the S&P 500
ret=(cl- backshift(lookback,cl))./backshift(lookback,cl); % daily returnslongs=false(size(ret));
shorts=false(size(ret));
positions=zeros(size(ret));
for t=lookback+1:length(tday)
[foo idx]=sort(ret(t, :), 'ascend');
nodata=find(isnan(ret(t, :)));
idx=setdiff(idx, nodata, 'stable');
longs(t, idx(end-topN+1:end))=true;
shorts(t, idx(1:topN))=true;
end
for h=0:holddays-1
long_lag=backshift(h, longs);
long_lag(isnan(long_lag))=false;
long_lag=logical(long_lag);
short_lag=backshift(h, shorts);
short_lag(isnan(short_lag))=false;
short_lag=logical(short_lag);
positions(long_lag)=positions(long_lag)+1;
positions(short_lag)=positions(short_lag)-1;
end
dailyret=smartsum(backshift(1, positions).*(cl-lag(cl))./lag(cl), 2)/(2*topN)/holddays;
dailyret(isnan(dailyret))=0;
cumret=cumprod(1+dailyret(idxStart:idxEnd))-1;
plot(cumret);
tday=tday([idxStart:idxEnd]);
fprintf(1, 'Avg Ann Ret=%7.4f Sharpe ratio=%4.2f \n',252*smartmean(dailyret(idxStart:idxEnd)), sqrt(252)*smartmean(dailyret(idxStart:idxEnd))/smartstd(dailyret(idxStart:idxEnd)));
fprintf(1, 'APR=%10.4f\n', prod(1+dailyret(idxStart:idxEnd)).^(252/length(dailyret(idxStart:idxEnd)))-1);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
% Avg Ann Ret= 0.0315 Sharpe ratio=0.40
% APR= 0.0288
% Max DD =-0.066923 Max DDD in days=182
+81
View File
@@ -0,0 +1,81 @@
clear;
load('../Data/AUDCAD_unequal_ret', 'ret');
moments={mean(ret), std(ret), skewness(ret), kurtosis(ret)};
[ret_sim, type]=pearsrnd(moments{:}, 100000, 1);
g=inline('sum(log(1+f*R))/length(R)', 'f', 'R');
% g=inline('prod(1+f*R)^(1/length(R))-1', 'f', 'R');
myf=0:23;
myg=NaN(24, 1);
for f=myf
myg(f+1)=g(f, ret_sim);
end
plot(myf, myg);
minusG=@(f)-g(f, ret);
minusGsim=@(f)-g(f, ret_sim);
optimalF=fminbnd(minusGsim, 0, 20); % optimal leverage based on simulated returns
fprintf(1, 'Optimal leverage=%f optimal growth rate=%f\n', optimalF, -minusGsim(optimalF));
minR=min(ret_sim); % minimum return in simulated series
fprintf(1, 'minR=%f\n', minR);
maxDD=calculateMaxDD(cumprod(1+optimalF*ret_sim)-1); % max drawdown with optimal leverage
fprintf(1, 'f=%i maxDD with optimal leverage=%f\n', optimalF, maxDD);
maxDD=calculateMaxDD(cumprod(1+optimalF/2*ret_sim)-1); % max drawdown with half of optimal leverage
fprintf(1, 'f=%i maxDD with half of optimal leverage=%f\n', optimalF/2, maxDD);
maxDD=calculateMaxDD(cumprod(1+optimalF/7*ret_sim)-1); % max drawdown with 1/7 of optimal leverage
fprintf(1, 'f=%i maxDD with 1/7 of optimal leverage=%f\n', optimalF/7, maxDD);
maxDD=calculateMaxDD(cumprod(1+optimalF/1.4*ret)-1); % max drawdown with 1/1.4 of optimal leverage for historical returns
fprintf(1, 'f=%i maxDD for historical returns=%f\n', optimalF/1.4, maxDD);
D=0.5;
fprintf(1, 'Growth rate on simulated returns using D=%3.1f of optimal leverage on full account=%f\n', D, -minusGsim(optimalF*D));
fprintf(1, 'MaxDD on simulated returns using D of optimal leverage on full account=%f\n', calculateMaxDD(cumprod(1+optimalF*D*ret_sim)-1));
% CPPI
g_cppi=0;
% g_debug=0;
drawdown=0;
for t=1:length(ret_sim)
g_cppi=g_cppi+log(1+ret_sim(t)*D*optimalF*(1+drawdown));
% g_cppi=(1+g_cppi)*(1+r(t)*D*optimalF*(1+drawdown))-1;
% g_debug=g_debug+log(1+r(t)*D*optimalF)
% if (g_cppi/t >= 1)
% keyboard;
% end
drawdown=min(0, (1+drawdown)*(1+ret_sim(t))-1);
end
g_cppi=g_cppi/length(ret_sim);
% g_cppi=(1+g_cppi)^(1/length(r))-1;
fprintf(1, 'Growth rate on simulated returns using CPPI=%f\n', g_cppi);
fprintf(1, 'Growth rate on historical returns using D of optimal leverage on full account=%f\n', -minusG(optimalF*D));
fprintf(1, 'MaxDD on historical returns using D of optimal leverage on full account=%f\n', calculateMaxDD(cumprod(1+optimalF*D*ret)-1));
% CPPI
g_cppi=0;
drawdown=0;
for t=1:length(ret)
% g_cppi=(1+g_cppi)*(1+ret(t)*D*optimalF*(1+drawdown))-1;
g_cppi=g_cppi+log(1+r(t)*D*optimalF*(1+drawdown));
drawdown=min(0, (1+drawdown)*(1+ret(t))-1);
end
g_cppi=g_cppi/length(ret);
% g_cppi=(1+g_cppi)^(1/length(ret))-1;
fprintf(1, 'Growth rate on historical returns using CPPI=%f\n', g_cppi);
+17
View File
@@ -0,0 +1,17 @@
function [mvavg] = movingAvg(x, T)
% [mvavg]=movingAvg(x, T). create moving average series over T days. mvavg
% has T-1 NaN in beginning.
assert(T>0);
mvavg = zeros(size(x,1)-T+1, size(x, 2));
for i=0:T-1
mvavg = mvavg + x(1+i:end-T+1+i, :);
end
mvavg = mvavg / T;
mvavg=[NaN*ones(T-1, size(x,2)); mvavg];
+20
View File
@@ -0,0 +1,20 @@
function sd=movingStd(x, T, varargin)
% calculate standard deviation of x over T days. Expect T-1
% NaN in the beginning of the series
% [mvstd]=movingStd(x, lookback, period) creates moving std of lookback
% periods. I.e. data is sampled every period.
% This uses std which normalizes by N-1.
sd=NaN*ones(size(x));
if (nargin == 2)
for t=T:size(x, 1)
% for t=T:length(x)
sd(t, :)=std(x(t-T+1:t, :));
end
else
period=varargin{1};
for t=T*period:size(x, 1)
sd(t, :)=std(x(t-T*period+1:t, :));
end
end
@@ -0,0 +1,69 @@
function [earnann]=parseEaringsCalendarFromEarningsDotCom(prevDate,todayDate, allsyms)
% [earnann]==parseEaringsCalendarFromEarningsDotCom(prevDate,todayDate, allsyms)
% allsyms=regexprep(allsyms, '\.', ''); % for earnings.com, BF.B is BFB
allsyms=regexprep(allsyms, '-', ''); % for earnings.com, BF.B is BFB
earnann=zeros(size(allsyms));
prevEarningsFile=urlread(['http://www.earnings.com/earning.asp?date=', num2str(prevDate), '&client=cb']);
todayEarningsFile=urlread(['http://www.earnings.com/earning.asp?date=', num2str(todayDate), '&client=cb']);
% patternSym='finance.yahoo.com/q\?s=[\w-%\.=&]*">([\w-\.]+)</a>';
% patternSym='<a\s+href="http://finance.yahoo.com/q\?s=[\w%\.=&]*">([\w-\.]+)</a>';
% patternSym='<a href="http://finance.yahoo.com/q\?s=.+">([\w-\.]+)</a>';
% patternTime='<small>([\w:\s]+)</small>';
prevd=day(datenum(num2str(prevDate), 'yyyymmdd'));
todayd=day(datenum(num2str(todayDate), 'yyyymmdd'));
prevmmm=datestr(datenum(num2str(prevDate), 'yyyymmdd'), 'mmm');
todaymmm=datestr(datenum(num2str(todayDate), 'yyyymmdd'), 'mmm');
patternSym='<a\s+href="company.asp\?ticker=([%\*\w\._/-]+)&coid';
% prevDate
patternPrevDateTime=['<td align="center"><nobr>', num2str(prevd), '-', num2str(prevmmm), '([ :\dABPMCO]*)</nobr>'];
symA=regexp(prevEarningsFile, patternSym , 'tokens');
timeA=regexp(prevEarningsFile, patternPrevDateTime, 'tokens');
symsA=[symA{:}];
timeA=[timeA{:}];
assert(length(symsA)==length(timeA));
isAMC=~cellfun('isempty', regexp(timeA, 'AMC'));
patternPM='[ ]+\d:\d\d[ ]+PM'; % e.g. ' 6:00 PM'
isAMC2=~cellfun('isempty', regexp(timeA, patternPM));
symsA=symsA(isAMC | isAMC2);
[foo, idxA, idxALL]=intersect(symsA, allsyms);
earnann(idxALL)=1;
% today
patternTodayDateTime=['<td align="center"><nobr>', num2str(todayd), '-', num2str(todaymmm), '([ :\dABPMCO]*)</nobr>'];
symA=regexp(todayEarningsFile, patternSym , 'tokens');
timeA=regexp(todayEarningsFile, patternTodayDateTime, 'tokens');
symsA=[symA{:}];
timeA=[timeA{:}];
symsA=symsA(1:length(timeA));
assert(length(symsA)==length(timeA));
isBMO=~cellfun('isempty', regexp(timeA, 'BMO'));
patternAM='[ ]+\d:\d\d[ ]+AM'; % e.g. ' 8:00 AM'
isBMO2=~cellfun('isempty', regexp(timeA, patternAM));
symsA=symsA(isBMO | isBMO2);
[foo, idxA, idxALL]=intersect(symsA, allsyms);
earnann(idxALL)=1;
+36
View File
@@ -0,0 +1,36 @@
clear;
load('inputDataOHLCDaily_stocks_20120424', 'tday', 'stocks', 'op', 'cl');
e=load('earnannFile', 'earnann', 'tday');
[tday idx1 idx2]=intersect(tday, e.tday);
op=op(idx1, :);
cl=cl(idx1, :);
earnann=e.earnann(idx2, :);
lookback=90;
retC2O=(op-backshift(1, cl))./backshift(1, cl);
stdC2O=smartMovingStd(retC2O, lookback);
positions=zeros(size(cl));
longs=retC2O >= 0.5*stdC2O & earnann;
shorts=retC2O <= -0.5*stdC2O & earnann;
positions(longs)=1;
positions(shorts)=-1;
ret=smartsum(positions.*(cl-op)./op, 2)/30;
cumret=cumprod(1+ret)-1;
plot(cumret);
fprintf(1, 'Avg Ann Ret=%7.4f Sharpe ratio=%4.2f \n',252*smartmean(ret), sqrt(252)*smartmean(ret)/smartstd(ret));
fprintf(1, 'APR=%10.4f\n', prod(1+ret).^(252/length(ret))-1);
[maxDD maxDDD]=calculateMaxDD(cumret);
fprintf(1, 'Max DD =%f Max DDD in days=%i\n\n', maxDD, round(maxDDD));
% Avg Ann Ret= 0.0667 Sharpe ratio=1.49
% APR= 0.0680
% Max DD =-0.026052 Max DDD in days=109
+35
View File
@@ -0,0 +1,35 @@
function [mvavg] = smartMovingAvg(x, T, varargin)
% [mvavg]=movingAvg(x, lookback). create moving average series over T days. mvavg
% has T-1 NaN in beginning. Ignore over days with NaN.
% [mvavg]=movingAvg(x, lookback, period) creates moving avg of lookback
% periods. I.e. data is sampled every period.
assert(T>0);
mvavg=zeros(size(x));
goodDays=isfinite(x);
xx=x;
xx(~goodDays)=0;
numGoodDays=zeros(size(x));
if (nargin == 2)
for i=0:T-1
mvavg=mvavg+backshift(i, xx);
numGoodDays=numGoodDays+isfinite(backshift(i, x));
end
else
period=varargin{1};
for i=0:T-1
mvavg=mvavg+backshift(i*period, xx);
numGoodDays=numGoodDays+isfinite(backshift(i*period, x));
end
end
nonzeroDays=numGoodDays>0;
mvavg(nonzeroDays)=mvavg(nonzeroDays) ./ numGoodDays(nonzeroDays);
mvavg(~nonzeroDays)=NaN;
+21
View File
@@ -0,0 +1,21 @@
function sd=smartMovingStd(x, T, varargin)
% calculate standard deviation of x over T days. Expect T-1
% NaN in the beginning of the series
% [mvstd]=smartMovingStd(x, lookback, period) creates moving std of lookback
% periods. I.e. data is sampled every period.
% This version is inefficient. See implementation of smartMovingCorrcoef
% for faster implementation.
sd=NaN*ones(size(x));
if (nargin == 2)
for t=T:size(x, 1)
% for t=T:length(x)
sd(t, :)=smartstd(x(t-T+1:t, :));
end
else
period=varargin{1};
for t=T*period:size(x, 1)
sd(t, :)=smartstd(x(t-T*period+1:t, :));
end
end
+43
View File
@@ -0,0 +1,43 @@
function y = smartmean(x,dim)
%SMARTMEAN Average or mean value ignoring NaN.
%
% Same as MEAN except that it returns the mean of the finite elements
% instead of propagating NaN and Inf
% Returns NaN if there are no finite elements
%
% For vectors, MEAN(X) is the mean value of the elements in X. For
% matrices, MEAN(X) is a row vector containing the mean value of
% each column. For N-D arrays, MEAN(X) is the mean value of the
% elements along the first non-singleton dimension of X.
%
% MEAN(X,DIM) takes the mean along the dimension DIM of X.
%
% Example: If X = [0 1 2
% 3 4 5]
%
% then mean(X,1) is [1.5 2.5 3.5] and mean(X,2) is [1
% 4]
%
% See also MEDIAN, STD, MIN, MAX, COV.
% Copyright (c) 1984-98 by The MathWorks, Inc.
% $Revision: 5.13 $ $Date: 1997/11/21 23:23:55 $
if nargin==1,
% Determine which dimension SUM will use
dim = min(find(size(x)~=1));
if isempty(dim), dim = 1; end
k=isfinite(x);
x(~k)=0;
warning off
y=sum(x)./sum(k,dim);
y(all(~isfinite(x)))=NaN;
warning on
else
k=isfinite(x);
x(~k)=0;
warning off
y=sum(x,dim)./sum(k,dim);
y(all(~isfinite(x), dim))=NaN;
warning on
end
+20
View File
@@ -0,0 +1,20 @@
function y = smartstd(x,dim)
%SMARTSTD Standard deviation of finite elements.
%
% Same as STD except that it ignores NaN and Inf instead of
% propagating them
%
% Normalizes by N, not N-1
if nargin<2,
dim = min(find(size(x)~=1));
if isempty(dim), dim = 1; end
end
tile=ones(1,max(ndims(x),dim));
tile(dim)=size(x,dim);
xc=x-repmat(smartmean(x,dim),tile); % Remove mean
y=sqrt(smartmean(conj(xc).*xc,dim)); % normalize by N
% y=sqrt(smartsum(conj(xc).*xc,dim)/(smartsum(abs(sign(xc)), dim)-1)); %normalize by N-1
+33
View File
@@ -0,0 +1,33 @@
function y = smartsum(x,dim)
%SMARTSUM Sum ignoring NaN.
%
% Same as SUM except that it returns the sum of the finite elements
% instead of propagating NaN and Inf
% Returns NaN if no element is finite
if nargin==1,
% Determine which dimension SUM will use
dim = min(find(size(x)~=1));
if isempty(dim), dim = 1; end
k=isfinite(x);
% x(~k)=-9999*ones(size(x(~k)));
% warning off
% y=sum(x.*k)./(sum(k,dim)>0);
% warning on
x(~k)=0;
y=sum(x, dim);
y(sum(k, dim)==0)=NaN;
else
% k=isfinite(x);
% x(~k)=-9999*ones(size(x(~k)));
% warning off
% y=sum(x.*k,dim)./(sum(k,dim)>0);
% warning on
k=isfinite(x);
x(~k)=0;
y=sum(x, dim);
y(sum(k, dim)==0)=NaN;
end
+59
View File
@@ -0,0 +1,59 @@
clear;
% 1 minute data on USDCAD
load('inputData_USDCAD', 'tday', 'hhmm', 'cl');
% Select the daily close at 16:59 ET.
y=cl(hhmm==1659);
plot(y);
% Assume a non-zero offset but no drift, with lag=1.
results=adf(y, 0, 1); % adf is a function in the jplv7 (spatial-econometrics.com) package.
% Print out results
prt(results);
% Augmented DF test for unit root variable: variable 1
% ADF t-statistic # of lags AR(1) estimate
% -1.840744 1 0.994120
%
% 1% Crit Value 5% Crit Value 10% Crit Value
% -3.458 -2.871 -2.594
% Find Hurst exponent
H=genhurst(log(y), 2);
fprintf(1, 'H2=%f\n', H);
% Variance ratio test from Matlab Econometrics Toolbox
[h,pValue]=vratiotest(log(y));
fprintf(1, 'h=%i\n', h); % h=1 means rejection of random walk hypothesis, 0 means it is a random walk.
fprintf(1, 'pValue=%f\n', pValue); % pValue is essentially the probability that the null hypothesis (random walk) is true.
% Output:
% h=0
% pValue=0.367281
% Find value of lambda and thus the halflife of mean reversion by linear regression fit
ylag=lag(y, 1); % lag is a function in the jplv7 (spatial-econometrics.com) package.
deltaY=y-ylag;
deltaY(1)=[]; % Regression functions cannot handle the NaN in the first bar of the time series.
ylag(1)=[];
regress_results=ols(deltaY, [ylag ones(size(ylag))]); % ols is a function in the jplv7 (spatial-econometrics.com) package.
halflife=-log(2)/regress_results.beta(1);
fprintf(1, 'halflife=%f days\n', halflife);
% halflife=115.209794 days
% Apply a simple linear mean reversion strategy to USDCAD
lookback=round(halflife); % setting lookback to the halflife found above
mktVal=-(y-movingAvg(y, lookback))./movingStd(y, lookback); % capital in number of shares invested in USDCAD. movingAvg and movingStd are functions from epchan.com/book2
pnl=lag(mktVal, 1).*(y-lag(y, 1))./lag(y, 1); % daily P&L of the strategy
pnl(isnan(pnl))=0;
figure;
plot(cumsum(pnl)); % Cumulative P&L