empyrical icon indicating copy to clipboard operation
empyrical copied to clipboard

Calmar Ratio w/ EMDD

Open akaniklaus opened this issue 7 years ago • 3 comments

It would be great if you can add this. http://alumnus.caltech.edu/~amir/mdd-risk.pdf

function EDD = emaxdrawdown(Mu, Sigma, T)
%EMAXDRAWDOWN Compute expected maximum drawdown for a Brownian motion.
%
%   EDD = emaxdrawdown(Mu, Sigma, T);
%
% Inputs:
%   Mu - The drift term of a Brownian motion with drift.
%   Sigma - The diffusion term of a Brownian motion with drift.
%   T - A time period of interest or a vector of times.
%
% Outputs:
%   EDD - Expected maximum drawdown for each time period in T.
%
% Notes:
%   If a geometric Brownian motion with stochastic differential equation
%       dS(t) = Mu0 * S(t) * dt + Sigma0 * S(t) * dW(t) ,
%   convert to the form here by Ito's Lemma with X(t) = log(S(t)) such that
%       Mu = M0 - 0.5 * Sigma0^2
%       Sigma = Sigma0 .
%
%   Maximum drawdown is non-negative since it is the change from a peak to a
%   trough.
%
% References:
%   Malik Magdon-Ismail, Amir F. Atiya, Amrit Pratap, and Yaser S. Abu-Mostafa,
%   "On the Maximum Drawdown of a Brownian Motion", Journal of Applied
%   Probability, Volume 41, Number 1, March 2004, pp. 147-161. 
%
%   See also MAXDRAWDOWN
%   Copyright 2005 The MathWorks, Inc.
%   $Revision: 1.1.6.2 $ $Date: 2005/12/12 23:16:10 $
if nargin < 3 || isempty(Mu) || isempty(Sigma) || isempty(T)
    error('Finance:emaxdrawdown:MissingInputArg', ...
        'Missing required input arguments Mu, Sigma, or T.');
end
[n, i] = size(Mu);
if (n > 1) || (i > 1)
    error('Finance:emaxdrawdown:InvalidInputArg', ...
        'Argument Mu must be a scalar.');
end
[n, i] = size(Sigma);
if (n > 1) || (i > 1)
    error('Finance:emaxdrawdown:InvalidInputArg', ...
        'Argument Sigma must be a scalar.');
end
T = T(:);
[n, i] = size(T);
if i > 1
    error('Finance:emaxdrawdown:InvalidInputArg', ...
        'Argument T must be a vector.');
end
    
if ~isfinite(Mu) || ~isfinite(Sigma) || (Sigma < 0)
    error('Finance:emaxdrawdown:InvalidInputArg', ...
        'Invalid argument values. Requires finite Mu, Sigma >= 0, T >= 0.');
end
for i = 1:n
    if ~isfinite(T(i)) || (T(i) < 0)
        error('Finance:emaxdrawdown:InvalidInputArg', ...
            'Invalid argument values. Requires finite T >= 0.');
    end
end
 
if Sigma < eps
    if Mu >= 0.0
        EDD = zeros(n,1);
    else
        EDD = - Mu .* T;
    end
    return
end
EDD = zeros(n,1);
for i = 1:n
    if T(i) < eps
        EDD = zeros(n,1);
    else
        if abs(Mu) <= eps
            EDD(i) = (sqrt(pi/2) * Sigma) .* sqrt(T(i));
        elseif Mu > eps
            Alpha = Mu/(2.0 * Sigma * Sigma);
            EDD(i) = emaxddQp(Alpha * Mu * T(i))/Alpha;
        else
            Alpha = Mu/(2.0 * Sigma * Sigma);
            EDD(i) = - emaxddQn(Alpha * Mu * T(i))/Alpha;
        end
    end
end
function Q = emaxddQp(x)
A = [   0.0005;     0.001;      0.0015;     0.002;      0.0025;     0.005;
        0.0075;     0.01;       0.0125;     0.015;      0.0175;     0.02;
        0.0225;     0.025;      0.0275;     0.03;       0.0325;     0.035;
        0.0375;     0.04;       0.0425;     0.045;      0.0475;     0.05;
        0.055;      0.06;       0.065;      0.07;       0.075;      0.08;
        0.085;      0.09;       0.095;      0.1;        0.15;       0.2;
        0.25;       0.3;        0.35;       0.4;        0.45;       0.5;
        1.0;        1.5;        2.0;        2.5;        3.0;        3.5;
        4.0;        4.5;        5.0;        10.0;       15.0;       20.0;
        25.0;       30.0;       35.0;       40.0;       45.0;       50.0;
        100.0;      150.0;      200.0;      250.0;      300.0;      350.0;
        400.0;      450.0;      500.0;      1000.0;     1500.0;     2000.0;
        2500.0;     3000.0;     3500.0;     4000.0;     4500.0;     5000.0 ];
