Issue with Scale-in trades during drawdown

Scale-in trades seem to work on and off during backtesting. Especially during drawdown as it can be seen from the image below - that upto about 20% drawdown it works as expected then suddenly scale-in trades don't occur only the original entry trade exists. No AFL code tweaking the equity is used.

Scale-in trades are supposed to occur after every 0.1% of favourable move upto 5 times.

Turn on Detailed Log under Backtester Settings > Report > Detailed Log. Then run the backtest and you'll get to see what occurred on each bar and why. If a scale entry is not taken, it will display the reason why (eg Insufficient Capital). That will help you get to the bottom of why it's occurring.

Tried doing that - the scale-in signal is generated but no trade is executed. Please see the below screenshot for further reference:

It looks like you have the scale in on the sell side. For long trades, all scalings (in and out) need to be done on the Buy array.


// This is correct
Buy = IIf(BuyCondition, 1, IIf(ScaleCondition, sigScaleIn, 0));
Sell = SellCondition;

// This is Wrong
Buy = BuyCondition;
Sell = IIf(ScaleCondition, sigScaleIn, SellCondition);

Ref: https://www.amibroker.com/guide/h_pyramid.html

1 Like

Doubt that is the issue - because it is executing scale-in trades properly in the first few trades and then it suddenly stops.

For reference - I have included the 2 screenshots of the same detailed log generated after backtesting - which will illustrate my point better.

Scale-in trades Working

Scale In Trades Not Working

Your position sizing code is likely incorrect or you have assignments for scale ins wrong (as @HelixTrader pointed out). Post your code. Otherwise it is guessing game.

@HelixTrader and @Tomasz - please find below the code used for executing scale-in trades:

