Last active
August 29, 2015 13:58
-
-
Save caub/10067926 to your computer and use it in GitHub Desktop.
zigzag chart indicator, a piecewise linear curve fit with alternate slopes (up, down, up, down...), used here to detect double-top and double-bottom patterns http://en.wikipedia.org/wiki/Chart_pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function [z,s,offsetH,offsetL]=zigzag(depth, h, l) | |
% return the zigzag points (=last points of a series of local extrema) | |
% and signals (= first point of these series) from a series of prices | |
% (h=l by default, or else specify the high prices per period, and low price from ohlc) | |
% depth: the number of points looked back | |
if nargin<=1 | |
rng(0); | |
depth=3; | |
h = cumsum(rand(40,1)-0.5); | |
end | |
if nargin==2 | |
l = h; | |
end | |
s = []; % the signals (=first maxima/minima) | |
z = []; % the zigzags (= last maxima/minima) | |
offsetH=1; %first index of highs | |
offsetL=1; %first index of lows, it will be [offsetH,offsetL]=[1,2] or [2,1] | |
cur=0; % current max/min index, minima are *-1 | |
for i=depth:length(h) | |
[~,j]=max(flipud(h(i-depth+1:i))); | |
[~,k]=min(flipud(l(i-depth+1:i))); | |
% flipud so as to make sure to take last values in case of equality | |
if j==1 && k==1 %rare case | |
if cur==0 % oh damn let's choose to start with min | |
offsetH =2; | |
s= [s;i]; | |
cur = -i; | |
elseif cur>0 | |
if h(i)>=h(cur) | |
cur = i; | |
end | |
else | |
if l(i)<=l(-cur) | |
cur = -i; | |
end | |
end | |
elseif j==1 | |
if cur==0 | |
offsetL =2; | |
s= [s;i]; | |
cur = i; | |
elseif cur>0 | |
if h(i)>=h(cur) | |
cur = i; | |
end | |
else | |
z=[z;-cur]; | |
s= [s;i]; | |
cur = i; | |
end | |
elseif k==1 | |
if cur==0 | |
offsetH =2; | |
s= [s;i]; | |
cur = -i; | |
elseif cur<0 | |
if l(i)<=l(-cur) | |
cur = -i; | |
end | |
else | |
z=[z;cur]; | |
s= [s;i]; | |
cur = -i; | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Demo fake dataset | |
rng(4) | |
h = cumsum(rand(1010,1)-0.5); | |
% smooth with ema(8) | |
%w=linspace(-1,0,8);w =w/sum(w); | |
%h=conv(h,w); | |
h=h(1:length(h)); | |
%h = movavg(h, 8,8,'e'); %the same as the 3 lines above | |
l = h; | |
depth = 8; | |
d0 = 0.2; | |
D0 = 0.5; | |
%% Real dataset | |
tic | |
f = fopen('EURCHF_1m_2014.csv'); % http://www.dukascopy.com/swiss/french/marketwatch/historical/ | |
A = textscan(f, '%s %f %f %f %f %f', 'Delimiter', ',j', 'HeaderLines', 1); | |
fclose(f); | |
A{1} = char(A{1}); | |
A{1} = datenum(A{1}(:, 1:19), 'dd.mm.yyyy hh:MM:ss'); | |
toc | |
Hour = hour(A{1}); | |
Weekday = weekday(A{1}); | |
iw = find(Hour >21 & Weekday==1 | Weekday>1 & Weekday<6 | Weekday==6 & Hour<21); | |
HLC = [A{3}(iw) A{4}(iw) A{5}(iw)]; | |
cost = 0.0001; | |
depth = 20; | |
d0 = 1e-4; | |
D0 = 10e-4; | |
hlc = HLC(end-2e5:end-1e5,:); | |
[h,l,c] = deal(hlc(:,1), hlc(:,2), hlc(:,3)); | |
%% Extract zigzags and plot them | |
[z,s,offsetH,offsetL]=zigzag(depth, h, l); | |
close all; | |
figure, hold on | |
plot([h l]) | |
ss = zeros(size(s)); | |
ss(offsetH:2:end) = h(s(offsetH:2:end)); | |
ss(offsetL:2:end) = l(s(offsetL:2:end)); | |
plot(s, ss, '+c'); | |
zz = zeros(size(z)); | |
zz(offsetH:2:end) = h(z(offsetH:2:end)); | |
zz(offsetL:2:end) = l(z(offsetL:2:end)); | |
plot(z, zz, 'dr'); | |
line(z, zz, 'Color', 'k') | |
%% Double-top/bottom (http://bit.ly/double-top) | |
D = abs(zz(1:end-3)-zz(2:end-2)); | |
d = abs(zz(4:end)-zz(2:end-2)); | |
i = d<d0 & D >=D0; | |
% isolate double-tops from double bottom | |
ih = mod((1:length(z)-3)',2)==offsetH-1 & i; | |
il = mod((1:length(z)-3)',2)==offsetL-1 & i; | |
fprintf('found %d double-tops, %d double-bottoms out of %d zigzags\n', length(find(ih)), length(find(il)), length(z)); | |
ih_ = [0;ih;0;0]|[0;0;ih;0]|[0;0;0;ih];% keep points 2,3,4 of zigzags | |
ihs = logical([0;0;0;ih(1:end-1)]); | |
il_ = [0;il;0;0]|[0;0;il;0]|[0;0;0;il]; | |
ils = logical([0;0;0;il(1:end-1)]); | |
zzh = nan(size(zz)); | |
zzh(ih_) = zz(ih_); | |
zzl = nan(size(zz)); | |
zzl(il_) = zz(il_); | |
% plot fancy zigzag lines, double-top in blue, double-bottom in red | |
plot(z, zzh, 'LineWidth', 3, 'Color', 'b'); | |
plot(z, zzl, 'LineWidth', 3, 'Color', 'm'); | |
% calculate profit on a strategy that sells on double-top, buys on | |
% double-bottom | |
signals = zeros(size(h)); | |
signals(s(logical([0;0;0;0;ih(1:end-4)]))) = 1; | |
signals(s(logical([0;0;0;0;il(1:end-4)]))) = -1; | |
for i = 2:length(h) % fill with prior non-null sign | |
if signals(i) == 0 | |
signals(i) = signals(i-1); | |
end | |
end | |
costPerTrade=0; | |
trades = [0; 0; diff(signals(1:end-1))]; % shift trading by 1 period, time for the order to pass | |
cash = cumsum(-trades.*h-abs(trades)*costPerTrade/2); | |
pandl = [0; signals(1:end-1)].*h + cash; | |
r = diff(pandl); | |
figure,plot(pandl); | |
%% Head-and-shoulders (http://bit.ly/double-top) | |
D = abs(zz(1:end-5)-zz(4:end-2)); | |
dh = abs(zz(2:end-4)-zz(6:end)); | |
dl = abs(zz(3:end-3)-zz(5:end-1)); | |
i = D>D0 & dh<d0 & dl<d0 ... | |
& sign(zz(1:end-5)-zz(4:end-2)) == sign(zz(6:end)-zz(4:end-2)) ... | |
& sign(zz(1:end-5)-zz(4:end-2)) == sign(zz(2:end-4)-zz(4:end-2)); | |
% isolate double-tops from double bottom | |
ih = mod((1:length(z)-5)',2)==offsetH-1 & i; | |
il = mod((1:length(z)-5)',2)==offsetL-1 & i; | |
ih_ = [0;ih;0;0;0;0]|[0;0;ih;0;0;0]|[0;0;0;ih;0;0]|[0;0;0;0;ih;0]|[0;0;0;0;0;ih]; | |
ihs = logical([0;0;0;ih(1:end-1)]); | |
il_ = [0;il;0;0;0;0]|[0;0;il;0;0;0]|[0;0;0;il;0;0]|[0;0;0;0;il;0]|[0;0;0;0;0;il]; | |
ils = logical([0;0;0;il(1:end-1)]); | |
zzh = nan(size(zz)); | |
zzh(ih_) = zz(ih_); | |
zzl = nan(size(zz)); | |
zzl(il_) = zz(il_); | |
% | |
plot(z, zzh, 'LineWidth', 4, 'Color', 'b'); | |
plot(z, zzl, 'LineWidth', 4, 'Color', 'm'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment