$O(n^2)$ Imlementation
Here is a brute-force method with $O(n^2)$ complexity and $O(n^2)$ memory usage.
A = LowerTriangularize[Outer[Plus, -#, #]] &[Developer`ToPackedArray[lst]];
idx = Ordering[#, -1][[1]] & /@ A;
minpos = Ordering[Extract[A, Transpose[{Range[Length[A]], idx}]], -1][[1]];
maxpos = idx[[minpos]];
mdd = (lst[[maxpos]] - lst[[minpos]])
daycount = minpos - maxpos
losspercentage = mdd/lst[[maxpos]] 100
ListLinePlot[{
Transpose[{Range[Length[lst]], lst}],
Transpose[{Range[maxpos, minpos], lst[[maxpos ;; minpos]]}]
},
PlotRange -> All,
PlotStyle -> {Automatic, Red}
]
6.24
88
20.0643

$O(n)$ Imlementation
Here is a prototype of a functions that should find the positions that realize the maximum drop down:
getMDDPosition = Compile[{{x, _Real, 1}},
Block[{y, min, max, minpos, maxpos, mdd, mddminpos, mddmaxpos},
mddminpos = mddmaxpos = maxpos = minpos = 1;
max = min = Compile`GetElement[x, 1];
mdd = 0.;
Do[
y = Compile`GetElement[x, i];
If[y <= min,
min = y;
minpos = i;
,
If[y >= max,
If[max - min >= mdd,
mdd = max - min;
mddmaxpos = maxpos;
mddminpos = minpos;
];
max = min = y;
maxpos = minpos = i;
];
],
{i, 2, Length[x]}];
If[max - min >= mdd,
mdd = max - min;
mddmaxpos = maxpos;
mddminpos = minpos;
];
{mddmaxpos, mddminpos}
],
CompilationTarget -> "C",
RuntimeAttributes -> {Listable},
Parallelization -> True,
RuntimeOptions -> "Speed"
];
Call it like
{maxpos, minpos} = getMDDPosition[lst]
{1, 89}
Use this at your own risk; I haven't conducted too much of testing...
Edit
Towards the problem that the compiled function needs to be recompiled in each session: One can use these very easy mechanics to memoize the compiled library. This way, only the loading into Mathematica has to be performed at runtime.
Write something like this into your package. When the package is loaded it checks whether a library already exists. If it does not exist, it compiles getMDDPosition
and copy its library to a file where it can be located afterwards. (This is only an example; best to write into a subdirectory of your package.) If it does exist, it just loads it from file. Note that still certain Mathematca packages for the treatment of compiled functions have to be loaded, but it has to be done only once per session, independent of the number of compiled functions you load this way.
Needs["CCompilerDriver`"];
If[FileExistsQ["getMDDPosition.dylib"] && FileExistsQ["getMDDPosition.m"],
getMDDPosition = Import["getMDDPosition.m"];
,
With[{libfile = "getMDDPosition" <> CCompilerDriver`CCompilerDriverBase`$PlatformDLLExtension},
getMDDPosition =
Compile[{{x, _Real, 1}},
Block[{y, min, max, minpos, maxpos, mdd, mddminpos, mddmaxpos},
mddminpos = mddmaxpos = maxpos = minpos = 1;
max = min = Compile`GetElement[x, 1];
mdd = 0.;
Do[y = Compile`GetElement[x, i];
If[y <= min, min = y;
minpos = i;,
If[y >= max,
If[max - min >= mdd, mdd = max - min;
mddmaxpos = maxpos;
mddminpos = minpos;
];
max = min = y;
maxpos = minpos = i;];
],
{i, 2, Length[x]}
];
If[max - min >= mdd, mdd = max - min;
mddmaxpos = maxpos;
mddminpos = minpos;
];
{mddmaxpos, mddminpos}
],
CompilationTarget -> "C",
RuntimeAttributes -> {Listable},
Parallelization -> True,
RuntimeOptions -> "Speed"];
CopyFile[getMDDPosition[[-1, 1]], libfile, OverwriteTarget -> True];
getMDDPosition[[-1, 1]] = libfile;
];
Export["getMDDPosition.m", getMDDPosition, "Package"];
]
Instead of loading "CCompilerDriver`"
here, it might be a better strategy to put it into the dependency list of your package (the second argument of BeginPackage
).