B = [   0.01969;    0.027694;   0.033789;   0.038896;   0.043372;   0.060721;
        0.073808;   0.084693;   0.094171;   0.102651;   0.110375;   0.117503;
        0.124142;   0.130374;   0.136259;   0.141842;   0.147162;   0.152249;
        0.157127;   0.161817;   0.166337;   0.170702;   0.174924;   0.179015;
        0.186842;   0.194248;   0.201287;   0.207999;   0.214421;   0.220581;
        0.226505;   0.232212;   0.237722;   0.24305;    0.288719;   0.325071;
        0.355581;   0.382016;   0.405415;   0.426452;   0.445588;   0.463159;
        0.588642;   0.668992;   0.72854;    0.775976;   0.815456;   0.849298;
        0.878933;   0.905305;   0.92907;    1.088998;   1.184918;   1.253794;
        1.307607;   1.351794;   1.389289;   1.42186;    1.450654;   1.476457;
        1.647113;   1.747485;   1.818873;   1.874323;   1.919671;   1.958037;
        1.991288;   2.02063;    2.046885;   2.219765;   2.320983;   2.392826;
        2.448562;   2.494109;   2.532622;   2.565985;   2.595416;   2.621743 ];
if x > 5000
    Q = 0.25*log(x) + 0.49088;
elseif x < 0.0005
    Q = 0.5*sqrt(pi*x);
else
    Q = interp1(A,B,x);
end
function Q = emaxddQn(x)
A = [   0.0005;     0.001;      0.0015;     0.002;      0.0025;     0.005;
        0.0075;     0.01;       0.0125;     0.015;      0.0175;     0.02;
        0.0225;     0.025;      0.0275;     0.03;       0.0325;     0.035;
        0.0375;     0.04;       0.0425;     0.045;      0.0475;     0.05;
        0.055;      0.06;       0.065;      0.07;       0.075;      0.08;
        0.085;      0.09;       0.095;      0.1;        0.15;       0.2;    
        0.25;       0.3;        0.35;       0.4;        0.45;       0.5;
        0.75;       1.0;        1.25;       1.5;        1.75;       2.0;
        2.25;       2.5;        2.75;       3.0;        3.25;       3.5;
        3.75;       4.0;        4.25;       4.5;        4.75;       5.0 ];
B = [   0.019965;   0.028394;   0.034874;   0.040369;   0.045256;   0.064633;
        0.079746;   0.092708;   0.104259;   0.114814;   0.124608;   0.133772;
        0.142429;   0.150739;   0.158565;   0.166229;   0.173756;   0.180793;
        0.187739;   0.194489;   0.201094;   0.207572;   0.213877;   0.220056;
        0.231797;   0.243374;   0.254585;   0.265472;   0.27607;    0.286406;
        0.296507;   0.306393;   0.316066;   0.325586;   0.413136;   0.491599;
        0.564333;   0.633007;   0.698849;   0.762455;   0.824484;   0.884593;
        1.17202;    1.44552;    1.70936;    1.97074;    2.22742;    2.48396;
        2.73676;    2.99094;    3.24354;    3.49252;    3.74294;    3.99519;
        4.24274;    4.49238;    4.73859;    4.99043;    5.24083;    5.49882 ];
if (x > 5.0)
    Q = x + 0.5;
elseif x < 0.0005
    Q = 0.5*sqrt(pi*x);
else
    Q = interp1(A,B,x);
end

akaniklaus avatar Mar 30 '18 16:03 akaniklaus

Also, Sterling ratio is missing.

akaniklaus avatar Apr 01 '18 12:04 akaniklaus

@akaniklaus Sorry for the late response, but I believe that the max drawdown is implemented here:

https://github.com/quantopian/empyrical/blob/master/empyrical/stats.py#L315

eigenfoo avatar May 29 '18 17:05 eigenfoo

@eigenfoo Thanks but expected max drawdown (for a brownian motion) is different than max drawdown

akaniklaus avatar May 29 '18 17:05 akaniklaus