for( i = 0; i < BarCount; i++ ) 
{ 
   if( priceatbuy == 0 AND Buy[ i ] ) 
    { 
        //initialize required variables
        priceatbuy = BuyPrice[i]; 
        StopLoss = StopAmt[i];
        FirstProfitTarget = ProfitTarget[i];
        SecondProfitTarget = ProfitTarget2[i];
        ThirdProfitTarget = ProfitTarget3[i];
	FourthProfitTarget = ProfitTarget4[i];
	FifthProfitTarget = ProfitTarget5[i];
    } 
 
   if( priceatshort == 0 AND Short[ i ] ) 
    {
        //initialize required variables
        priceatshort = ShortPrice[ i ];
        StopLoss = StopAmt[i];
        FirstProfitTarget = ProfitTarget[i];
        SecondProfitTarget = ProfitTarget2[i];
        ThirdProfitTarget = ProfitTarget3[i];
		FourthProfitTarget = ProfitTarget4[i];
		FifthProfitTarget = ProfitTarget5[i];
    } 
 
   if( priceatbuy > 0 ) 
    { 
       
		//check if 1st target hit and Buy not = 1
       if( Buy[i] != 1 AND exit == 0 AND High[ i ] >= FirstProfitTarget + priceatbuy ) 
       { 
         // first profit target hit - scale-in 
         exit = 1; 
         Buy[ i ] = sigScaleIn; 
         BuyPrice[i] = FirstProfitTarget + priceatbuy;
                  
       } 
 
		//check if 2nd target hit and Buy not = 1
       if( Buy[i] != 1 AND Buy[i] != sigScaleIn AND exit == 1 AND High[ i ] >= SecondProfitTarget + priceatbuy ) 
       { 
         // second profit target hit - scale-in 
         exit = 2; 
         Buy[ i ] = sigScaleIn;
         BuyPrice[i] = SecondProfitTarget + priceatbuy;
       }
       
       //check if 1st target hit and Buy not = 1
       if( Buy[i] != 1 AND Buy[i] != sigScaleIn AND exit == 2 AND High[ i ] >= ThirdProfitTarget + priceatbuy ) 
       { 
         // first profit target hit - scale-in 
         exit = 3; 
         Buy[ i ] = sigScaleIn; 
         BuyPrice[i] = ThirdProfitTarget + priceatbuy;
                  
       } 
 
		//check if 2nd target hit and Buy not = 1
       if( Buy[i] != 1 AND Buy[i] != sigScaleIn AND exit == 3 AND High[ i ] >= FourthProfitTarget + priceatbuy ) 
       { 
         // second profit target hit - scale-in 
         exit = 4; 
         Buy[ i ] = sigScaleIn;
         BuyPrice[i] = FourthProfitTarget + priceatbuy;
       }

		//check if 2nd target hit and Buy not = 1
       if( Buy[i] != 1 AND Buy[i] != sigScaleIn AND exit == 4 AND High[ i ] >= FifthProfitTarget + priceatbuy ) 
       { 
         // second profit target hit - scale-in 
         exit = 5; 
         Buy[ i ] = sigScaleIn;
         BuyPrice[i] = FifthProfitTarget + priceatbuy;
       }
       
	    //check if system exit hit and Buy not = 1
       if(ExitLong [i]) //need to substitute system exit here
       { 
         // System Exit hit - exit all remaining contracts 
         exit = 6; 
         SellPrice[i] = Close[i]; //all three contracts would exit here
       }
 
		//check if stop loss hit and Buy not = 1
       if(Buy[i] != 1 AND Buy[i] != sigScaleIn AND Low[ i ] <= priceatbuy - StopLoss AND exit != 6) 
       { 
         // Stop Loss hit - exit 
         exit = 7;    
         SellPrice[ i ] = priceatbuy - StopLoss;
       }

		//check if exit complete
       if( exit >= 6 ) 
       { 
         Buy[ i ] = 0; 
         Sell[ i ] = exit-5; // mark appropriate exit code 
         exit = 0;
         priceatbuy = 0; // reset price 
        }
    } //exit: Check exits for longs
 
    if( priceatshort > 0 ) 
    {  

		//check if 1st target hit and short not = 1
       if( Short[i] != 1 AND exit == 0 AND Low[ i ] <= priceatshort - FirstProfitTarget ) 
       { 
         // first profit target hit - scale-out 
         exit = 1; 
         Short[ i ] = sigScaleIn; 
         ShortPrice[i] = priceatshort - FirstProfitTarget;
       }  
 
		//check if 2nd target hit and short not = 1
       if( Short[i] != 1 AND Short[i] != sigScaleIn AND exit == 1 AND Low[ i ] <= priceatshort - SecondProfitTarget) 
       { 
         // second profit target hit - scale-out 
         exit = 2; 
         Short[ i ] = sigScaleIn;
         ShortPrice[i] = priceatshort - SecondProfitTarget;
        }
        
       //check if 1st target hit and Buy not = 1
       if( Short[i] != 1 AND Short[i] != sigScaleIn AND exit == 2 AND Low[ i ] <= priceatshort - ThirdProfitTarget ) 
       { 
         // first profit target hit - scale-in 
         exit = 3; 
         Short[ i ] = sigScaleIn; 
         ShortPrice[i] = priceatshort - ThirdProfitTarget;
                  
       } 
 
		//check if 2nd target hit and Buy not = 1
       if( Short[i] != 1 AND Short[i] != sigScaleIn AND exit == 3 AND Low[ i ] <= priceatshort - FourthProfitTarget ) 
       { 
         // second profit target hit - scale-in 
         exit = 4; 
         Short[ i ] = sigScaleIn;
         ShortPrice[i] = priceatshort - FourthProfitTarget;
       }

		//check if 2nd target hit and Buy not = 1
       if( Short[i] != 1 AND Short[i] != sigScaleIn AND exit == 4 AND Low[ i ] <= priceatshort - FifthProfitTarget ) 
       { 
         // second profit target hit - scale-in 
         exit = 5; 
         Short[ i ] = sigScaleIn;
         ShortPrice[i] = priceatshort - FifthProfitTarget;
       }
		//check if system exit and short not = 1
       if(ExitShort[i]) //need to substitute system exit here
       { 
         // System Exit hit - exit all remaining contracts 
         exit = 6; 
         CoverPrice[i] = Close[i]; //all contracts would exit here
       }
 
		//check if stop loss hit and short not = 1
       if(Short[i] != 1 AND Short[i] != sigScaleIn AND High[ i ] >= priceatshort  + StopLoss AND exit != 6) 
       { 
         // Stop Loss hit - exit 
         exit = 7;    
         CoverPrice[ i ] = priceatshort  + StopLoss; 
        } 

		//check if exit complete
       if( exit >= 6 ) 
       { 
         Short[ i ] = 0; 
         Cover[ i ] = exit-5; // mark appropriate exit code
         exit = 0; 
         priceatshort = 0; // reset price
        }
    } //exit: check exits for shorts
 
} //exit: loop

