PreProcess() CBT and access to some objects

Hello,
i'm setting up CBT work, and i'm getting there but have noticed some behaviors that would require clarification please.

Please look at the code below:

  1. Custom metrics for mc (monte carlo) are not displayed, don't they work after calling bo.PreProcess()?

  2. Similarly is it possible to access stats: bo.GetPerformanceStats(0); from this context?

  3. Do you see any reason why the switch statement in that code doesn't work? (but the commented if statements do).

SetOption( "MCEnable", True ); 
SetOption( "MCRuns", 1000 ); 


SetCustomBacktestProc("");
if (Status("action") == actionPortfolio)
{


	_TRACE("!CLEAR!");
	
    bo = GetBacktesterObject();    //  Get backtester object
    bo.PreProcess();    //  Do pre-processing
    
    stat = bo.GetPerformanceStats(0); // get stats for all trades 
    mc = bo.GetMonteCarloSim(); 
    


    if( mc )  // This will not compute and display the metrics
    { 
         // get 25-th percentile of final CAR distribution ; 
         bo.AddCustomMetric( "FinalEquity25", mc.GetValue( "FinalEquity", 25 ) ); 
         bo.AddCustomMetric( "CAR25", mc.GetValue( "CAR", 25 ) ); 
         bo.AddCustomMetric( "LowestEquity25", mc.GetValue( "LowestEquity", 25 ) ); 
         bo.AddCustomMetric( "MaxDrawdown25", mc.GetValue( "MaxDrawdown", 25 ) ); 
         bo.AddCustomMetric( "MaxPercDrawdown25", mc.GetValue( "MaxPercDrawdown", 25 ) ); 
    } 
    
    
    for (i = 0; i < BarCount; i++)    //  Loop through all bars
    {
		
		
        for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i))
        {    //  Loop through all signals at this bar
             
		
            if (sig.IsEntry() )    //  If this signal an entry
            {

				currentEquity = bo.Equity;    
				_TRACE("currentEquity: " + currentEquity);
			
			
			
				defaultPositionSize = 1;
				
				/*if ( currentEquity >= 1200 AND currentEquity < 1599 )
				{
					defaultPositionSize = 2;
				}
				
				if ( currentEquity >= 1600 AND currentEquity < 2199 )
				{
					defaultPositionSize = 3;
				}*/
				
				
				switch(currentEquity) { 
					case currentEquity >= 1200 AND currentEquity < 1599: 
						defaultPositionSize = 2; 
						_TRACE("TEST: ");
						break;
					case currentEquity >= 1600 AND currentEquity < 2199: 
						defaultPositionSize = 3;
						break;
					case currentEquity >= 2200 AND currentEquity < 2999: 
						defaultPositionSize = 4;
						break;
					default: defaultPositionSize = 1; break;	
					
				}
				
                sig.PosSize = -2000 - defaultPositionSize;    //  Set modified position size back into object
            }
        }    //  End of for loop over signals at this bar
   
        
        bo.ProcessTradeSignals(i);    //  Process trades at this bar
    }    //  End of for loop over bars
    
    
    initialEquity = bo.InitialEquity;
    for (trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade())
        {    //  Loop through all open positions
            initialEquity += trade.GetProfit();
            trade.AddCustomMetric("Current Equity", initialEquity  ); 
        }    //  End of for loop over trades at this bar
        
    bo.AddCustomMetric( "Number of trades: ", 6 );   // this is a test
    bo.PostProcess();    //  Do post-processing
}

By Moving MonteCarlo initialization below bo.PostProcess(); I got it working. And by moving stats below the loops, I got it work also.
Only thing I couldn't get working is that switch statement.

Case constant-expression has to match value of switch ( expression ). Expression can be scalar (number) or string.

Code like this

a > x and a < y

return true or false boolean but not matching currentEquity value to switch ( expression ).

Use if-else instead of switch for what you want to do.

As for switch you should follow documentation:
https://www.amibroker.com/guide/keyword/switch.html

1 Like

Thank you for your answer.
I did read that doc, but from the exemple with n == number from the loop, I didn't thought that a Boolean was necessary. I understand how I was wrong though.

I'll just use the if-else then.

There is no n == number boolean code in the AB help example (see below).
The example there uses loop to iterate a range of numbers and switch expression being loop counter n. Case expressions are numbers to match the loop counter n. So if a case expression matches switch n expression then case statement result is returned.

Example of the AB help:

for( n = 0; n < 10; n++ ) 
{ 
	printf("Current n = %f\n", n ); 

	switch(n) { 
		 case 0: 
		   printf("The number is zero.\n"); 
		   break; 
		 case 3: 
		 case 5: 
		 case 7: 
		   printf("n is a prime number\n"); 
		   break; 
		 case 2: printf("n is a prime number\n"); 
		 case 4: 
		 case 6: 
		 case 8: 
		   printf("n is an even number\n"); 
		   break; 
		 case 1: 
		 case 9: 
		   printf("n is a perfect square\n"); 
		   break; 
		 default: 
		   printf("Only single-digit numbers are allowed\n"); 
		 break; 
	} 
}
1 Like

Got it. My problem was in fact in the case part of code: my expression there was the boolean that didn't match the switch statement which is a number.
Thank you.