I am attempting to understand the line by line logic of the ScaleOut example provided by the AmiBroker Users Guide (Portfolio-level back testing). I am hoping that someone can assist... I have copied the code directly from the users guide and attempted to go line by line to understand what is happening within the code. I commented to the right with " //** " followed by my question or guess at what is happening. If anyone is willing to help walk me through, it would be so hugely appreciated!
Buy = Cross( MA( C, 10 ), MA( C, 50 ) );
Sell = 0;
// 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 targets in percent
SecondProfitTarget = 20; // profit targets in percent
TrailingStop = 10; // Trail stop in percent
priceatbuy = 0; //** Is this establishing a baseline in the timeseries? As in the Buy price is timeseries 0?
highsincebuy = 0; //** Again, is this establishing a baseline in the timeseries and once the position moves in profitability, this will be increased?
exit = 0;
for( i = 0; i < BarCount; i++ )
{
if( priceatbuy == 0 AND Buy[ i ] ) //** Is this checking to see that there are no existing positions ("priceatbuy == 0") and that a new buy signal ("Buy[ i ]") has been generated?
{
priceatbuy = BuyPrice[ i ]; //** "Priceatbuy" now becomes the entry price from the buy signal?
}
if( priceatbuy > 0 ) //** Is this checking as to whether price has moved higher from the buy signal?
{
highsincebuy = Max( High[ i ], highsincebuy ); //** Is this establishing the high point for the trailing stop further down in the code? Checking to see the high of today's bar vs the high since buy signal?
if( exit == 0 AND
High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy ) //** Is this saying if there has not been an exit yet ("exit == 0"), and today's high has exceeded the first profit target in %, then scale out?
{
// first profit target hit - scale-out
exit = 1; //** Now the code knows there has been 1 exit so far?
Buy[ i ] = sigScaleOut; //** Can someone explain this line for me? Why is this different than the code for the scale out after "exit = 2" a few lines below?
}
if( exit == 1 AND
High[ i ] >= ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy ) //** Is this saying, if there has already been one exit ("exit == 1") and today's high has exceeded the second profit target in %, then scale out?
{
// second profit target hit - exit
exit = 2; //** Now the code knows there have been 2 exits?
SellPrice[ i ] = Max( Open[ i ], ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy ); //** Establishing execution price of second scale, being that a gap could have occurred beyond the profit target? Why does this code and the code of the first scale out differ?
}
if( Low[ i ] <= ( 1 - TrailingStop * 0.01 ) * highsincebuy ) //** If at any point the low of a bar is less than or equal to the trail stop in % off the highs since the entry?
{
// trailing stop hit - exit
exit = 3; //** Now the code knows there have been 3 exits?
SellPrice[ i ] = Min( Open[ i ], ( 1 - TrailingStop * 0.01 ) * highsincebuy ); //** Establishing execution price of trail stop, being that a gap lower could have occurred beyond the set trail stop percentage?
}
if( exit >= 2 ) //** Confused on why this reads >= to 2... I am assuming this is resetting the code in some way, so shouldnt exit be = 3?
{
Buy[ i ] = 0;
Sell[ i ] = exit + 1; // mark appropriate exit code
exit = 0; //** Is this resetting the code to say that there are no exits as we are no longer in a position?
priceatbuy = 0; //** Is this resetting the code to say that we are no longer in a position?
highsincebuy = 0; //** Resetting the code that there are no highs yet established as there is no open position?
}
}
}
SetPositionSize( 100, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position
Here are answers after your questions:
See //Answer: ... lines
// https://www.amibroker.com/guide/h_pyramid.html
// Questions and answers:
// https://forum.amibroker.com/t/trying-to-understand-multiple-scale-outs-example/27445
Buy = Cross( MA( C, 10 ), MA( C, 50 ) );
Sell = 0;
// 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 targets in percent
SecondProfitTarget = 20; // profit targets in percent
TrailingStop = 10; // Trail stop in percent
//** Is this establishing a baseline in the timeseries? As in the Buy price is timeseries 0?
// Answer: it is initialization of price at Buy (out of trade)
priceatbuy = 0;
//** Again, is this establishing a baseline in the timeseries and once the position moves in profitability, this will be increased?
// Answer: same as before. Initialize highest price since buy
highsincebuy = 0;
exit = 0;
for( i = 0; i < BarCount; i++ )
{
//** Is this checking to see that there are no existing positions
//("priceatbuy == 0") and that a new buy signal ("Buy[ i ]") has been generated?
// Answer: it checks whether being out of trade and
// in addition checking whether there is entry signal at same time/bar of check
if( priceatbuy == 0 AND Buy[ i ] )
{
//** "Priceatbuy" now becomes the entry price from the buy signal?
// Answer: Yes, it stores price at Buy entry to variable priceatbuy.
priceatbuy = BuyPrice[ i ];
}
//** Is this checking as to whether price has moved higher from the buy signal?
//Anwser: it checks whether being in long trade.
if( priceatbuy > 0 )
{
//** Is this establishing the high point for the trailing stop further down in the code?
// Checking to see the high of today's bar vs the high since buy signal?
// Answer: It stores highest high price since Buy entry
highsincebuy = Max( High[ i ], highsincebuy );
//** Is this saying if there has not been an exit yet ("exit == 0"),
//and today's high has exceeded the first profit target in %, then scale out?
// Answer: Yes.
if( exit == 0 AND
High[ i ] >= ( 1 + FirstProfitTarget * 0.01 ) * priceatbuy ) {
// first profit target hit - scale-out
//** Now the code knows there has been 1 exit so far?
// Answer: if statement is true then make exit = 1 from zero.
// and scale out position
exit = 1;
//** Can someone explain this line for me?
//Why is this different than the code for the scale out after "exit = 2" a few lines below?
// Answer: it is just an instruction to not exit completely but to reduce position.
// It is partial exit in profit.
Buy[ i ] = sigScaleOut;
}
//** Is this saying, if there has already been one exit ("exit == 1")
//and today's high has exceeded the second profit target in %, then scale out?
// Answer: No, it says if there has been scaled out of position
// and if second profit level has been reached then exit everything completely
if( exit == 1 AND
High[ i ] >= ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy )
{
// second profit target hit - exit
//** Now the code knows there have been 2 exits?
// Answer: the program just checks statements.
// if statement is true then execute further code inside the statement
// so here 2nd level is hit so set "exit" flag to 2
// so that the program can set Sell signal and reset everything in below statement "if( exit >= 2 )"
exit = 2;
// /** Establishing execution price of second scale,
// being that a gap could have occurred beyond the profit target?
// Why does this code and the code of the first scale out differ?
// Answer: No, it is not a second scale out but regular exit and exit all of the remaining position
// It differs because first one is scale out and this is complete exit.
SellPrice[ i ] = Max( Open[ i ], ( 1 + SecondProfitTarget * 0.01 ) * priceatbuy );
}
//** If at any point the low of a bar is less than or equal to the trail stop in % off the highs since the entry?
// Answer: Yes.
if( Low[ i ] <= ( 1 - TrailingStop * 0.01 ) * highsincebuy )
{
// trailing stop hit - exit
//** Now the code knows there have been 3 exits?
//Answer: similar to exit = 2 but here it is complete exit of remaining position in loss
// so here loss level is hit so set "exit" flag to 3
// so that the program can set Sell signal and reset everything in below statement "if( exit >= 2 )"
exit = 3;
//** Establishing execution price of trail stop, being that a gap lower could have occurred beyond the set trail stop percentage?
// Answer: Yes.
SellPrice[ i ] = Min( Open[ i ], ( 1 - TrailingStop * 0.01 ) * highsincebuy );
}
//** Confused on why this reads >= to 2... I am assuming this is resetting the code in some way, so shouldnt exit be = 3?
// Answer: if there has been set Sell "exit" flags (either in profit "exit = 2" or in loss "exit = 3")
// Then set Sell signal and reset everything else (since we are out of trade)
if( exit >= 2 )
{
Buy[ i ] = 0;
Sell[ i ] = exit + 1; // mark appropriate exit code
//** Is this resetting the code to say that there are no exits as we are no longer in a position?
// Answer: Yes.
exit = 0;
//** Is this resetting the code to say that we are no longer in a position?
//Answer: Yes, resetting price at Buy since we are out of trade
priceatbuy = 0;
//** Resetting the code that there are no highs yet established as there is no open position?
//Answer: Yes, resetting to original since we are out of trade
highsincebuy = 0;
}
}
}
SetPositionSize( 100, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position
@fxshrat massive help!! Thank you my friend, I really appreciate you taking the time. I will work with this and tweak on my end to see if I can fully understand how it flows through to the back test.
@fxshrat sorry to bother, but I have been messing with the code, adjusting the profit targets and the trailing stop % to understand the triggers but something seems to be off.
I back tested for NVDA 5/19/2021 through present as it would be a good example of the different scales after a successful buy signal. If I adjust the profit targets to extreme levels 50%+ in order to see the trail stop functionality, I see that it indeed works. As for the profit targets, it seems to scale all but 1 share of the position, and it does so on a random date (6/3/2021) where the high has not exceeded the initial % profit target as specified in the code... Is there an error in the code or am I missing something? This was straight from the User Guide, only adjustments I made were to the trail stop and profit target numbers. I've attached the analysis as well. Thank you again for your help.
Buy = Cross( MA( C, 10 ), MA( C, 50 ) );
Sell = 0;
// 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 targets in percent
SecondProfitTarget = 20; // profit targets in percent
TrailingStop = 10; // Trail stop 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;
highsincebuy = 0;
}
}
}
SetPositionSize( 100, spsPercentOfEquity );
SetPositionSize( 50, spsPercentOfPosition * ( Buy == sigScaleOut ) ); // scale out 50% of position
Thank you @fxshrat for working through this with me. My apologies but I am still seeing an error in the first target execution price when I go line by line, using the updated code in the post above. If I use the same back test example, NVDA for 5/24/2021 through present, there is an entry on 5/25/2021. That entry price is $157.66. If I look at the code, first profit target is set to +10%, which should be a price of $173.42. That would have been reached on 6/4/2021. The back test does execute a scale out on 6/4/2021, but does so on the open price. This leads me to believe it is looking into the future at that day's high having exceeded the profit target, but executing at the day's open price. If I look at profit target 2 of +20%, it executes correctly on 6/18 at the intraday price of $189.19.
Is there something that needs to be added to the "Buy [ i ] = sigScaleOut" section of the code for the first profit target to execute at the correct price intraday on 6/4/2021?
Thank you again for your help, really trying to make sense of the example