Scale out of the same number of shares as my last scale-in entry

When scaling out, I am trying to exit the same number of shares as my last entry and/or scale-in. I am real close, but off by just a little. Here is my CBT code:

dn = DateNum();
tn = TimeNum();
dt=DateTime();
doTrace = 1;
SetCustomBacktestProc( "" );
if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject(); 
    bo.PreProcess(); 

    for ( i = 0; i < BarCount; i++ )
    {
        if ( i == 0 )
		{
			LastEntryShares = 0;
		}

		if ( i > 0 )
		{
			dn_tn = NumToStr(dn[i], 1.0, False, False) + "_" + NumToStr(tn[i], 1.0, False, False);
			dn_tn_i = "DT: " + dn_tn + " i: " + NumToStr(i,1.0, True, False) + " ||||| " ;

			for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i))
			{   
				tmpPrc = sig.Price;
				if (doTrace) { _TRACE(dn_tn_i + " tmpPrc: " + NumToStr(tmpPrc, 1.2)); }
				
				if (sig.IsLong() AND NOT sig.Type == 2 AND NOT sig.Type == 6 )  
				{
					psize = sig.PosSize;    
					
					if (psize < 0)   
						psize = (-psize/100) * bo.Equity; 
					
					LastEntryShares = psize / tmpPrc;
					StaticVarSet ( "LastEntryShares" +  sig.Symbol, LastEntryShares);
					if (doTrace) { _TRACE(dn_tn_i + " !!!!!!!!! En ---LastEntryShares: " + NumToStr(LastEntryShares, 1.4) + "  Equity: " + NumToStr(bo.Equity, 1.6) + "  psize: " + NumToStr(psize, 1.2) + "  sig.Price: " + NumToStr(tmpPrc, 1.2) + "  sig.Type: " + NumToStr(sig.Type, 1.0) ); }
				}
			
				if (sig.Type == 6)    //  If this signal is a scale-out exit
				{
					LastEntryShares = StaticVarGet ( "LastEntryShares" +  sig.Symbol);
					if (doTrace) { _TRACE(dn_tn_i + " Ex ---LastEntryShares: " + NumToStr(LastEntryShares, 1.4)); }
					sig.PosSize = LastEntryShares * tmpPrc;    //  Set modified position size back into object
				}
			}

		}
		bo.ProcessTradeSignals( i );
	}	

    bo.PostProcess();  
}

image

I have set positions sizing to 5% per entry and/or scale-in. With the given example here, I calculate the number of shares to enter at 33.6198, but AB is entering 33.62014 shares. Why? I do not have AllowPositionSizeShrinking on. You can see that I am calculating the number of shares traded like this:
LastEntryShares = psize / sig.Price;
But that gives me 33.6198 shares, not what the detailed report is showing at 33.62014.

Also if I do the math from my print statements:
Equity: 121878.382813 * 5% = $6093.92 to trade, divided by price of 181.26 = 33.6198 shares.

Why would AB say that we entered 33.62014 shares when all calculations return 33.6198?

A quick guess... commission?

Nope, I have commissions set to zero.

image

You use

 "  sig.Price: " + NumToStr(tmpPrc, 1.2)

But you do not tell whether it is dividend and split adjusted data which would result in more decimal places then two ones after comma!

So use

 StrFormat("  sig.Price: %g", tmpPrc )

Or use _TRACEF instead of _TRACE.

and see if you get something like 181.258 instead of just 181.26.

Also this 121878.382813 is more than 7 significant digits.

Other than that it is pointless looking for wrong calculations by AB. Forget about it.

Indeed, looking with more attention to the report, it clearly says Entry + scaling commission 0
I apologize.

@fxshrat , the data is not dividend or split adjusted. Just raw from a csv file. Also, I round all of my entry and exit prices with the following rounding function, so the price is always just two decimals max:

function StkRnd(input)
{
	result = round(input*100)/100;
	return result;
}

I have revised my trace statement according to your suggestion:

if (doTrace) { _TRACE(dn_tn_i + " !!!!!!!!! En ---LastEntryShares: " + StrFormat(" LastEntryShares: %g", LastEntryShares ) + StrFormat(" Equity: %g", bo.Equity ) + StrFormat(" psize: %g", psize ) + StrFormat(" sig.Price: %g", tmpPrc ) + " sig.Type: " + NumToStr(sig.Type, 1.0) ); }

And now I am getting this but the math still does not line up:
image

You said, "Other than that it is pointless looking for wrong calculations by AB. Forget about it."

But this is so simple. Why can't we figure this out?

Hi @vjsworld,

I'm not 100% sure, but I think the reason for that small difference is due to the fact that your calculation of number of shares is based on the equity at the end of the bar while AB uses equity before all the update is done including the effect of trades entries and exits which might occur at that bar.
To reference that individual scale-in entry, one approach could be to use the handle property described here:
https://forum.amibroker.com/t/api-backtester-exittrade/10542/2.

Simple answer - your calculation may be using different equity value than used by AmiBroker. Depending on settings AmiBroker may use previous bar close equity or opening bar equity value. When prices move from previous bar close to this bar open these two equities will be different. Secondly AmiBroker internally uses double precision for backtester calculations therefore it is more precise than your code.

1 Like