Forum on trading, automated trading systems and testing trading strategies

What is wrong in my code? Getting error 138Alain Verleyen, 2018.11.12 16:35

mql4 topic in mql4 section of the forum please.37483

Forum on trading, automated trading systems and testing trading strategies

What is wrong in my code? Getting error 138Alain Verleyen, 2018.11.12 16:35

mql4 topic in mql4 section of the forum please.82

37483

82

Looks like nobody has an idea?

This is the line that needs to be modified but I'm stumped

if(MER_SD != 0) SR = MER_Average / MER_SD; //

This is the line that needs to be modified but I'm stumped

94

Looks like nobody has an idea?

This is the line that needs to be modified but I'm stumped

It's this line:

for(i = 0; i < ArraySize(MonthlyProfit); i++){ // skip positive results if (MonthlyProfit[i] > 0) MonthlyEarningRate[i] = 0; else MonthlyEarningRate[i] = MonthlyProfit[i] / Balance; SumMER += MonthlyEarningRate[i]; Balance += MonthlyProfit[i]; }

82

94

...doing this, Sortino ratio always returns 1

The 1 is caused by this part:

double MER_SD = iStdDevOnArray(MonthlyEarningRate, 0, TradeMonths, 0, 0, 0); // returns 0 double SR = 1; if(MER_SD != 0) SR = MER_Average / MER_SD; // this line never gets executed

iStdDevOnArray() can be considered undocumented. In the last 10 years I never found a working example here or anywhere at the web. So until some person smarter then me comes up with the right syntax I calculate the std-dev manually if I need it:

// calculate deviation manually (for some reason iStdDevOnArray() fails) //dev = iStdDevOnArray(buffer, WHOLE_ARRAY, periods, 0, MODE_SMA, bar) * stdDevMultiplier; double sum = 0; for (int i=0; i < periods; i++) { double value = series[i]; double ma = iMAOnArray(series, WHOLE_ARRAY, periods, 0, MODE_SMA... double distance = value - ma; sum += distance * distance; } double stdDev = MathSqrt(sum/periods); double myDev = stdDev * stdDevMultiplier;

Essentially this is the manual way to calculate std-dev. You have to adapt the iMAOnArray() part to your profit series.

82

@alphatrading

Could you provide a working example with the sortino ratio? Would really appreciate it thanks

Could you provide a working example with the sortino ratio? Would really appreciate it thanks

94

There are a few things to consider:

You can't calculate statistics for a test the way a fund manager would do it for annual reporting. Summing up results by month will hide all the in-between drawdowns, that's exactly what you try to avoid by calculating those values in the first place. So you have to take the actual results of every trade as inputs.

The calculated ratios need to be normalized to become comparable. A fund manager does this by normalizing "monthly" which is a simplification but for funds this is OK as returns and in-between deviations are always very small. But for a test in the tester this approach doesn't work. First we need a sufficient large sample, so each test should have at least 100 trades. Now how to compare a test on M15 over 3 months with 100 trades with a test on H4 over 9 months with 200 trades? It's not easily possible.

As a general rule tests should be non-compounding, so we are able to simplify and to compare absolute values (not growth rates). This let's us take the factor "money"/"balance" out of the equation. Instead we calculate trade results in positive or negative pips. It means that a test should use a standard lotsize over the whole testing period. If the strategy scales in/out or uses oherwise different trade sizes those results need to be normalized again (pips * lotsize). Later when we are satisfied by the results we may still run the strategy with compounding by simple multiplication.

By calculating stats for each single trade we take the factor "time" out of the equation. 100 trades on M15 over 3 months become comparable over 100 trades on H4 over a different time period. We still need the same/similar number of trades. How can I compare 30 trades on one period with 200 trades on another? This is the most complicated part and I will not cover it in the following calculations. Solution: Markets (and equity curves) are fractal and instead of using trade closes as input we need to normalize the whole equity curve. Both equity curves (from a 30 trade test and from a 200 trade tests) need to be split into the same number of units (equity points) and those points become input of the stat calculations. For this we need equity curves and because most people will not be able to produce those I'll skip it here.

After trade results are normalized and ratios calculated the raw results can be normalized back to let's say a monthly ratio. Again I'll skip it as it depends highly on the strategy. You can't compare a scalper to a long term trend follower. As can be seen it takes a lot of effort to get comparable results over different test periods, timeframes and/or trade numbers.

Finally the calculations:

/** * */ void CalculateRatios() { int trades, orders = OrdersHistoryTotal(); double totalPips, pips[]; ArrayResize(pips, orders); int pipDigits = Digits & (~1); double pip = NormalizeDouble(1/MathPow(10, pipDigits), pipDigits); for (int i=0; i < orders; i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && OrderSymbol()==Symbol() && OrderType()<=OP_SELL) { pips[trades] = (OrderType()-OrderType()^1) * (OrderOpenPrice()-OrderClosePrice()) / pip; totalPips += pips[trades]; trades++; } } ArrayResize(pips, trades); double avgPips = totalPips/trades; double sharpe = CalculateSharpeRatio(pips, totalPips); double sortino = CalculateSortinoRatio(pips, totalPips); Print("trades="+ trades +" totalPips="+ DoubleToStr(totalPips, 1) +" avgPips="+ DoubleToStr(avgPips, 2) +" sharpe="+ DoubleToStr(sharpe, 4) +" sortino="+ DoubleToStr(sortino, 4)); } /** * */ double CalculateSharpeRatio(double values[], double sum) { int size = ArraySize(values); if (!size) return(NULL); double mean = sum / size; double sharpe = mean / MathStdev(values, mean); return(sharpe); } /** * */ double CalculateSortinoRatio(double values[], double sum) { int size = ArraySize(values); if (!size) return(NULL); double losses[]; ArrayResize(losses, size); for (int i, n=0; i < size; i++) { if (values[i] <= 0) { losses[n] = values[i]; n++; } } ArrayResize(losses, n); double mean = sum / size; double sortino = mean / MathStdev(losses, mean); return(sortino); } /** * */ double MathStdev(double values[], double mean) { int size = ArraySize(values); if (!size) { double N_INF = MathLog(0); // negative infinity double P_INF = -N_INF; // positive infinity double NaN = N_INF - N_INF; // not-a-number return(NaN); } double sum; for (int i=0; i < size; i++) { sum += MathPow((values[i] - mean), 2); } double stdDev = MathSqrt(sum / size); return(stdDev); }

94

Calculating average trade results in pip gives you another good and easily interpretable measure. You immediately see the probable influence of slippage/commissions/swap on your results. If your average trade gains less than 5 pip the probability is high that most of your theoretical gains will be eaten away by trading costs.

Another option in the calulation of the sortino ratio is to not skip positive results but instead skip all results better then the mean. This way your sortino ratio describes all trades worse then the average trade which may make sense, too. It depends on what you prefer/want to know with your stats...

Can somebody who knows mql4 better than me help convert this function SharpeRatio() to work as a Sortino ratio instead? Thank you for your time