Walk-forward optimization library for MetaTrader: Estimator formula

This post is a part of documentation of WalkForwardOptimizer library for MetaTrader4/5 - here is the table of contents.
Estimator formula reference
Expressions for performance estimator can contain the following variables:
NP - net profit
GP - gross profit
GL - gross loss
PF - profit factor
SHARPE - sharpe
TRADES - number of trades
DDMAX - maximum drawdown
DDREL - maximum relative drawdown
WIN - number of winning trades
LOSS - number of losing trades
DEPOSIT - initial balance
AR - average return, i.e. average % of return on a deal (profit/loss amount divided by current balance, averaged on all trades) - this is a measure of balance curve slope, used in sharpe (MT5, version 1.6+)
STDEV - standard deviation of balance curve (MT5, version 1.6+)
All mathematical and logical operators are supported, as well as common functions such as abs, exp, max, min, pow, sqrt. Here is an example of expression for modified PROC (Pessimistic Return on Capital):
(GP * (1 - 1/sqrt(WIN + 1)) + GL * (1 + 1/sqrt(LOSS + 1))) + NP / TRADES
Starting from version 1.6 for MT5 the following option is available.
If required calculations can not be expressed with a formula, one may implement a custom callback of type (updated in 1.8):
typedef double (*FUNCPTR_WFO_CUSTOM)(const datetime startDate, const datetime splitDate, const double &map[/*WFO_STATS_MAP*/]);
in the expert adviser and pass it to the library via wfo_setCustomPerformanceMeter(FUNCPTR_WFO_CUSTOM funcptr). Then WFO will call it from OnTester with the dates and the map filled with actual data. The function should return a custom value for OnTester (TesterStatistics can not be used inside!).
The indices of the array "map" are defined by the following enum:
/** * Built-in enum with indices for WFO stats container. * All is calculated for in-sample range of dates. */ enum WFO_STATS_MAP { WFO_STATS_NP, // net profit WFO_STATS_GP, // gross profit WFO_STATS_GL, // gross loss WFO_STATS_PF, // profit factor WFO_STATS_SHARPE, // sharpe WFO_STATS_TRADES, // N of trades WFO_STATS_DDMAX, // max drawdown value WFO_STATS_DDREL, // drawdown percent WFO_STATS_WIN, // N of winning trades WFO_STATS_LOSS, // N of losing trades WFO_STATS_DEPOSIT, // start deposit WFO_STATS_AR, // average return (% of current balance) WFO_STATS_STDEV, // standard deviation of balance curve WFO_STATS_MAP_SIZE };
The list of supported variants corresponds to the variables names shown above.
Here is an example of usage:
double customEstimator(const datetime startDate, const datetime splitDate, const double &map[]) export { // TesterStatistics should not be normally used in custom estimators, // it's used here for validation purpose only (to check in-sample profit provided by WFO library // by calculating it in alternative way as the total profit minus out-of-sample) double profit = TesterStatistics(STAT_PROFIT); HistorySelect(splitDate + 1, TimeCurrent()); uint total = HistoryDealsTotal(); ulong ticket = 0; double plus = 0, minus = 0; int win = 0, loss = 0; for(uint i = 0; i < total; i++) { if((ticket = HistoryDealGetTicket(i)) > 0) { if(HistoryDealGetInteger(ticket, DEAL_ENTRY) != DEAL_ENTRY_IN) { double p = HistoryDealGetDouble(ticket, DEAL_PROFIT) + HistoryDealGetDouble(ticket, DEAL_SWAP) + HistoryDealGetDouble(ticket, DEAL_COMMISSION); if(p >= 0) { plus += p; win++; } else { minus -= p; loss++; } profit -= p; } } } Print("WFO stats: in-sample profit=", (float)map[WFO_STATS_NP], " in-sample Ntrades=", map[WFO_STATS_TRADES]); Print("Custom stats: in-sample profit(check)=", (float)profit); Print("Custom stats (out-of-sample): PF=", (float)(minus > 0 ? plus / minus : 1000), " Nwin=", win, " Nloss=", loss); return profit; }
.