//+------------------------------------------------------------------+
//|                                                      k_ratio.mqh |
//|                                       Copyright 2018, KlondikeFX |
//|                                       https://www.klondikefx.com |
//|                                                      MT4 Version |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, KlondikeFX"
#property link      "https://www.klondikefx.com"


#include <orderKFX.mqh>
enum econfidence
{
   conf90 = 1645, //90%
   conf95 = 1960, //95%
   conf99 = 2576  //99%

};
enum eerror
{
   err1 = 1,   //1%
   err5 = 5,   //5%
   err10 = 10  //10%
};

sinput string samplesize_info = "";       //------------ Automatic Min Samples ------------
sinput eerror error = err10;              //Error
sinput econfidence confidence = conf90;   //Confidence  
sinput string drawdown_info = "";         //------------ Drawdown Penalty k-ratio ------------
sinput double dd_weight = .5;             //DD Penalty weight

//Cochran's Sample Size Formula
int samplesize(int population)
{
   double zscore = (double)confidence / 1000;
   double ss_numerator = (pow(zscore,2) * .25) / pow((double)error/100,2);
   double ss_denominaotr = ( 1 + (pow(zscore,2) * .25) / (pow((double)error/100,2) * population));
   return (int)ceil(ss_numerator / ss_denominaotr); //always round up
}

double penalty(double dd)
{
   return MathMax(0, 1 - (dd_weight * pow(dd, 2) / 100));
}

double OnTester()
{
   long start_time = 0;
   double balance = TesterStatistics(STAT_INITIAL_DEPOSIT); 
   double log_balance = 0;
   double k_profit[];
   
   double x_sum = 0;
   double y_sum = 0;
   
   OrderSelection* myorders = OrderWorker::GetHistory(); 
  
   ArrayResize(k_profit, 1);
   k_profit[0] = 0;    
   
   while(!myorders.End())
   {
      Order* order = myorders.Next();
      long deal_time = order.closeTime;
      
      int size = ArraySize(k_profit);
      ArrayResize(k_profit, size + 1);
      
      log_balance += log((balance  + order.profit) / balance);
      balance += order.profit;
      k_profit[size] = log_balance;
      
      x_sum += size;       
      y_sum += log_balance;    
   }

   delete(myorders);
   
   
   int bars = Bars(_Symbol,_Period,iBars(Symbol(),Period()), TimeCurrent());
   int minsample = samplesize(bars);

   if(TesterStatistics(STAT_TRADES) < minsample)
      return 0.0;

   double x_mean = x_sum / ArraySize(k_profit);
   double y_mean = y_sum / ArraySize(k_profit);
 
   double slope_numerator = 0;
   double slope_denominator = 0;
   double x_sqr = 0;
   double y_sqr = 0;
   for(int i = 0; i < ArraySize(k_profit); i ++)
   {
      slope_numerator += (i - x_mean) * (k_profit[i] - y_mean);
      slope_denominator += pow(i - x_mean, 2);
      
      y_sqr += pow(k_profit[i] - y_mean, 2); 
      x_sqr += pow(i - x_mean, 2);
   } 
   double slope = slope_numerator / slope_denominator;
   double std_err = MathSqrt( (y_sqr - (pow(slope_numerator, 2) / x_sqr)) / ((ArraySize(k_profit) - 2) * x_sqr) );
   double kratio = slope / std_err;
   double dd_penalty = penalty(TesterStatistics(STAT_EQUITY_DDREL_PERCENT));
   return kratio * dd_penalty;
}
