Optimizing sortino ratio in OnTester() using genetic algorithms? - page 2

To add comments, please log in or register
QuantCoder
82
QuantCoder  
alphatrading:

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...

Wow! Thank you so so so much for your quality post and time. You have by far provided the most quality and information to me than any other member on this forum and this is not an exaggeration. I wish there were people like you here. Thank you for helping out a fellow quant.
@alphatrading

Anyway, the code you returned gives me a few errors that I cant seem to fix. Maybe they will pop up for you if you compile your code. This is what I have so far:

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);
}

double OnTester()
{
  CalculateRatios();
  return sortino;
}

Im 100% sure I have the last bit wrong but feel free to correct me, however, the problems are 

'n' - undeclared identifier


'sortino' - undeclared identifier


and 


'values' - arrays are passed by reference only
'values' - arrays are passed by reference only
'values' - arrays are passed by reference only
alphatrading
94
alphatrading  
QuantCoder:..Anyway, the code you returned gives me a few errors that I cant seem to fix. Maybe they will pop up for you if you compile your code. This is what I have so far:

 Im 100% sure I have the last bit wrong but feel free to correct me, however, the problems are...

I forgot to compile with "#property strict". Fixed. And I changed the calculation of the standard deviation from the full population to a sample.

double OnTester() {
   int trades=0, orders = OrdersHistoryTotal();
   double totalPips=0, 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=0, sharpe=0, sortino=0;
   if (trades > 0) {
      avgPips = totalPips/trades;
      sharpe  = CalculateSharpeRatio(pips, totalPips);
      sortino = CalculateSortinoRatio(pips, totalPips);
   }
   Print("trades=", trades, "  totalPips=", DoubleToStr(totalPips, 1), "  avgPips=", DoubleToStr(avgPips, 2), "  sharpe="+ DoubleToStr(sharpe, 4), "  sortino=", DoubleToStr(sortino, 4));
   return(sortino);
}


/**
 *
 */
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 n=0, size = ArraySize(values);
   if (!size) return(NULL);

   double losses[];
   ArrayResize(losses, size);

   for (int i=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 < 2) {
      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 = 0;
   for (int i=0; i < size; i++) {
      sum += MathPow((values[i] - mean), 2);
   }
   double stdDev = MathSqrt(sum / (size-1));
   return(stdDev);
}
Arthur Albano
610
Arthur Albano  
alphatrading:

The 1 is caused by this part:

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:

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

If I am not wrong, the distance between one point to the average or other reference is called "location".
Location parameter - Wikipedia
Location parameter - Wikipedia
  • en.wikipedia.org
f x 0 ( x ) = f ( x − x 0 ) . {\displaystyle f_{x_{0}}(x)=f(x-x_{0}).} [ ] Here, is called the location parameter. Examples of location parameters include the mean, the median, and the mode. Thus in the one-dimensional case if is increased, the probability density or mass function shifts rigidly to the right, maintaining its exact...
Arthur Albano
610
Arthur Albano  

I decided to study more on Sortino. And I wrote a code to calculate deal by deal, but the core calculation is done by this:

   double sum    = 0.0; // Simple sum
   double sumTDD = 0.0; // Target Downside Deviation
   double sumTUD = 0.0; // Target Upside Deviation
   for(int l=0;l<ArraySize(Results);l++)
     {
      sum = sum + Results[l];
      sumTDD = sumTDD + MathPow(MathMin(0,Results[l]),2);
      sumTUD = sumTUD + MathPow(MathMax(0,Results[l]),2);
     }
      
   double average = sum / (1.0*ArraySize(Results));
   
   double variance = 0.0;

   for(int l=0;l<ArraySize(Results);l++)
     {
      variance = variance + pow(Results[l]-average,2);
     }
     
   variance = variance / (1.0*ArraySize(Results));
   
   double StdDev = MathSqrt(variance);                  // Standard Deviation
   double TDD    = MathSqrt(sumTDD/ArraySize(Results)); // Target Downside Deviation
   double TUD    = MathSqrt(sumTUD/ArraySize(Results)); // Target Upside Deviation

The concept of Target Upside Deviation (TUD) is mine. I do a lot of High Frequency Trading and Scalping in daytrading, but performance indicators such as Sharpe and Sortino applies a little bit different. I am trying to develop a non-parametric indicator that applies to every trade, so I can evaluate better my EA. My target is to skew my EA results as much as possible from normal distribution. To profit direction, of course :)

Sortino A Sharper Ratio Red Rock Capital
Sortino A Sharper Ratio Red Rock Capital
  • David Cohen
  • www.academia.edu
Sortino A Sharper Ratio Red Rock Capital
12
To add comments, please log in or register