What is a COM object variable?

Hello,

while backtesting, this error has occured:
Error 18.
COM object variable is not initialized or has invalid type (valid COM object handle required).
Amibroker highlighted this part of the code:

atar = Foreign("~atar_"+sig.symbol(),"C");

   if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i])); 

    bo.ExitTrade(i, sig.Symbol,

Please, help me understand what's wrong.

Thank you

@ondra10192, the Component Object Model (COM) is a (somewhat old) Windows technology that defines and implements mechanisms that enable software components, such as applications, data objects, controls, and services, to interact as objects.
The AmiBroker Portfolio Backtester Interface is implemented using this kind of technology, so the errors it reports are labeled as COM errors (and they are raised when your code is doing something wrong, like calling a function with wrong parameters, a number of args less than required, etc.).

Anyway, your pasted code (ignoring the last incomplete line) seems wrong:

if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i]));

This "if" line is terminated with a ";" and in such a case the following code IS NOT in a conditional statement as you probably wanted to write.

1 Like

@ondra10192 - First you did NOT post entire code. This makes it impossible to answer correctly. Please follow this advice: How to ask a good question

Your trade variable is apparently NEVER defined or assigned. But since you are not posting entire code it is guessing game. And we don't play guessing games here.

1 Like

I really don't mean to waste anyone's time. Sorry for not posting the entire code before. I appreciate your feedback. The entire CBT part is here:

AddToComposite(ATR(5),"~atar_"+Name(),"C",atcFlagEnableInBacktest);

SetCustomBacktestProc("");

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
    
    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() ) 
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, sig.PosSize );
                
           if( sig.IsExit() )
                bo.ExitTrade( i, sig.Symbol, sig.Price );
          
        }	
        
        bo.HandleStops( i );	//  Handle programmed stops at this bar
        
        for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos())	//loop through open positions
        {
			atar = Foreign("~atar_"+sig.symbol(),"C");
			if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i]));	// if price drops under SL, I will exit the trade
				bo.ExitTrade(i, sig.Symbol, trade.EntryPrice-(3*atar[i]));		//exiting the trade at the SL price

        
		}
        bo.UpdateStats( i, 1 );	//  Update MAE/MFE stats for bar
        bo.UpdateStats( i, 2 );	//  Update stats at bar's end
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}

trade is the variable you're using to loop through open positions.
I think that the problem is that you have no open positions, so trade will never have a value (i.e. it is a variable that will never be initialized).

You can try to call bo.Backtest before bo.GetFirstOpenPos to make Amibroker generate a trade list...

Thank you LeoCV. I will try it.

As @beppe wrote - your code has an extra semicolon that TERMINATES if statement, so next line is executed unconditionally: You must REMOVE THAT SEMICOLON!

if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i]));	// SEMICOLON here is an ERROR
				bo.ExitTrade(i, sig.Symbol, trade.EntryPrice-(3*atar[i]));		

should be:

if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i])) 	
{  // if price drops under SL, I will exit the trade
				bo.ExitTrade(i, sig.Symbol, trade.EntryPrice-(3*atar[i]));	
}	

Thank you for pointing out the extra semicolon but it doesn't solve the problem.

The code works fine withouth this CBT part. Which should mean that the problem is within this CBT part. The whole point of using this low-level CBT is that I want to use a specific SL (placed at a distance of 3xATR(5) under the entry price). Using ApplyStop function is not possible since it is not supported in backtestRegularRaw mode.

@ondra10192, try replacing the sig.Symbol in this loop with trade.Symbol:

   for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos())	//loop through open positions
        {
			atar = Foreign("~atar_"+trade.symbol(),"C");
			if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i]));	// if price drops under SL, I will exit the trade
				bo.ExitTrade(i, trade.Symbol, trade.EntryPrice-(3*atar[i]));		//exiting the trade at the SL price

        
		}

I suggest reviewing the Portfolio Backtester Interface Reference Guide. The Symbol property is defined both for the Signal and the Trade objects.

Hooray!! Thank you @beppe It works. I replaced sig.symbol() with trade.Symbol in the code and its working fine now. I will definitely reread the Reference Guide. This was my first Low-level CBT that I ever created. Feels nice that it actually works :slight_smile:

2 Likes

Still this line is simply wrong. Terminating semicolon is still in wrong place

Corrected version:

if(trade.GetPrice(i,"C") <= trade.EntryPrice-(3*atar[i])) 	
{  // if price drops under SL, I will exit the trade
				bo.ExitTrade(i, trade.Symbol, trade.EntryPrice-(3*atar[i]));	
}	

Yes, you are 100% right. I simply pasted a section of the OP code and modified it as suggested but forgot to remove the extra semicolon (that I also spotted on my first answer). Sorry for the oversight.

1 Like

Quite frankly if original poster just looked carefully at the error message he got, it was pointing right before his eyes that sig variable is NOT valid (it was zero). And that it is precisely explained in the manual http://www.amibroker.com/guide/errors/18.html and one only needs to press F1 on error message to get the insight.

1 Like