Partial exit help

Hello,
I have copied the partial exits code from the AFL reference contents, and have modified it to only take 1 partial exit, and exit the whole position at the other point,
but i cant get it to sigScaleOut, not matter what i try…

i know the buy conditions work perfectly, though i don’t want to include them,
i was hoping the good people here may have a quick look to see if i am just missing something or is the problem a bit larger.

pt = BuyPrice - ValueWhen(Buy,zone,1);
FirstProfitTarget = pt; // profit 
//SecondProfitTarget = 20; // in percent 
TrailingStop = Ref(zone,-1); // also in percent 

priceatbuy=0; 
FirstProfitTarget=0; 

exit = 0; 

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

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

      if( Low[ i ] <= ( TrailingStop[i] ) )
       { 
         // trailing stop hit - exit 
         exit = 2;    
         SellPrice[ i ] = zone[i]; 
       } 

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

SetPositionSize( 100, spsShares ); // 100 shares by default 
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ));
//SetPositionSize( 50, Buy == sigScaleOut, spsPercentOfPosition);
 

There are a few ways to troubleshoot this.

The first is to create some Explore code at the foot of your AFL, thus:

Filter = 1;
AddColumn(Buy, "Buy", 1);

Then run that as an Explore. Your entry buy will show as a 1, and any scale outs will show as 99999. If you're not seeing any, it's probable the condition for it is not being met ahead of the exit.

The other way is to run a backtest with the Detailed Log turned on in the settings. That will show you exactly what is happening in the backtester on every bar. Again you can check for the scale being signalled and ignored, or never appearing at all.

A third way is to use PlotShapes and plot the scaling on the chart.

PlotShapes(IsTrue(Buy == sigScaleOut) * shapeSmallCircle, colorRed, 0, L, -12);

3 Likes

Hello Helix,

thanks for the reply, following your toubleshooting (explorer) I've found that the FirstProfitTarget is not ever being assigned. which is weird because the first IF statment is pretty standard in all the templates.. is it a formatting issue?