//SetPositionSize(20000, spsValue);
SetPositionSize( 5, spsPercentOfEquity );
//SetPositionSize(80, spsShares);
SetPositionSize( 25, spsPercentOfPosition * ( Buy == sigScaleIn OR Short == sigScaleIn) ); // scale-in 50% of position

Really, you need to read “How to use this site” first.
Code must be placed inside [code]..[/code] tags. Otherwise you force me to correct each your posting.
Please DO NOT add to my work overload.
I corrected your post but it is really NOT difficult to post code correctly. Don’t be lazy!

As to the problem itself - your problems likely are caused by last line.

SetPositionSize( 25, spsPercentOfPosition * ( Buy == sigScaleIn OR Short == sigScaleIn) );

I guess that you are using non-zero delays and your pos sizing is not synchronized with that.
SetPositionSize calls must set the correct size at the bar when actual trade is made. If you are using non-zero delays, it means that you have adjust position size array accordingly so it sets new position size at right moment (for example one day LATER than the buy signal, because of the delay)

For example if you are using one bar delay

// bars when scale-in signals are present
scale_ins = Buy == sigScaleIn OR Short == sigScaleIn;
// do we use delays ???
delayed_scale_ins = Ref( scale_ins, -1 ); // only valid if using 1 bar delay in the settings !
// set scale-in size only on valid bars, otherwise keep unchanged
scale_in_size = IIF( delayed_scale_ins, spsPercentOfPosition, spsNoChange );
SetPositionSize( 25, scale_in_size );
5 Likes

@Tomasz - I am using zero delay (i.e) I am entering the trade at the close of the current bar in which the signal is generated. Therefore, there shouldn’t be an issue with the position size array and the scale in signal generation syncing up.

Furthermore, it doesn’t explain why the code works well during times of gains and not during drawdowns for the same symbol in the same backtest.

Keep in mind that there are other constraints like RoundLotSize, MinTrade size and so on. Most likely some of those constraints block the trade. Use exploration to debug your formula
http://www.amibroker.com/kb/2014/09/29/debugging-techniques-part-1-exploration/

Really debugging is a process of eliminating things. Replace your complex position size with something simpler, like say scaling in ONE share or 1000 dollars.
Only if you have simple stuff working expand with a little bit complex bits.
Bit by bit.

A typical mistake beginners make is that they write tons of code and click “Go” and they are surprised it does not work. Learn to program bit by bit. Start with simple things, add complexity layers one by one, step by step. Start with working example from the manual, add one piece at a time. Do not add dozens of things at once.

5 Likes

In the next version, I may add extra info to the detailed log that will tell you why exactly scale-in is skipped. It is always because of constraints like RoundLotSize, Min/max trade size, etc.

One practical example when you will see ignored Scale-Ins. The code below adds 10% of equity scale-ins each bar. After 10-th scaling, it will run out of cash and will ignore subsequent scale-in signals.

// scale -in each bar
Buy = sigScaleIn; 
// don't exit ever
Sell = 0;

// will run out of money after 10th trade
SetPositionSize( 10, spsPercentOfEquity ); 
4 Likes

I have followed your advice on taking things step by step and hence the code is but a minor variation of the code on the pyramding page suggested by @HelixTrader. But the code still breaks - however, your suggestion of scaling up with simpler options seems to work (i.e) if the code is executed with spsShares or spsValue then it works flawlessly but it breaks down when using a more dynamic parameter like spsPercentOfEquity or spsPercentOfPosition.

Moreover, going for a graphical representation of the scale in trades over the exploration option - the trades are indicated on the chart correctly but does not reflect in the backtester results only - indicating the signal being generated but the buying/shorting of shares is not happening - despite more than sufficient funds being available as seen from the detailed log screenshots enclosed earlier.

Yes - a more info on the detailed log should help in the future versions.

1 Like

As I wrote already - the only reason for scale ins to be ignored is violation of position size constraints
(too small order or too large order). In your case scale ins requested may be simply too small (effective number of shares less than round lot size setting). It is easy to overlook when you are using percentages.

1 Like