Example of scaling out

Has anyone tried running the example for scaling out in the Ambroker user guide? I'm referring to Example 4 on this web page here:
https://www.amibroker.com/guide/h_pyramid.html?fbclid=IwAR0PwyZXa2ufOGaIK2921VanFhXyPKLI9M1OnxngVG3dXdYsLkbbeBfCM1s

When I try running the code I don't see the backtest results that I would expect. When it scales out, it should scale out of 50% of the position. In the screen shot below, the detailed log, shows that it held 9514 shares and then scaled out of 9375 shares. I ran the code against a watchlist with two equities, CEF and SPY
Capture

// scale out 50% of position
SetPositionSize( 50, spsPercentOfPosition *( Buy == sigScaleOut )); 

Position value does not mean number of stocks but "Dollar" value (-> number of stocks * price). Look at market value before and after.

1 Like

From your picture, it seems working.

Your market value decreases and your cash position increases.

a836083ad422a64fd41a67e553c1600f0450f427

@Marcel,

disable trade delays of analysis setting in code and use Ref() function to delay signals. Then it should scale out 50% of symbol's position value instead of what you get in 1st post.

See
7

/// @link https://forum.amibroker.com/t/example-of-scaling-out/14652/4
tradedelay = 1; // entry/exit bar delay
if ( tradedelay > 0 ) {
    pricearray = Open;
} else {
    pricearray = Close;
}

// disable UI trade delays
SetTradeDelays( 0, 0, 0, 0 );
 
BuyPrice = SellPrice = pricearray;
ShortPrice = Coverprice = pricearray;

// delay signals  via Ref()
Buy = Ref(Cross( MA( C, 10 ), MA( C, 50 ) ), -tradedelay);
Sell = 0;
Short = Cover = 0;

// ################################################################
// 4th code of AB manual pyramiding
/// @link https://www.amibroker.com/guide/h_pyramid.html
// the system will exit
// 50% of position if FIRST PROFIT TARGET stop is hit
// 50% of position is SECOND PROFIT TARGET stop is hit
// 100% of position if TRAILING STOP is hit

FirstProfitTarget = 10; // profit
SecondProfitTarget = 20; // in percent
TrailingStop = 10; // also in percent

priceatbuy=0;
highsincebuy = 0;

exit = 0;

for( i = 0; i < BarCount; i++ )
{
   if( priceatbuy == 0 AND Buy[ i ] )
    {
       priceatbuy = BuyPrice[ i ];
    }

   if( priceatbuy > 0 )
    {
       highsincebuy = Max( High[ i ], highsincebuy );

      if( exit == 0 AND
          High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy )
       {
         // first profit target hit - scale-out
         exit = 1;
         Buy[ i ] = sigScaleOut;
       }

      if( exit == 1 AND
          High[ i ] >= ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy )
       {
         // second profit target hit - exit
         exit = 2;
         SellPrice[ i ] = Max( Open[ i ], ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy );
       }

      if( Low[ i ] <= ( 1 - TrailingStop * 0.01 ) * highsincebuy )
       {
         // trailing stop hit - exit
         exit = 3;   
         SellPrice[ i ] = Min( Open[ i ], ( 1 - TrailingStop * 0.01 ) * highsincebuy );
       }

      if( exit >= 2 )
       {
         Buy[ i ] = 0;
         Sell[ i ] = exit + 1; // mark appropriate exit code
         exit = 0;
         priceatbuy = 0; // reset price
         highsincebuy = 0;
       }
    }
}