for( i = 0; i < BarCount; i++ ) 
{ 
   if( priceatbuy == 0 AND Buy[i] )
   { 
    zoneatbuy = zone[i];
    priceatbuy = buyprice[i];
    FirstProfitTarget = thehhv[i];
    } 
	
	if( priceatbuy > 0 ) 
    { 
      if( exit == 0 AND High[ i ] >= FirstProfitTarget)
       { 
         // first profit target hit - scale-out 
         exit = 1; 
         Buy[ i ] = sigScaleOut; 
       } 

      if( Low[ i ] <= ( zone[i-1] ) )
       { 
         // trailing stop hit - exit 
         exit = 2;    
         SellPrice[ i ] = zone[i-1]; 
       } 

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

hi, I agree with Helixtrader, it helps to visualize the trades.

Below another example. The system enter 300 shares and has 2 targets where it exits 100 shares at each target (if reached). If stopped out it sells the entire open position. It can also be backtested in a portfolio type system.

_SECTION_BEGIN( "Pivots" );
per = Param( "per", 20, 1, 150, 1 );
mult = Param( "mult", 2, 1, 4, 0.05 );
fact = Param( "Chart Time Frame Factor", 3, 1, 10, 1 );
_SECTION_END();

tfrm = Interval() * fact;

TimeFrameSet( tfrm );
sup = C - mult * ATR( per );
res = C + mult * ATR( per );
trailARRAY = Null;
trailstop = 0;

for( i = 1; i < BarCount; i++ )
{
    if( C[ i ] > trailstop AND C[ i - 1 ] > trailstop )
        trailstop = Max( trailstop, sup[ i ] );
    else
        if( C[ i ] < trailstop AND C[ i - 1 ] < trailstop )
            trailstop = Min( trailstop, res[ i ] );
        else
            trailstop = IIf( C[ i ] > trailstop, sup[ i ], res[ i ] );

    trailARRAY[ i ] = trailstop;
}

ts = IIf( trailArray > C, trailArray, Null );
tl = IIf( trailArray < C, trailArray, Null );
TimeFrameRestore();

ts = TimeFrameExpand( ts, tfrm, expandLast );
tl = TimeFrameExpand( tl, tfrm, expandLast );

Buy = IsEmpty( ts ) AND !isempty( Ref( ts, -1 ) ) AND !IsEmpty( tl );
Sell = 0;

FirstProfitTarget = Null;
flag1 = 0;
SecondProfitTarget = Null;
flag2 = 0;
slip = 0.00;

for( i = 0; i < BarCount; i++ )
{
    if( Buy[ i ] )
    {
        BuyPrice[i] = C[i];
        FirstProfitTarget[i] = BuyPrice[i] + ( BuyPrice[i] - tl[i] );
        SecondProfitTarget[i] = BuyPrice[i] + ( BuyPrice[i] - tl[i] ) * 2;

        for( j = i + 1; j < BarCount; j++ )
        {
            if( flag1 == 0 ) FirstProfitTarget[j] = FirstProfitTarget[i];
            if( flag2 == 0 AND flag1 == 1 ) SecondProfitTarget[j] = SecondProfitTarget[i];

            if( High[ j ] >= FirstProfitTarget[j] AND !IsEmpty( tl[j] ) AND flag1 == 0 )
            {
                Buy[ j ] = sigScaleOut;
                BuyPrice[j] = Max( O[j], FirstProfitTarget[j] );
                flag1 = 1;
            }

            if( High[ j ] >= SecondProfitTarget[j] AND !IsEmpty( tl[j] ) AND flag2 == 0 )
            {
                Buy[ j ] = sigScaleOut;
                BuyPrice[j] = Max( O[j], SecondProfitTarget[j] );
                flag2 = 1;
            }

            if( IsEmpty( tl[j] ) AND !IsEmpty( ts[j] ) )
            {
                Sell[j] = 1;
                SellPrice[ j ] = C[j] - slip;
                i = j;
                flag1 = 0;
                flag2 = 0;
                break;
            }

            if( j == BarCount - 1 )
            {
                i = BarCount;
                flag1 = 0;
                flag2 = 0;
                break;
            }
        }
    }
}

SetOption( "InitialEquity", 200000 );
SetOption( "CommissionMode", 3 );
SetOption( "CommissionAmount", 0.006 );
SetOption( "MarginRequirement", 100 );
SetTradeDelays( 0, 0, 0, 0 );
Qty = 20;
SetOption( "maxopenpositions", Qty );

SetChartBkColor( colorBlack );
SetChartOptions( 0, chartShowDates );
GraphXSpace = 10;
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ), IIf( C <= O, ColorRGB( 255, 0, 0 ), colorLightGrey ) ), 64, Null, Null, 0, 0, 1 );
Plot( ts, "", colorRed, styleLine, Null, Null, 0, 0, 1 );
Plot( tl, "", colorBlue, styleLine, Null, Null, 0, 0, 1 );

SetPositionSize( 300, spsShares );
SetPositionSize( 100, spsShares * ( Buy == sigScaleOut ) );

