947 lines
67 KiB
Plaintext
947 lines
67 KiB
Plaintext
//+---------------------------------------------------------------------+
|
|
//| CTradeStatistics.mqh |
|
|
//| jafferwilson |
|
|
//| https://www.mql5.com/en/users/jafferwilson |
|
|
//+---------------------------------------------------------------------+
|
|
#property copyright "jafferwilson"
|
|
#property link "https://www.mql5.com/en/users/jafferwilson"
|
|
|
|
#define NUMBER_OF_TRY_GET_HISTORY 20
|
|
|
|
#include <Trade\DealInfo.mqh>
|
|
#include <Arrays\ArrayDouble.mqh>
|
|
enum ENUM_CALC_STATE
|
|
{
|
|
CALC_INIT,
|
|
CALC_TICK,
|
|
CALC_DEINIT
|
|
};
|
|
enum deal_result
|
|
{
|
|
NO_VALUE=0,
|
|
WIN=1,
|
|
LOSS
|
|
};
|
|
enum ENUM_STATISTICS_PLUS
|
|
{
|
|
STAT_BALANCE=10000,
|
|
STAT_EQUITY,
|
|
STAT_AHPR,
|
|
STAT_GHPR,
|
|
STAT_Z_SCORE,
|
|
STAT_LR_CORRELATION,
|
|
STAT_LR_STANDARD_ERROR,
|
|
STAT_AVG_PROFIT_TRADE,
|
|
STAT_AVG_LOSS_TRADE,
|
|
STAT_BALANCE_DD_ABSOLUTE
|
|
};
|
|
class CTradeStatistics
|
|
{
|
|
private:
|
|
CDealInfo m_deal;
|
|
CArrayDouble m_profit_data;
|
|
CArrayDouble m_balance_data;
|
|
CArrayDouble m_sharp_balance;
|
|
CArrayDouble m_balance_line;
|
|
string m_err_msg;
|
|
|
|
//---
|
|
double m_initial_deposit;
|
|
double m_withdrawal;
|
|
int m_deals;
|
|
int m_trades;
|
|
|
|
double m_profit_factor;
|
|
|
|
double m_profit;
|
|
double m_gross_profit;
|
|
double m_gross_loss;
|
|
|
|
double m_expected_payoff;
|
|
|
|
double m_balance_min;
|
|
double m_balance_dd;
|
|
double m_balance_dd_percent;
|
|
double m_balance_dd_relative;
|
|
double m_balance_dd_relative_percent;
|
|
double m_balance_dd_absolute;
|
|
//---
|
|
double m_equity_min;
|
|
double m_equity_dd;
|
|
double m_equity_dd_percent;
|
|
double m_equity_dd_relative;
|
|
double m_equity_dd_relative_percent;
|
|
double m_equity_dd_absolute;
|
|
//---
|
|
int m_short_trades;
|
|
int m_profit_short_trades;
|
|
|
|
int m_long_trades;
|
|
int m_profit_long_trades;
|
|
|
|
int m_profit_trades;
|
|
double m_profit_trades_percent;
|
|
|
|
int m_loss_trades;
|
|
double m_loss_trades_percent;
|
|
|
|
//---
|
|
int m_profit_trades_avg_con;
|
|
int m_loss_trades_avg_con;
|
|
|
|
//---
|
|
double m_larg_profit_trade;
|
|
double m_larg_loss_trade;
|
|
|
|
//---
|
|
double m_con_profit_max;
|
|
int m_con_profit_max_trades;
|
|
double m_max_con_wins;
|
|
int m_max_con_profit_trades;
|
|
|
|
double m_con_loss_max;
|
|
int m_con_loss_max_trades;
|
|
double m_max_con_losses;
|
|
int m_max_con_loss_trades;
|
|
|
|
//---
|
|
double m_recovery_factor;
|
|
double m_shape_ratio;
|
|
double m_min_margin_level;
|
|
|
|
//---
|
|
double m_z_score;
|
|
double m_z_score_percent;
|
|
|
|
double m_sharpe_ratio;
|
|
|
|
//---
|
|
double m_ghpr;
|
|
double m_ghpr_percent;
|
|
|
|
double m_ahpr;
|
|
double m_ahpr_percent;
|
|
|
|
double m_lr_correlation;
|
|
double m_lr_standard_error;
|
|
|
|
//---
|
|
int m_series_count;
|
|
int m_wins_series_count;
|
|
int m_loss_series_count;
|
|
|
|
protected:
|
|
bool CalculateRL(CArrayDouble &data,CArrayDouble &line,double &Standard_Error,double &Correlation);
|
|
void CalcEquityDrawdown(bool finally);
|
|
double CalcZScorePercent(double z_score);
|
|
|
|
public:
|
|
double InitialDeposit() {return(m_initial_deposit);}
|
|
double Withdrawal() {return(m_withdrawal);}
|
|
double Profit() {return(m_profit);};
|
|
double GrossProfit() {return(m_gross_profit);}
|
|
double GrossLoss() {return(m_gross_loss);}
|
|
//---
|
|
double LargestProfitTrade() {return(m_larg_profit_trade);}
|
|
double LargestLossTrade() {return(m_larg_loss_trade);};
|
|
double ConProfitMax() {return(m_con_profit_max);}
|
|
int ConProfitMaxTrades() {return(m_con_profit_max_trades);}
|
|
double MaxConWins() {return(m_max_con_wins);};
|
|
int MaxConProfitTrades() {return(m_max_con_profit_trades);}
|
|
double ConLossMax() {return(m_con_loss_max);}
|
|
int ConLossMaxTrades() {return(m_con_loss_max_trades);}
|
|
double MaxConLosses() {return(m_max_con_losses);}
|
|
int MaxConLossTrades() {return(m_max_con_loss_trades);}
|
|
//---
|
|
double BalanceMin() {return(m_balance_min);};
|
|
double BalanceDD() {return(m_balance_dd);};
|
|
double BalanceDDPercent() {return(m_balance_dd_percent);};
|
|
double BalanceDDRelative() {return(m_balance_dd_relative);};
|
|
double BalanceDDRelativePercent() {return(m_balance_dd_relative_percent);};
|
|
//---
|
|
double EquityMin() {return(m_equity_min);};
|
|
double EquityDD() {return(m_equity_dd);};
|
|
double EquityDDPercent() {return(m_equity_dd_percent);};
|
|
double EquityDDRelative() {return(m_equity_dd_relative);};
|
|
double EquityDDRelativePercent() {return(m_equity_dd_relative_percent);};
|
|
//---
|
|
double ExpectedPayoff() {return(m_expected_payoff);}
|
|
double ProfitFactor() {return(m_profit_factor);}
|
|
double RecoveryFactor() {return(m_recovery_factor);}
|
|
double SharpeRatio() {return(m_sharpe_ratio);}
|
|
double MinMarginLevel() {return(m_min_margin_level);}
|
|
//---
|
|
int Deals() {return(m_deals);}
|
|
int Trades() {return(m_trades);}
|
|
int ProfitTrades() {return(m_profit_trades);};
|
|
int LossTrades() {return(m_loss_trades);};
|
|
int ShortTrades() {return(m_short_trades);};
|
|
int LongTrades() {return(m_long_trades);};
|
|
//---
|
|
int ProfitShortTrades() {return(m_profit_short_trades);}
|
|
int ProfitLongTrades() {return(m_profit_long_trades);}
|
|
//---
|
|
int ProfitTradesAvgCon() {return(m_profit_trades_avg_con);}
|
|
int LossTradesAvgCon() {return(m_loss_trades_avg_con);}
|
|
|
|
double AHPR() {return(m_ahpr);}
|
|
double AHPRPercent() {return(m_ahpr_percent);}
|
|
|
|
double GHPR() {return(m_ghpr);}
|
|
double GHPRPercent() {return(m_ghpr_percent);}
|
|
|
|
double ZScore() {return(m_z_score);}
|
|
double ZScorePercent() {return(m_z_score_percent);}
|
|
|
|
double LRCorrelation() {return(m_lr_correlation);}
|
|
double LRStandardError() {return(m_lr_standard_error);}
|
|
|
|
bool Calculate(datetime time_start,datetime time_end,double initial_deposit);
|
|
void PrintStatistics();
|
|
string GetLastErrorString() {return(m_err_msg);};
|
|
bool CalculateEquityDD(ENUM_CALC_STATE state);
|
|
double Percent(double value,double divider);
|
|
double Divide(double value,double divider);
|
|
};
|
|
double CTradeStatistics::Percent(double value,double divider)
|
|
{
|
|
if(MathAbs(value)<=FLT_EPSILON)
|
|
return(0);
|
|
return(100*value/divider);
|
|
}
|
|
double CTradeStatistics::Divide(double value,double divider)
|
|
{
|
|
if(MathAbs(value)<=FLT_EPSILON)
|
|
return(0);
|
|
return(value/divider);
|
|
}
|
|
bool CTradeStatistics::Calculate(datetime time_start=0,datetime time_end=0,double initial_deposit=0.0)
|
|
{
|
|
m_err_msg="";
|
|
if(time_end==0)
|
|
time_end=TimeTradeServer();
|
|
m_initial_deposit=initial_deposit;
|
|
|
|
m_withdrawal=0;
|
|
m_profit=0;
|
|
m_gross_profit=0;
|
|
m_gross_loss=0;
|
|
|
|
m_short_trades=0;
|
|
m_larg_profit_trade=0;
|
|
m_long_trades=0;
|
|
m_larg_loss_trade=0;
|
|
m_profit_short_trades=0;
|
|
m_profit_long_trades=0;
|
|
m_larg_profit_trade=0;
|
|
m_larg_loss_trade=0;
|
|
|
|
m_con_profit_max=0;
|
|
m_con_profit_max_trades=0;
|
|
m_con_loss_max=0;
|
|
m_con_loss_max_trades=0;
|
|
m_max_con_losses=0;
|
|
m_max_con_loss_trades=0;
|
|
m_balance_min=0.0;
|
|
m_balance_dd_absolute=0;
|
|
m_balance_dd=0;
|
|
m_balance_dd_percent=0;
|
|
m_balance_dd_relative=0;
|
|
m_balance_dd_relative_percent=0;
|
|
|
|
m_expected_payoff=0;
|
|
m_profit_factor=0;
|
|
m_recovery_factor=0;
|
|
m_sharpe_ratio=0;
|
|
|
|
m_deals=0;
|
|
m_trades=0;
|
|
m_profit_trades=0;
|
|
m_loss_trades=0;
|
|
m_short_trades=0;
|
|
m_long_trades=0;
|
|
|
|
m_series_count=0;
|
|
m_wins_series_count=0;
|
|
m_loss_series_count=0;
|
|
m_profit_trades_avg_con=0;
|
|
m_loss_trades_avg_con=0;
|
|
|
|
double min_peak = 0.0;
|
|
double max_peak = 0.0;
|
|
|
|
double balance=0,sharp_balance=0;
|
|
double profit=0;
|
|
|
|
double sequential=0.0;
|
|
int profit_length=0, loss_length=0;
|
|
|
|
deal_result result=NO_VALUE;
|
|
|
|
m_balance_data.Clear();
|
|
m_profit_data.Clear();
|
|
m_sharp_balance.Clear();
|
|
|
|
int try_=0;
|
|
bool res=HistorySelect(time_start,time_end);
|
|
if(!res && try_<NUMBER_OF_TRY_GET_HISTORY)
|
|
{
|
|
Sleep(100);
|
|
res=HistorySelect(time_start,time_end);
|
|
try_++;
|
|
}
|
|
if(!res)
|
|
{
|
|
m_err_msg="Unable to get the trade history";
|
|
return(false);
|
|
}
|
|
|
|
int deals_total=HistoryDealsTotal();
|
|
for(int i=0; i<deals_total; i++)
|
|
{
|
|
if(!m_deal.SelectByIndex(i))
|
|
{
|
|
m_err_msg="Error function SelectByIndex()";
|
|
return(false);
|
|
}
|
|
|
|
if(m_deal.DealType()==DEAL_TYPE_BALANCE)
|
|
{
|
|
//--- current balance
|
|
profit=NormalizeDouble(m_deal.Profit()+m_deal.Swap(),2);
|
|
balance+=profit;
|
|
m_balance_data.Add(balance);
|
|
|
|
if(min_peak == 0.0)
|
|
min_peak = balance;
|
|
else
|
|
min_peak+=profit;
|
|
if(max_peak == 0.0)
|
|
max_peak = balance;
|
|
else
|
|
max_peak+=profit;
|
|
if(profit>=0.0)
|
|
{
|
|
if(m_balance_min==0.0)
|
|
m_balance_min=balance;
|
|
else
|
|
m_balance_min+=profit;
|
|
result = WIN;
|
|
if(initial_deposit==0.0)
|
|
if(m_initial_deposit==0.0)
|
|
{
|
|
m_initial_deposit=m_deal.Profit();
|
|
sharp_balance += profit;
|
|
m_sharp_balance.Add(sharp_balance);
|
|
}
|
|
else
|
|
m_initial_deposit+=m_deal.Profit();
|
|
}
|
|
else
|
|
{
|
|
m_withdrawal-=m_deal.Profit();
|
|
result=LOSS;
|
|
}
|
|
|
|
}
|
|
|
|
if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
|
|
{
|
|
m_deals++;
|
|
profit=NormalizeDouble(m_deal.Profit()+m_deal.Swap()+m_deal.Commission(),2);
|
|
m_profit_data.Add(profit);
|
|
if(profit>=0.0)
|
|
{
|
|
m_gross_profit+=profit;
|
|
}
|
|
else
|
|
{
|
|
m_gross_loss+=profit;
|
|
}
|
|
balance=balance+profit;
|
|
m_balance_data.Add(balance);
|
|
|
|
if(balance<m_balance_min)
|
|
m_balance_min=balance;
|
|
|
|
if(min_peak == 0.0)
|
|
min_peak = balance;
|
|
if(max_peak == 0.0)
|
|
max_peak = balance;
|
|
double drawdown=max_peak-balance;
|
|
double drawdown_percent=drawdown/max_peak*100.0;
|
|
|
|
//--- price dd maximum
|
|
if(drawdown>m_balance_dd)
|
|
{
|
|
m_balance_dd=drawdown;
|
|
m_balance_dd_percent=drawdown_percent;
|
|
}
|
|
|
|
if(drawdown_percent>m_balance_dd_relative_percent)
|
|
{
|
|
m_balance_dd_relative_percent=drawdown_percent;
|
|
m_balance_dd_relative=drawdown;
|
|
}
|
|
|
|
if(max_peak<balance)
|
|
max_peak=balance;
|
|
if(m_deal.Entry()==DEAL_ENTRY_OUT || m_deal.Entry()==DEAL_ENTRY_INOUT)
|
|
{
|
|
sharp_balance += profit;
|
|
m_sharp_balance.Add(sharp_balance);
|
|
m_trades++;
|
|
|
|
if(profit>=0.0)
|
|
m_profit_trades++;
|
|
|
|
if(profit<0)
|
|
m_loss_trades++;
|
|
if(profit>=0.0)
|
|
{
|
|
if(profit>m_larg_profit_trade)
|
|
m_larg_profit_trade=profit;
|
|
|
|
if(result!=WIN)
|
|
{
|
|
result=WIN;
|
|
m_series_count++;
|
|
m_wins_series_count++;
|
|
profit_length=0;
|
|
sequential=0.0;
|
|
}
|
|
|
|
sequential+=profit;
|
|
profit_length++;
|
|
//---
|
|
if(m_max_con_profit_trades<profit_length)
|
|
{
|
|
m_max_con_profit_trades=profit_length;
|
|
m_max_con_wins=sequential;
|
|
}
|
|
//---
|
|
if(m_con_profit_max<sequential)
|
|
{
|
|
m_con_profit_max = sequential;
|
|
m_con_profit_max_trades = profit_length;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(profit<m_larg_loss_trade)
|
|
m_larg_loss_trade=profit;
|
|
|
|
|
|
if(result!=LOSS)
|
|
{
|
|
result=LOSS;
|
|
m_series_count++;
|
|
m_loss_series_count++;
|
|
loss_length=0;
|
|
sequential=0.0;
|
|
}
|
|
|
|
sequential+=profit;
|
|
loss_length++;
|
|
if(m_max_con_loss_trades<loss_length)
|
|
{
|
|
m_max_con_loss_trades=loss_length;
|
|
m_max_con_losses=sequential;
|
|
}
|
|
if(m_con_loss_max>sequential)
|
|
{
|
|
m_con_loss_max=sequential;
|
|
m_con_loss_max_trades=loss_length;
|
|
}
|
|
}
|
|
|
|
if(m_deal.DealType()==DEAL_TYPE_SELL)
|
|
{
|
|
if(profit>=0.0)
|
|
m_profit_long_trades++;
|
|
m_long_trades++;
|
|
}
|
|
|
|
if(m_deal.DealType()==DEAL_TYPE_BUY)
|
|
{
|
|
if(profit>=0.0)
|
|
m_profit_short_trades++;
|
|
m_short_trades++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| AHPR, GHPR, Sharpe_Ratio |
|
|
//+------------------------------------------------------------------+
|
|
m_ahpr=0;
|
|
m_ahpr_percent=0;
|
|
|
|
m_ghpr=0;
|
|
m_ghpr_percent=0;
|
|
|
|
//---
|
|
int limit=m_sharp_balance.Total();
|
|
if(limit>1)
|
|
{
|
|
double hpr=0;
|
|
double hpr2=0;
|
|
|
|
double HPR[];
|
|
ArrayResize(HPR,limit-1);
|
|
for(int i=1; i<limit; i++)
|
|
{
|
|
if(m_sharp_balance.At(i)!=0.0)
|
|
{
|
|
HPR[i-1]=m_sharp_balance.At(i)/m_sharp_balance.At(i-1);
|
|
m_ahpr+=HPR[i-1];
|
|
}
|
|
}
|
|
m_ahpr=m_ahpr/(limit-1);
|
|
m_ahpr_percent=(m_ahpr-1)*100;
|
|
|
|
m_ghpr=MathPow(m_sharp_balance.At(limit-1)/m_initial_deposit,1.0/(limit-1));
|
|
m_ghpr_percent=(m_ghpr-1)*100;
|
|
|
|
//--- Sharpe_Ratio
|
|
m_sharpe_ratio=0;
|
|
if(limit>2)
|
|
{
|
|
double Std=0.0;
|
|
double RiskFreeRate=0.0;
|
|
for(int i=0; i<limit-2; i++)
|
|
{
|
|
Std+=(m_ahpr-HPR[i])*(m_ahpr-HPR[i]);
|
|
}
|
|
Std=MathPow(Std/(limit-2),0.5);
|
|
|
|
m_sharpe_ratio=(m_ahpr -(1.0+RiskFreeRate))/Std;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Z-Score |
|
|
//+------------------------------------------------------------------+
|
|
m_z_score=0.0;
|
|
m_z_score_percent=0.0;
|
|
long N=m_profit_data.Total();
|
|
|
|
if(N>2)
|
|
{
|
|
long W = 0;
|
|
long L = 0;
|
|
long R = 0;
|
|
deal_result outcome=NO_VALUE;
|
|
|
|
for(int i=0; i<N; i++)
|
|
{
|
|
if(m_profit_data.At(i)>=0.0)
|
|
{
|
|
if(outcome!=WIN)
|
|
{
|
|
outcome=WIN;
|
|
R++;
|
|
}
|
|
W++;
|
|
}
|
|
else
|
|
{
|
|
if(outcome!=LOSS)
|
|
{
|
|
outcome=LOSS;
|
|
R++;
|
|
}
|
|
L++;
|
|
}
|
|
}
|
|
double P=2.0*W*L;
|
|
|
|
//--- check for division by zero
|
|
if(MathAbs(MathSqrt((P*(P-N))/(N-1))) >= FLT_EPSILON)
|
|
{
|
|
m_z_score=(N*(R-0.5)-P)/MathSqrt((P*(P-N))/(N-1));
|
|
m_z_score_percent=CalcZScorePercent(m_z_score)*100;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Other |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//--- Total_Net_Profit
|
|
m_profit=m_gross_profit+m_gross_loss;
|
|
|
|
//--- Profit Factor
|
|
m_profit_factor=0.0;
|
|
if(MathAbs(m_gross_loss)>FLT_EPSILON)
|
|
m_profit_factor=MathAbs(m_gross_profit/m_gross_loss);
|
|
|
|
//---
|
|
m_profit_trades_percent=0;
|
|
m_loss_trades_percent=0;
|
|
m_expected_payoff=0;
|
|
if(m_trades>0)
|
|
{
|
|
m_expected_payoff=m_profit/m_trades;
|
|
m_profit_trades_percent = (double)m_profit_trades/m_trades*100;
|
|
m_loss_trades_percent = (double)m_loss_trades/m_trades*100;
|
|
}
|
|
|
|
m_profit_trades_avg_con=0;
|
|
if(m_wins_series_count>0)
|
|
m_profit_trades_avg_con=(int)MathRound((double)m_profit_trades/m_wins_series_count);
|
|
|
|
m_loss_trades_avg_con=0;
|
|
if(m_loss_series_count>0)
|
|
m_loss_trades_avg_con=(int)MathRound((double)m_loss_trades/m_loss_series_count);
|
|
|
|
if(MathAbs(m_balance_dd)>FLT_EPSILON)
|
|
m_recovery_factor=m_profit/m_balance_dd;
|
|
|
|
CalculateRL(m_balance_data,m_balance_line,m_lr_standard_error,m_lr_correlation);
|
|
|
|
return(true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Laplas array |
|
|
//+------------------------------------------------------------------+
|
|
const double Laplas[][2]=
|
|
{
|
|
{0.00,0.00000},{0.01,0.00798},{0.02,0.01596},{0.03,0.02393},{0.04,0.03191},{0.05,0.03988},
|
|
{0.06,0.04784},{0.07,0.05581},{0.08,0.06376},{0.09,0.07171},{0.10,0.07966},{0.11,0.08759},
|
|
{0.12,0.09552},{0.13,0.10348},{0.14,0.11134},{0.15,0.11924},{0.16,0.12712},{0.17,0.13499},
|
|
{0.18,0.14285},{0.19,0.15069},{0.20,0.15852},{0.21,0.16633},{0.22,0.17413},{0.23,0.18191},
|
|
{0.24,0.18967},{0.25,0.19741},{0.26,0.20514},{0.27,0.21284},{0.28,0.22052},{0.29,0.22818},
|
|
{0.30,0.23582},{0.31,0.24344},{0.32,0.25103},{0.33,0.25860},{0.34,0.26614},{0.35,0.27366},
|
|
{0.36,0.28115},{0.37,0.28862},{0.38,0.29605},{0.39,0.30346},{0.40,0.31084},{0.41,0.31819},
|
|
{0.42,0.32552},{0.43,0.33280},{0.44,0.34006},{0.45,0.34729},{0.46,0.35448},{0.47,0.36164},
|
|
{0.48,0.36877},{0.49,0.37587},{0.50,0.38292},{0.51,0.38995},{0.52,0.39694},{0.53,0.40389},
|
|
{0.54,0.41080},{0.55,0.41768},{0.56,0.42452},{0.57,0.43132},{0.58,0.43809},{0.59,0.44481},
|
|
{0.60,0.45149},{0.61,0.45814},{0.62,0.46474},{0.63,0.47131},{0.64,0.47783},{0.65,0.48431},
|
|
{0.66,0.49075},{0.67,0.49714},{0.68,0.50350},{0.69,0.50981},{0.70,0.51607},{0.71,0.52230},
|
|
{0.72,0.52848},{0.73,0.53461},{0.74,0.54070},{0.75,0.54675},{0.76,0.55275},{0.77,0.55870},
|
|
{0.78,0.56461},{0.79,0.57047},{0.80,0.57629},{0.81,0.58206},{0.82,0.58778},{0.83,0.59346},
|
|
{0.84,0.59909},{0.85,0.60468},{0.86,0.61021},{0.87,0.61570},{0.88,0.62114},{0.89,0.62653},
|
|
{0.90,0.63188},{0.91,0.63718},{0.92,0.64243},{0.93,0.64763},{0.94,0.65278},{0.95,0.65789},
|
|
{0.96,0.66294},{0.97,0.66795},{0.98,0.67291},{0.99,0.67783},{1.00,0.68269},{1.01,0.68750},
|
|
{1.02,0.69227},{1.03,0.69699},{1.04,0.70166},{1.05,0.70628},{1.06,0.71086},{1.07,0.71538},
|
|
{1.08,0.71986},{1.09,0.72429},{1.10,0.72867},{1.11,0.73300},{1.12,0.73729},{1.13,0.74152},
|
|
{1.14,0.74571},{1.15,0.74986},{1.16,0.75395},{1.17,0.75800},{1.18,0.76200},{1.19,0.76595},
|
|
{1.20,0.76986},{1.21,0.77372},{1.22,0.77754},{1.23,0.78130},{1.24,0.78502},{1.25,0.78870},
|
|
{1.26,0.79233},{1.27,0.79592},{1.28,0.79945},{1.29,0.80295},{1.30,0.80640},{1.31,0.80980},
|
|
{1.32,0.81316},{1.33,0.81648},{1.34,0.81975},{1.35,0.82298},{1.36,0.82617},{1.37,0.82931},
|
|
{1.38,0.83241},{1.39,0.83547},{1.40,0.83849},{1.41,0.84146},{1.42,0.84439},{1.43,0.84728},
|
|
{1.44,0.85013},{1.45,0.85294},{1.46,0.85571},{1.47,0.85844},{1.48,0.86113},{1.49,0.86378},
|
|
{1.50,0.86639},{1.51,0.86696},{1.52,0.87149},{1.53,0.87398},{1.54,0.87644},{1.55,0.87886},
|
|
{1.56,0.88124},{1.57,0.88358},{1.58,0.88589},{1.59,0.88817},{1.60,0.89040},{1.61,0.89260},
|
|
{1.62,0.89477},{1.63,0.89690},{1.64,0.89899},{1.65,0.90106},{1.66,0.90309},{1.67,0.90508},
|
|
{1.68,0.90704},{1.69,0.90897},{1.70,0.91087},{1.71,0.91273},{1.72,0.91457},{1.73,0.91637},
|
|
{1.74,0.91814},{1.75,0.91988},{1.76,0.92159},{1.77,0.92327},{1.78,0.92492},{1.79,0.92655},
|
|
{1.80,0.92814},{1.81,0.92970},{1.82,0.93124},{1.83,0.93275},{1.84,0.93423},{1.85,0.93569},
|
|
{1.86,0.93711},{1.87,0.93852},{1.88,0.93989},{1.89,0.94124},{1.90,0.94257},{1.91,0.94387},
|
|
{1.92,0.94514},{1.93,0.94639},{1.94,0.94762},{1.95,0.94882},{1.96,0.95000},{1.97,0.95116},
|
|
{1.98,0.95230},{1.99,0.95341},{2.00,0.95450},{2.01,0.95557},{2.02,0.95662},{2.03,0.95764},
|
|
{2.04,0.95865},{2.05,0.95964},{2.06,0.96060},{2.07,0.96155},{2.08,0.96247},{2.09,0.96338},
|
|
{2.10,0.96427},{2.11,0.96514},{2.12,0.96599},{2.13,0.96683},{2.14,0.96765},{2.15,0.96844},
|
|
{2.16,0.96923},{2.17,0.96999},{2.18,0.97074},{2.19,0.97148},{2.20,0.97219},{2.21,0.97289},
|
|
{2.22,0.97358},{2.23,0.97425},{2.24,0.97491},{2.25,0.97555},{2.26,0.97618},{2.27,0.97679},
|
|
{2.28,0.97739},{2.29,0.97798},{2.30,0.97855},{2.31,0.97911},{2.32,0.97966},{2.33,0.98019},
|
|
{2.34,0.98072},{2.35,0.98123},{2.36,0.98172},{2.37,0.98221},{2.38,0.98269},{2.39,0.98315},
|
|
{2.40,0.98360},{2.41,0.98405},{2.42,0.98448},{2.43,0.98490},{2.44,0.98531},{2.45,0.98571},
|
|
{2.46,0.98611},{2.47,0.98649},{2.48,0.98686},{2.49,0.98723},{2.50,0.98758},{2.51,0.98793},
|
|
{2.52,0.98826},{2.53,0.98859},{2.54,0.98891},{2.55,0.98923},{2.56,0.98953},{2.57,0.98983},
|
|
{2.58,0.99012},{2.59,0.99040},{2.60,0.99068},{2.61,0.99095},{2.62,0.99121},{2.63,0.99146},
|
|
{2.64,0.99171},{2.65,0.99195},{2.66,0.99219},{2.67,0.99241},{2.68,0.99263},{2.69,0.99285},
|
|
{2.70,0.99307},{2.71,0.99327},{2.72,0.99347},{2.73,0.99367},{2.74,0.99386},{2.75,0.99404},
|
|
{2.76,0.99422},{2.77,0.99439},{2.78,0.99456},{2.79,0.99473},{2.80,0.99489},{2.81,0.99505},
|
|
{2.82,0.99520},{2.83,0.99535},{2.84,0.99549},{2.85,0.99563},{2.86,0.99576},{2.87,0.99590},
|
|
{2.88,0.99602},{2.89,0.99615},{2.90,0.99627},{2.91,0.99639},{2.92,0.99650},{2.93,0.99661},
|
|
{2.94,0.99672},{2.95,0.99682},{2.96,0.99692},{2.97,0.99702},{2.98,0.99712},{2.99,0.99721},
|
|
{3.00,0.99730},{3.01,0.99739}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| CalcZScorePercent |
|
|
//+------------------------------------------------------------------+
|
|
double CTradeStatistics::CalcZScorePercent(double z_score)
|
|
{
|
|
int total=ArrayRange(Laplas,0);
|
|
double value=NormalizeDouble(MathAbs(z_score),2);
|
|
|
|
if(value>Laplas[total-2][0])
|
|
return(Laplas[total-1][1]);
|
|
|
|
for(int i=0; i<total; i++)
|
|
if(Laplas[i][0]==value)
|
|
return(Laplas[i][1]);
|
|
|
|
return(0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| PrintStatistics |
|
|
//+------------------------------------------------------------------+
|
|
void CTradeStatistics::PrintStatistics()
|
|
{
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_INITIAL_DEPOSIT),TesterStatistics(STAT_INITIAL_DEPOSIT),InitialDeposit());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_WITHDRAWAL),TesterStatistics(STAT_WITHDRAWAL),Withdrawal());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_PROFIT),TesterStatistics(STAT_PROFIT),Profit());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_GROSS_PROFIT),TesterStatistics(STAT_GROSS_PROFIT),GrossProfit());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_GROSS_LOSS),TesterStatistics(STAT_GROSS_LOSS),GrossLoss());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_MAX_PROFITTRADE),TesterStatistics(STAT_MAX_PROFITTRADE),LargestProfitTrade());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_MAX_LOSSTRADE),TesterStatistics(STAT_MAX_LOSSTRADE),LargestLossTrade());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_CONPROFITMAX),TesterStatistics(STAT_CONPROFITMAX),ConProfitMax());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_CONPROFITMAX_TRADES),TesterStatistics(STAT_CONPROFITMAX_TRADES),ConProfitMaxTrades());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_MAX_CONWINS),TesterStatistics(STAT_MAX_CONWINS),MaxConWins());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_MAX_CONPROFIT_TRADES),TesterStatistics(STAT_MAX_CONPROFIT_TRADES),MaxConProfitTrades());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_CONLOSSMAX),TesterStatistics(STAT_CONLOSSMAX),ConLossMax());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_CONLOSSMAX_TRADES),TesterStatistics(STAT_CONLOSSMAX_TRADES),ConLossMaxTrades());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_MAX_CONLOSSES),TesterStatistics(STAT_MAX_CONLOSSES),MaxConLosses());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_MAX_CONLOSS_TRADES),TesterStatistics(STAT_MAX_CONLOSS_TRADES),MaxConLossTrades());
|
|
|
|
//--- Balance
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_BALANCEMIN),TesterStatistics(STAT_BALANCEMIN),BalanceMin());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_BALANCE_DD),TesterStatistics(STAT_BALANCE_DD),BalanceDD());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_BALANCEDD_PERCENT),TesterStatistics(STAT_BALANCEDD_PERCENT),BalanceDDPercent());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_BALANCE_DD_RELATIVE),TesterStatistics(STAT_BALANCE_DD_RELATIVE),BalanceDDRelative());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_BALANCE_DDREL_PERCENT),TesterStatistics(STAT_BALANCE_DDREL_PERCENT),BalanceDDRelativePercent());
|
|
|
|
//--- Equity
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EQUITYMIN),TesterStatistics(STAT_EQUITYMIN),EquityMin());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EQUITY_DD),TesterStatistics(STAT_EQUITY_DD),EquityDD());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EQUITYDD_PERCENT),TesterStatistics(STAT_EQUITYDD_PERCENT),EquityDDPercent());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EQUITY_DD_RELATIVE),TesterStatistics(STAT_EQUITY_DD_RELATIVE),EquityDDRelative());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EQUITY_DDREL_PERCENT),TesterStatistics(STAT_EQUITY_DDREL_PERCENT),EquityDDRelativePercent());
|
|
|
|
/*
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(ACCOUNT_BALANCE),AccountInfoDouble(ACCOUNT_BALANCE),Balance);
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(ACCOUNT_PROFIT),AccountInfoDouble(ACCOUNT_PROFIT),Profit);
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(ACCOUNT_EQUITY),AccountInfoDouble(ACCOUNT_EQUITY),Equity);
|
|
*/
|
|
|
|
//---
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_EXPECTED_PAYOFF),TesterStatistics(STAT_EXPECTED_PAYOFF),ExpectedPayoff());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_PROFIT_FACTOR),TesterStatistics(STAT_PROFIT_FACTOR),ProfitFactor());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_RECOVERY_FACTOR),TesterStatistics(STAT_RECOVERY_FACTOR),RecoveryFactor());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_SHARPE_RATIO),TesterStatistics(STAT_SHARPE_RATIO),SharpeRatio());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_MIN_MARGINLEVEL),TesterStatistics(STAT_MIN_MARGINLEVEL),MinMarginLevel());
|
|
|
|
// PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_CUSTOM_ONTESTER),TesterStatistics(STAT_CUSTOM_ONTESTER),CustomOnTester());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_DEALS),TesterStatistics(STAT_DEALS),Deals());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_TRADES),TesterStatistics(STAT_TRADES),Trades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_PROFIT_TRADES),TesterStatistics(STAT_PROFIT_TRADES),ProfitTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_LOSS_TRADES),TesterStatistics(STAT_LOSS_TRADES),LossTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_SHORT_TRADES),TesterStatistics(STAT_SHORT_TRADES),ShortTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_LONG_TRADES),TesterStatistics(STAT_LONG_TRADES),LongTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_PROFIT_SHORTTRADES),TesterStatistics(STAT_PROFIT_SHORTTRADES),ProfitShortTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_PROFIT_LONGTRADES),TesterStatistics(STAT_PROFIT_LONGTRADES),ProfitLongTrades());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_PROFITTRADES_AVGCON),TesterStatistics(STAT_PROFITTRADES_AVGCON),ProfitTradesAvgCon());
|
|
|
|
PrintFormat("%s: %.0f - %.0f",EnumToString(STAT_LOSSTRADES_AVGCON),TesterStatistics(STAT_LOSSTRADES_AVGCON),LossTradesAvgCon());
|
|
|
|
//--- GHPR
|
|
PrintFormat("%s: %.4f(%.2f) - %.4f(%.2f)",EnumToString(STAT_GHPR),0,0,GHPR(),GHPRPercent());
|
|
|
|
//--- AHPR
|
|
PrintFormat("%s: %.4f(%.2f) - %.4f(%.2f)",EnumToString(STAT_AHPR),0,0,AHPR(),AHPRPercent());
|
|
|
|
//--- Z SCORE
|
|
PrintFormat("%s: %.2f(%.2f) - %.2f(%.2f)",EnumToString(STAT_Z_SCORE),0,0,ZScore(),ZScorePercent());
|
|
|
|
//--- LR
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_LR_CORRELATION),0,LRCorrelation());
|
|
|
|
PrintFormat("%s: %.2f - %.2f",EnumToString(STAT_LR_STANDARD_ERROR),0,LRStandardError());
|
|
|
|
}
|
|
bool CTradeStatistics::CalculateEquityDD(ENUM_CALC_STATE state)
|
|
{
|
|
switch(state)
|
|
{
|
|
case CALC_INIT:
|
|
m_equity_min=AccountInfoDouble(ACCOUNT_EQUITY);
|
|
m_equity_dd=0.0;
|
|
m_equity_dd_percent=0.0;
|
|
m_equity_dd_relative=0.0;
|
|
m_equity_dd_relative_percent=0.0;
|
|
m_min_margin_level=AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
|
|
break;
|
|
|
|
case CALC_TICK:
|
|
CalcEquityDrawdown(false);
|
|
break;
|
|
|
|
case CALC_DEINIT:
|
|
CalcEquityDrawdown(true);
|
|
break;
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| CalcEquityDrawdown |
|
|
//+------------------------------------------------------------------+
|
|
void CTradeStatistics::CalcEquityDrawdown(bool finally)
|
|
{
|
|
|
|
static double maxpeak = 0.0;
|
|
static double minpeak = 0.0;
|
|
|
|
double equity=AccountInfoDouble(ACCOUNT_EQUITY);
|
|
if(equity<m_equity_min)
|
|
m_equity_min=equity;
|
|
|
|
if(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)<m_min_margin_level)
|
|
m_min_margin_level=AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
|
|
|
|
if(maxpeak == 0.0)
|
|
maxpeak = equity;
|
|
if(minpeak == 0.0)
|
|
minpeak = equity;
|
|
|
|
if((maxpeak<equity) || (finally))
|
|
{
|
|
double drawdown=maxpeak-minpeak;
|
|
double drawdown_percent=drawdown/maxpeak*100.0;
|
|
|
|
if(m_equity_dd_relative_percent<drawdown_percent)
|
|
{
|
|
m_equity_dd_relative_percent=drawdown_percent;
|
|
m_equity_dd_relative=drawdown;
|
|
}
|
|
|
|
if(m_equity_dd<drawdown)
|
|
{
|
|
m_equity_dd=drawdown;
|
|
m_equity_dd_percent=drawdown_percent;
|
|
}
|
|
|
|
maxpeak = equity;
|
|
minpeak = equity;
|
|
}
|
|
|
|
if(minpeak>equity)
|
|
minpeak=equity;
|
|
}
|
|
bool CTradeStatistics::CalculateRL(CArrayDouble &data,CArrayDouble &line,double &Standard_Error,double &Correlation)
|
|
{
|
|
int total=data.Total();
|
|
if(total<=2)
|
|
return(true);
|
|
|
|
double s1=0;
|
|
double s2=0;
|
|
double a1=0;
|
|
double a2=0;
|
|
double b1=0;
|
|
double b2= total;
|
|
|
|
for(int i=1; i<=total; i++)
|
|
{
|
|
s1 = s1 + data.At(i-1)*i;
|
|
s2 = s2 + data.At(i-1);
|
|
a1 = a1+i*i;
|
|
a2 = a2+i;
|
|
}
|
|
|
|
b1=a2;
|
|
|
|
double dif = a1*b2-a2*b1;
|
|
double A = (s1*b2-s2*b1) / dif;
|
|
double B = (a1*s2-a2*s1) / dif;
|
|
|
|
int sign=1;
|
|
if(A<0.0)
|
|
sign=-1;
|
|
|
|
line.Clear();
|
|
string str="";
|
|
for(int i = 1; i<=total; i++)
|
|
{
|
|
str=str+StringFormat("| %i %.2f",i,A*i+B);
|
|
line.Add(A*i+B);
|
|
}
|
|
|
|
Standard_Error=0;
|
|
double sum=0;
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
|
|
double delta=MathAbs(data.At(i)-line.At(i));
|
|
sum=sum+delta*delta;
|
|
//PrintFormat("B=%.2f L=%.2f D=%.2f",m_balance_data.At(i),BalanceLine.At(i),delta);
|
|
}
|
|
Standard_Error=MathSqrt(sum/(total-2));
|
|
|
|
|
|
//--- LR Correlation
|
|
double avg_balance=0;
|
|
double avg_line=0;
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
avg_balance=avg_balance+data.At(i);
|
|
avg_line=avg_line+line.At(i);
|
|
}
|
|
|
|
avg_balance = avg_balance / total;
|
|
avg_line = avg_line / total;
|
|
|
|
|
|
double cov=0;
|
|
double Sx=0;
|
|
double Sy=0;
|
|
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
cov = cov +(data.At(i)-avg_balance) *(line.At(i)-avg_line);
|
|
Sx = Sx + MathPow(data.At(i) - avg_balance, 2);
|
|
Sy = Sy + MathPow(line.At(i) - avg_line, 2);
|
|
}
|
|
cov = (cov / total);
|
|
Sx = MathSqrt(Sx / total);
|
|
Sy = MathSqrt(Sy / total);
|
|
|
|
Correlation=sign*cov/(Sx*Sy);
|
|
|
|
return(false);
|
|
}
|