SetPositionSize( 50, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position
5 Likes

Thank you so much @fxshrat for your solution!

From another post on this forum I was able to derive a basic code for a single scale out without having to use a loop:
https://forum.amibroker.com/t/problem-with-sigscaleout-instead-of-partial-exit-it-exit-100-positon-size/11961

This is the code that I came up with:

//code derived from:
///@link https://forum.amibroker.com/t/problem-with-sigscaleout-instead-of-partial-exit-it-exit-100-positon-size/11961
SetTradeDelays(1,1,1,1);
BuyPrice = SellPrice = Open;
FastMA = MA( Close, 10 );
SlowMA = MA( Close, 50 );
BuySetup = Cross( FastMA, SlowMA ); 
SellSetup = Cross( SlowMA, FastMA); 
HoldBuy = Flip(BuySetup, SellSetup);
FirstProfitTarget = 2; // profit in percent  
LongEntryPrice = IIf(Ref(HoldBuy, -1), ValueWhen(Ref(BuySetup,-1) ==1, Open, 1), 0);
TargetPrice = LongEntryPrice*(1+FirstProfitTarget/100);
TargetPrice = IIf(TargetPrice > 0,TargetPrice,Null);//removes 0 value for charting
LongEntryPrice = IIf(LongEntryPrice > 0,LongEntryPrice,Null);//removes 0 value for charting
ScaleOut = Ref(HoldBuy, -1) AND Close >= (LongEntryPrice *(1+ FirstProfitTarget/100));
ScaleOut = ExRem(ScaleOut, SellSetup);
Buy = IIf(ScaleOut, sigScaleOut, BuySetup); 
Sell = IIf(ScaleOut, 0, SellSetup);
Short = Cover = 0;
SetPositionSize( 50, spsPercentOfPosition* ( Buy == sigScaleOut));
PositionSize = Ref(PositionSize, -1);

//Charting
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( Close, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 
Plot(FastMA,"FastMA",colororange, styleLine|styleThick );
Plot(SlowMA,"SlowMA",colorBlue, styleLine|styleThick );
Plot(LongEntryPrice,"LongEntryPrice",colorWhite, styleDashed|styleThick );
Plot(TargetPrice,"TargetPrice",colorYellow, styleDashed|styleThick );
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-40);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-50);
PlotShapes(IIf(Buy, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-45);
PlotShapes(IIf(ScaleOut, shapeSquare, shapeNone),colorgold, 0, H, Offset=40);
PlotShapes(IIf(ScaleOut, shapeSquare, shapeNone),colorlightOrange, 0,H, Offset=50);
PlotShapes(IIf(ScaleOut, shapeDownArrow, shapeNone),colorWhite, 0,H, Offset=-45);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, H, Offset=40);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,H, Offset=50);
PlotShapes(IIf(Sell, shapeDownArrow, shapeNone),colorWhite, 0,H, Offset=-45);
2 Likes

I am trying to follow along with this example but change it so that it only has one profit target and also plot the trailing stop level as outlined in this article. Looking at the detailed logs, I am not seeing proper scaling out with this single scaleout like I do when both scaleouts were used in the previous example.

Another thing I'm not clear about is the different "exit codes" that are assigned to Sell. I could not find the documentation about what this means. At first I thought it was just a counter in this example, but as I look at the results it seems related to the type of exit (profit, max loss, trailing, etc.). Is this somewhere in the manual I am not finding? This is potentially an issue with this modification is I don't know what I'm doing with the exit codes.

Here is my updated code where I attempted to scale out using only one profit target by hiding the second profit target code and adding the trailing stop as a visual. Would appreciate any guidance on what I am doing wrong here.

SetOption("InitialEquity", 100000);
RoundLotSize = 1;  // Disallow fractional share purchasing

/// @link https://forum.amibroker.com/t/example-of-scaling-out/14652/4
tradedelay = 1; // entry/exit bar delay
if ( tradedelay > 0 ) {
    pricearray = Open;
} else {
    pricearray = Close;
}

// disable UI trade delays
SetTradeDelays( 0, 0, 0, 0 );

// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

sma10 = ma(Close, 10);
sma20 = ma(Close, 20);
Plot(sma10,"10MA",color = colorBlueGrey, styleNoTitle);
Plot(sma20,"20MA",color = colorGrey50, styleNoTitle);
 
BuyPrice = SellPrice = pricearray;
ShortPrice = Coverprice = pricearray;

// delay signals  via Ref()
Buy = Ref(Cross( MA( C, 10 ), MA( C, 20 ) ), -tradedelay);
Sell = 0;
Short = Cover = 0;

// ################################################################
// 4th code of AB manual pyramiding
/// @link https://www.amibroker.com/guide/h_pyramid.html
// the system will exit
// 50% of position if FIRST PROFIT TARGET stop is hit
// 50% of position is SECOND PROFIT TARGET stop is hit
// 100% of position if TRAILING STOP is hit

FirstProfitTarget = 3; // profit
SecondProfitTarget = 8; // in percent
TrailingStop = 10; // also in percent

priceatbuy=0;
highsincebuy = 0;
trailstop = 0;

exit = 0;