PlotShapes( IIf( Buy == 1, shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 );
PlotShapes( IIf( Buy == 1, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
//PlotShapes( IIf( Buy == sigscalein, shapeUpArrow, shapeNone ), colorlightblue, 0, L, -15 );
//PlotShapes( IIf( Buy == sigscalein, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Buy == sigscaleout, shapeDownArrow, shapeNone ), colorOrange, 0, H, -15 );
PlotShapes( IIf( Buy == sigscaleout, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
PlotShapes( IIf( Sell, shapeSmallCircle, shapeNone ), colorWhite, 0, SellPrice, 0 );
Plot( FirstProfitTarget, "", colorYellow, styleDashed, Null, Null, 0, 0, 1 );
Plot( SecondProfitTarget, "", colorLightBlue, styleDashed, Null, Null, 0, 0, 1 );

Title = Name() +
        " | " + Now( 2 ) +
        " | " + "Timeframe Factor: " + EncodeColor( ColorRGB(	147, 197, 114 ) ) + "  " + fact + "  " + EncodeColor( colorWhite ) + " times the Base Time Frame";
4 Likes

There’s two issues here.

The first is your Buy condition is true on every bar, so FirstProfitTarget is being reassigned each time, which is probably why it’s never hit. So you need to hold its value without change after you enter.

The other issue is, the reason why you’re not seeing FirstProfitTarget in the Explore is it’s a scalar, not an array, which means it only holds a single value each time. The Explore will only show its final value, which is likely unassigned at the end of the loop.

If you want to inspect it for all bars in Explore, you’ll need to turn it into an array by assigning its bar value when you get a buy signal. You’ll also need to hold its value without changing until it’s hit or you get the exit, by copying its value from the previous bar once you’re in a trade. This should get you some way towards both of those:

if (priceatbuy = 0 and Buy[i])
{    FirstProfitTarget[i] = thehhv[i];
     BuyBar = 1;

Then just inside the evaluation condition, get its value from the previous bar (as long as you’re not on the bar that just assigned its initial value for that buy).

if( priceatbuy > 0 ) 
{   if (NOT BuyBar)
    {
        FirstProfitTarget[i] = FirstProfitTarget[i - 1];
    }
    BuyBar = 0;

This will hold it at the value assigned on the Buy. Then from there on, refer to it as FirstProfitTarget[i]

Its bar-by-bar values should then also appear in the Explore.

2 Likes

Actually, on a second look I don’t think that FirstProfitTarget is being reassigned each time. Either way, the approach I’ve given you should be able to help you work out where the issue is.

1 Like

Hi empottasch,

This is really old topic but I like your idea of partial exits at your 1R and 2R. I also have further referenced this article and tried to modify it a bit because I wanted to use a trailing stop. The code runs well and shows up on the chart perfectly. But when running backtest, it does not show the partial exit and the result is only calculated on the last selling point (trailing stop). Can you take a look and help me figure this out.

This is my code as below:

SetChartOptions(1,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( C, "Close", ParamColor("Price Color", colorBlueGrey ), ParamStyle("Price Style",styleCandle|styleNoTitle|styleThick ) | GetPriceStyle() );
Buy = Cross( MA( C, 10 ), MA( C, 50 ) );
Sell = 0;

// the system will exit
// 1/3 of position if FIRST PROFIT TARGET stop is hit
// 1/3 of position is SECOND PROFIT TARGET stop is hit
// 100% of position if TRAILING STOP is hit
per = Param( "per", 20, 1, 150, 1 );
mult = Param( "mult", 2, 1, 4, 0.05 );

TrailingStop = C - mult * ATR( per );
trailARRAY = Null;
trailstop = 0;
FirstProfitTarget = Null;
SecondProfitTarget = Null;
flag1 = 0;
flag2 = 0;
for( i = 0; i < BarCount; i++ )
{
if( Buy[ i ] )
{
priceatbuy = BuyPrice[ i ];
trailstop = TrailingStop[i];
FirstProfitTarget [i] = (BuyPrice[ i ] - TrailingStop[i]) + BuyPrice[ i ]; //1R
SecondProfitTarget[i] = 2* (BuyPrice[ i ] - TrailingStop[i]) + BuyPrice[ i ]; //2R

for ( j = i + 1; j < BarCount; j++ )
    {
    	trailstop = Max( TrailingStop[j], trailstop );
  	trailARRAY[ j ] = trailstop;
  	if( flag1 == 0 ) FirstProfitTarget[j] = FirstProfitTarget[i];
  	if( flag2 == 0 AND flag1 == 1 ) SecondProfitTarget[j] = SecondProfitTarget[i];
  
  	if( flag1 == 0 AND High[ j ] >= FirstProfitTarget [j]  )
  	{
  		// first profit target hit - scale-out
  		flag1 = 1;
  		Buy[ j ] = sigScaleOut;
  		BuyPrice [j] = FirstProfitTarget[j] ;
  	}
  	
  	if( flag2 == 0 AND High[ j ] >= SecondProfitTarget[j]  )
  	{
  		flag2 = 1;
  		Buy[ j ] = sigScaleOut;
  		BuyPrice [j] = SecondProfitTarget[j] ;
  	}	
  	if( Low[ j] <= trailstop )
  	{
  		// trailing stop hit - exit
 			SellPrice[ j ] = Min( Open[ j ], trailstop );
  		Buy[ j ] = 0;
  		Sell[ j ] = 1;
  		flag2 = 0;
  		flag1 = 0;
  		i = j;
  		break;
  	}
  
  	if( j == BarCount - 1 )
        {
            i = BarCount;
            flag1 = 0;
            flag2 = 0;
            break;
        }

  }
}

}
SetTradeDelays( 0, 0, 0, 0 );
SetPositionSize( 30, spsPercentOfEquity );
SetPositionSize( 30, spsPercentOfEquity * ( Buy == sigScaleOut ) );

Plot( trailARRAY,"trailing buy stop level", colorRed );
PlotShapes( IIf( Buy == 1, shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 );
PlotShapes( IIf( Buy == 1, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
//PlotShapes( IIf( Buy == sigscalein, shapeUpArrow, shapeNone ), colorlightblue, 0, L, -15 );
//PlotShapes( IIf( Buy == sigscalein, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Buy == sigscaleout, shapeDownArrow, shapeNone ), colorOrange, 0, H, -15 );
PlotShapes( IIf( Buy == sigscaleout, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
PlotShapes( IIf( Sell, shapeSmallCircle, shapeNone ), colorWhite, 0, SellPrice, 0 );
Buy = ExRem(Buy, Sell);
Sell = ExRem(Sell, Buy);

Plot( FirstProfitTarget, "", colorSeaGreen, styleThick + styleDashed, Null, Null, 0, 0, 1 );
Plot( SecondProfitTarget, "", colorViolet,styleThick + styleDashed, Null, Null, 0, 0, 1 );

Filter = Buy OR Sell;

AddColumn(Buy == sigscaleout,"sigscaleout",1.0);
AddColumn(Sell,"Sell",1.0);

This is how it shows on chart


Backtest results only show entry date and exit date

I tried to figure out by using addcolumn in bottom of my code and here is result

hi, i quickly tested the code I posted in this thread and to see the scale-out and scale-in you need to use "detailed log". So in the "Analysis Settings" window you go to the "Report" tab and then chose "Detailed Log" in the Reporting section.

1 Like

@hungboss1, remove these lines and check again the exploration result.
Moreover, I think that a nested loop is not needed.

1 Like

Thank you, problem solved! And yes that nested loop is a bit complex than necessary because I modified from empottasch code. I tried to make it more simpler but it did not work. So as it has already worked now I just keep it like that.

yes i used to use these nested loops. I have abandoned that although they also work ok in my opinion. Possible I will adjust that code

1 Like

the signal seems to be repeated even though it was reset at the end of the code. Do you have a way to remove it?

not sure what you mean. Below an example of the same code and now avoiding the nested loop. Sofar what I tested it gives the same result as the code posted earlier with the nested loop.

per = Param( "per", 100, 1, 150, 1 );
mult = Param( "mult", 5, 1, 4, 0.05 );

sup = C - mult * ATR( per );
res = C + mult * ATR( per );
trailARRAY = Null;
trailstop = 0;

for( i = 1; i < BarCount; i++ )
{
    if( C[ i ] > trailstop AND C[ i - 1 ] > trailstop )
        trailstop = Max( trailstop, sup[ i ] );
    else
        if( C[ i ] < trailstop AND C[ i - 1 ] < trailstop )
            trailstop = Min( trailstop, res[ i ] );
        else
            trailstop = IIf( C[ i ] > trailstop, sup[ i ], res[ i ] );

    trailARRAY[ i ] = trailstop;
}

ts = IIf( trailArray > C, trailArray, Null );
tl = IIf( trailArray < C, trailArray, Null );

Buy = IsEmpty( ts ) AND !isempty( Ref( ts, -1 ) ) AND !IsEmpty( tl );
Sell = 0;

FirstProfitTarget = Null;
SecondProfitTarget = Null;
slip = 0.00;
inlong = 0;
flag1 = 0;
flag2 = 0;

for( i = 0; i < BarCount; i++ )
{
    if( Buy[ i ] AND inlong == 0 )
    {
        inlong = 1;
        BuyPrice[i] = C[i];
        FirstProfitTarget[i] = BuyPrice[i] + ( BuyPrice[i] - tl[i] );
        SecondProfitTarget[i] = BuyPrice[i] + ( BuyPrice[i] - tl[i] ) * 2;
        idx = i;
    }

    if( inlong == 1 AND flag1 == 0 ) FirstProfitTarget[i] = FirstProfitTarget[idx];

    if( inlong == 1 AND flag2 == 0 AND flag1 == 1 ) SecondProfitTarget[i] = SecondProfitTarget[idx];

    if( High[i] >= FirstProfitTarget[i] AND !IsEmpty( tl[i] ) AND inlong == 1 AND flag1 == 0 )
    {
        Buy[i] = sigScaleOut;
        BuyPrice[i] = Max( O[i], FirstProfitTarget[i] );
        flag1 = 1;
    }

    if( High[i] >= SecondProfitTarget[i] AND !IsEmpty( tl[i] ) AND inlong == 1 AND flag1 == 1 AND flag2 == 0 )
    {
        Buy[i] = sigScaleOut;
        BuyPrice[i] = Max( O[i], SecondProfitTarget[i] );
        flag2 = 1;
    }

    if( IsEmpty( tl[i] ) AND !IsEmpty( ts[i] ) AND inlong == 1 )
    {
        Sell[i] = 1;
        SellPrice[i] = C[i] - slip;
        flag1 = 0;
        flag2 = 0;
        inlong = 0;
    }
}

SetOption( "InitialEquity", 200000 );
SetOption( "CommissionMode", 3 );
SetOption( "CommissionAmount", 0.006 );
SetOption( "MarginRequirement", 100 );
SetTradeDelays( 0, 0, 0, 0 );
SetOption( "maxopenpositions", 20 );

SetChartBkColor( colorBlack );
SetChartOptions( 0, chartShowDates );
GraphXSpace = 10;
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ), IIf( C <= O, ColorRGB( 255, 0, 0 ), colorLightGrey ) ), 64, Null, Null, 0, 0, 1 );
Plot( ts, "", colorRed, styleLine, Null, Null, 0, 0, 1 );
Plot( tl, "", colorBlue, styleLine, Null, Null, 0, 0, 1 );

SetPositionSize( 300, spsShares );
SetPositionSize( 100, spsShares * ( Buy == sigScaleOut ) );

PlotShapes( IIf( Buy == 1, shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 );
PlotShapes( IIf( Buy == 1, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Buy == sigscaleout, shapeDownArrow, shapeNone ), colorOrange, 0, H, -15 );
PlotShapes( IIf( Buy == sigscaleout, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
PlotShapes( IIf( Sell, shapeSmallCircle, shapeNone ), colorWhite, 0, SellPrice, 0 );
Plot( FirstProfitTarget, "", colorYellow, styleDashed, Null, Null, 0, 0, 1 );
Plot( SecondProfitTarget, "", colorLightBlue, styleDashed, Null, Null, 0, 0, 1 );

Title = Name() + " | " + Now( 2 );

1 Like