Standard Deviation in Custom backtest metric

Hello,
I'm trying to calculate Van Tharp's SQN as a custom backtest metric.
I don't believe it's the best objective function but it's more a way to learn AFL and AB.

This code doesn't work because I guess I have a problem calculating the standard deviation.
You can see that I calculate it on an array "trades" that I manually created to be sure it's properly populated.

Problem is that "stdrmultiples" variable is always 0.

Do you see any problem in my syntax there that would prevent the proper calculation of the standard deviation on array "trades"?

/* Now custom-backtest procedure follows */ 
if( Status("action") == actionPortfolio ) 
{ 
	_TRACE("!CLEAR!");
    bo = GetBacktesterObject(); 

    bo.Backtest(1); // run default backtest procedure 
    
    st = bo.GetPerformanceStats(0); // get stats for all trades 
    
    averageRisk = st.GetValue("LosersAvgLoss"); // Average loss = 1R

   SumProfitPerRisk = 0; 
   NumTrades = 0; 
   

   // iterate through closed trades first 
   for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) 
   { 
       // Avg loss = LosersAvgLoss
       RMultiple = trade.GetProfit()/ abs(averageRisk); // Rmultipe per trade
       SumProfitPerRisk = SumProfitPerRisk + RMultiple; // Summ of all R multiple
       
       trade.AddCustomMetric("R-Multiple", RMultiple  ); 
       NumTrades++; 
   } 
    trades = 0;
    trades[ 0 ] = 1;
    trades[ 1 ] = 11;
    trades[ 2 ] = 41;
    trades[ 3 ] = 21;
	_TRACE("trades" + trades[ 3 ]); // 21

    expectancy = SumProfitPerRisk / NumTrades; // Average of sum of R multiples = Expectancy.

    bo.AddCustomMetric( "Expectancy (per risk)", expectancy ); 

    stdrmultiples = StDev( trades , 4 , False );
    _TRACE("stdrmultiples" + stdrmultiples); // 0

    MSQN = ( expectancy / stdrmultiples ) * ( sqrt(4) );
    bo.AddCustomMetric( "stddev", MSQN ); 

    bo.ListTrades(); 

} 

Found this: Trying to use stdev in a custom metric - I get no output from stdev but others work

Should I assume that standard deviation function doesn't work to calculate custom metrics?
If so, can I know why?

It's not that the Standard Deviation function "doesn't work", it's that it's not a good match for what you're trying to do. The StDev() function takes an array and a lookback period as input, and it produces a new array as output. In the CBT, all arrays are the same size, with one element per bar in the backtest date range. In your example, you only used 4 of the N bars of the trades array, so the standard deviation value that you want is in the fourth element of the returned array (i.e. index 3). But what if your backtest had produced more trades than there were bars? You wouldn't have room to store all your values.

The method described by @fxshrat in the post you linked to does not require that you put values (R multiples in this case) into an array first, because it accumulates the values needed to calculate Standard Deviation as they are encountered. This is a far superior way to approach the problem.

1 Like

At least for me StdDev function is not working at all in CBT. I tried to put the values at the end of the array instead and backwards:

Rdist[BarCount-NumTrades]=RMultiple;

But still returns nothing:

 bo.AddCustomMetric( "StdDev" , StDev(Rdist,5)); 

Hopefully @Brakkar reference did the trick and I think it is a much better way of calculate standard deviation, but I wonder why native function does not work on CBT

StDev requires input ARRAY and outputs the ARRAY (not single value as you wrongly assume) and it is "running" / walking / moving stdev like "moving average"

If you only want to use 5 last bars you have to FILL last bars and use LastValue!

Something along these lines:

Rdist = Null; // initialize ALL bars with Null
Rdist[ BarCount - 1 ]  = non-null-values here
Rdist[ BarCount - 2 ]  = non-null-values here
Rdist[ BarCount - 3 ]  = non-null-values here
Rdist[ BarCount - 4 ]  = non-null-values here
Rdist[ BarCount - 5 ]  = non-null-values here
Rdist[ BarCount - 6 ]  = non-null-values here

bo.AddCustomMetric( "StDev 5 last bars", LastValue( StDev( RDist, 5 ) ) );

The other method already quoted here is: Trying to use stdev in a custom metric - I get no output from stdev but others work - #2 by fxshrat

Please don't revive 5-year old topics that were marked as solved. Solution was already given, so just use it.

Topic was 5-year old.