for( i = 0; i < BarCount; i++ )
{
   if( priceatbuy == 0 AND Buy[ i ] )
    {
       priceatbuy = BuyPrice[ i ];
    }

   if( priceatbuy > 0 )
    {
       highsincebuy = Max( High[ i ], highsincebuy );

      if( exit == 0 AND
          High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy )
       {
          //first profit target hit - scale-out
         exit = 2;
         Buy[ i ] = sigScaleOut;
       }

      //if( exit == 1 AND
      //    High[ i ] >= ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy )
      // {
          //second profit target hit - exit
      //   exit = 2;
      //   SellPrice[ i ] = Max( Open[ i ], ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy );
      // }
      
      if( trailstop == 0 AND Buy[ i ] ) 
	  { 
		trailstop = High[ i ] * (1 - TrailingStop * 0.01);
      }
		else Buy[ i ] = 0; // remove excess buy signals

      if( trailstop > 0 AND Low[ i ] < trailstop )
       {
          //trailing stop hit - exit
         exit = 3;     
         SellPrice[ i ] = Min( Open[ i ], trailstop );
         trailstop = 0;
       }
       
      if( trailstop > 0 )
	   {
		  trailstop = Max( High[ i ] * (1 - TrailingStop * 0.01), trailstop );
		  trailARRAY[ i ] = trailstop;
	   }

      if( exit >= 2 )
       {
         Buy[ i ] = 0;
         Sell[ i ] = exit + 1; // mark appropriate exit code
         exit = 0;
         priceatbuy = 0; // reset price
         highsincebuy = 0;
       }
    }
}

SetPositionSize( 50, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position

PlotShapes(Buy*shapeUpArrow,colorGreen,0,Low);
PlotShapes(Sell*shapeDownArrow,colorRed,0,High);
Plot( trailARRAY,"trailing stop level", colorRed );

You are over-riding your scale out variable with this Sell variable.

1 Like

Thanks for your help, I was able to figure it out with your tips. Most had to do with the exit codes and my lack of understanding before seeing that link. There was also another piece of code that was overriding my scaleout:

else Buy[ i ] = 0; // remove excess buy signals

Looks like I have it working now. Reposting final code for anyone else who might be doing something similar and to solicit any other recommendations/optimizations if there are any.

SetOption("InitialEquity", 100000);
RoundLotSize = 1;  // Disallow fractional share purchasing

/// @link https://forum.amibroker.com/t/example-of-scaling-out/14652/4
tradedelay = 1; // entry/exit bar delay
if ( tradedelay > 0 ) {
    pricearray = Open;
} else {
    pricearray = Close;
}

// disable UI trade delays
SetTradeDelays( 0, 0, 0, 0 );

// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

sma10 = ma(Close, 10);
sma20 = ma(Close, 20);
Plot(sma10,"10MA",color = colorBlueGrey, styleNoTitle);
Plot(sma20,"20MA",color = colorGrey50, styleNoTitle);
 
BuyPrice = SellPrice = pricearray;
ShortPrice = Coverprice = pricearray;

// delay signals  via Ref()
Buy = Ref(Cross( MA( C, 10 ), MA( C, 20 ) ), -tradedelay);
Sell = 0;
Short = Cover = 0;

// Sell exit codes: https://www.amibroker.com/kb/2014/09/24/how-to-identify-which-signal-triggers/
// ################################################################
// 4th code of AB manual pyramiding
/// @link https://www.amibroker.com/guide/h_pyramid.html
// the system will exit
// 50% of position if FIRST PROFIT TARGET stop is hit
// 50% of position is SECOND PROFIT TARGET stop is hit
// 100% of position if TRAILING STOP is hit

FirstProfitTarget = 3; // profit
SecondProfitTarget = 8; // in percent
TrailingStop = 10; // also in percent

priceatbuy=0;
highsincebuy = 0;
trailstop = 0;

exit = 0;

for( i = 0; i < BarCount; i++ )
{
   if( priceatbuy == 0 AND Buy[ i ] )
    {
       priceatbuy = BuyPrice[ i ];
    }

   if( priceatbuy > 0 )
    {
       highsincebuy = Max( High[ i ], highsincebuy );

      if( exit == 0 AND
          High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy )
       {
          //first profit target hit - scale-out
         exit = 1;
         Buy[ i ] = sigScaleOut;
       }
      
      if( trailstop == 0 AND Buy[ i ] ) 
	  { 
		trailstop = High[ i ] * (1 - TrailingStop * 0.01);
      }

      if( trailstop > 0 AND Low[ i ] < trailstop )
       {
          //trailing stop hit - exit
         exit = 2;     
         SellPrice[ i ] = Min( Open[ i ], trailstop );
         trailstop = 0;
       }
       
      if( trailstop > 0 )
	   {
		  trailstop = Max( High[ i ] * (1 - TrailingStop * 0.01), trailstop );
		  trailARRAY[ i ] = trailstop;
	   }

      if( exit == 2 )
       {
         Buy[ i ] = 0;
         Sell[ i ] = 1; // mark appropriate exit code
         exit = 0;
         priceatbuy = 0; // reset price
         highsincebuy = 0;
       }
    }
}

SetPositionSize( 50, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position

PlotShapes(Buy*shapeUpArrow,colorGreen,0,Low);
PlotShapes(Sell*shapeDownArrow,colorRed,0,High);
Plot( trailARRAY,"trailing stop level", colorRed );
2 Likes