My goal is to be able to use a looping trailing stop (say, the Chandelier stop loss) and NOT the ApplyStop() function, whilst back testing with delisted data from Norgate.
My example is one where I set the 1-bar trade delays in my backtesting settings.
The problem without having some code in the SELL criteria of the looping stop loss is that the results present a number of stocks that are held until the end of the back test - with a trade category of "Open Long". This is clearly not right as it impacts the amount of equity available for trading throughout the test period and given the stock delisted it doesn't release these funds as intended.
If you copy code from elsewhere then please add link to the code.
E.g.
/// Original code by amibroker.com at:
/// @link https://www.amibroker.com/kb/2007/03/24/how-to-plot-a-trailing-stop-in-the-price-chart/
/// modified at:
/// @link https://forum.amibroker.com/t/incoporating-looping-trailing-stop-and-closing-trades-in-delisted-symbols/25518/2
StopLevel = 1 - Param("trailing stop %", 3, 0.1, 10, 0.1)/100;
SetTradeDelays(0,0,0,0);
bi = BarIndex();
second_to_lastBar = LastValue(bi)-1;
exitLastBar = bi == second_to_lastBar;
BuyPrice = Open;
Buy = Cross( MACD(), Signal() );
Buy = Ref(Buy, -1);
Sell = 0;
SellSignal = /*your regular sell rules OR*/ exitLastBar;
SellSignal = Ref(SellSignal, -1);
trailARRAY = Null;
trailstop = 0;
for( i = 1; i < BarCount; i++ )
{
if( trailstop == 0 AND Buy[ i ] )
{
trailstop = High[ i ] * stoplevel;
}
else Buy[ i ] = 0; // remove excess buy signals
if( trailstop > 0 AND (Low[ i ] < trailstop OR SellSignal[ i ]))
{
Sell[ i ] = 1;
if ( SellSignal[ i ] )
SellPrice[ i ] = Open[ i ];
else
SellPrice[ i ] = trailstop;
trailstop = 0;
}
if( trailstop > 0 )
{
trailstop = Max( High[ i ] * stoplevel, trailstop );
trailARRAY[ i ] = trailstop;
}
}
Other than that...
Instead of looping you could just use ApplyStop function and instead of Sell = 0; using
/// Incomplete Snippet
/// see here for more
/// @link https://www.amibroker.com/kb/2007/03/24/how-to-plot-a-trailing-stop-in-the-price-chart/
Sell = /*your regular sell rules*/ OR exitLastBar;
ApplyStop( stopTypeTrailing, stopModePercent, StopLevel, True );
Assuming a trade delay of 1 bar, you need to have an "exit" signal on the second last bar to simulate exiting a delisted stock. This will cause AmiBroker to exit the position on the final day of trading. You also want to avoid entering any new positions during the final 2 days.
OnSecondLastBarOfDelistedSecurity = !IsNull(GetFnData("DelistingDate")) AND (BarIndex() == (LastValue(BarIndex()) -1) OR DateTime() >= GetFnData("DelistingDate") ) ;
OnLastTwoBarsOfDelistedSecurity = !IsNull(GetFnData("DelistingDate")) AND (BarIndex() >= (LastValue(BarIndex()) -1) OR DateTime() >= GetFnData("DelistingDate") );
Buy = Buy AND NOT OnLastTwoBarsOfDelistedSecurity;
Sell = Sell OR OnSecondLastBarOfDelistedSecurity;
// If you have a short selling system you will also need to include the following:
Short = Short AND NOT OnLastTwoBarsOfDelistedSecurity;
Cover = Cover OR OnSecondLastBarOfDelistedSecurity;
Your main question was about incorporating regular sell condition into loop. What is part of (regular, non-trailstop) Sell condition is of secondary importance since it is up to you what sell exit you look for there.
There already is trade delay added to loop version!
Also you should not use SetTradeDelays (delay greater zero) with that loop version but Ref() function as I did.
Adding
Sell = Sell OR OnSecondLastBarOfDelistedSecurity;
after loop is incorrect (e.g. it would use trail stop sell price for delisting sell condition and not Open, also trail would not reset).