Exit All Trades when Profit > Some Amount

I am trying to exit all trades when the total portfolio amount gets to a certain point. I've tried to write a custom backtest, but it does not generate any results.

Here is the code:

PosSize = 2000;

maxpos =  40; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 50K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 5.0, spsPercentOfEquity );
SetPositionSize( PosSize, spsValue ); 

SetTradeDelays( 0, 0, 0, 0 );
SetOption( "ActivateStopsImmediately", True );

ShortPrice  = Open;
 
Stocks = 

        TimeNum() >= 093000
	AND TimeNum() <= 093100;
         
   
Short  = Stocks;

Cover = 
	TimeNum() >= 155000
    AND TimeNum() <= 160000;

Buy = 0;
Sell = 0;


ApplyStop( stopTypeProfit, stopModePercent, 3.0, 1) ;
ApplyStop( stopTypeLoss,  stopModePercent, 8.0, 1 );
ApplyStop( stopTypeNBar, stopModeBars, 390, ExitAtStop = 0 );

//////////////////////////////////////////////////////////////////////////

SetCustomBacktestProc("");
if (Status("action") == actionPortfolio) {

	bo = GetBacktesterObject();
	bo.PreProcess();

    initEquity = bo.InitialEquity;

    for (i = 0; i < BarCount; i++) {
    
    	if ( bo.Equity - initEquity >= 100 ) {
			for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos()) {
				bo.ExitTrade(i, trade.Symbol, trade.GetPrice(i, "C"), 3);
		    }
        }
        
        bo.HandleStops(i);    	//  Handle programmed stops at this bar
		bo.UpdateStats(i, 1);   //  Update MAE/MFE stats for bar
		bo.UpdateStats(i, 2);   //  Update stats at bar's end
		 
    }
       
    //bo.Backtest();    //  Run backtests
	bo.PostProcess(); 
}

///////////////////////////////////////////////////////////////////////////

@pmfiorini it appears you are trying to write a mid-level CBT. However, you have not called

bo.ProcessTradeSignals(i) ;

inside your main for loop, so no trades are ever being entered.

Also, I would suggest adding these lines to your main AFL so that you're certain AmiBroker is executing your CBT rather than the standard back test, even if you don't change your Analysis Settings:

SetOption("usecustombacktestproc", True);
SetCustomBacktestProc("");
SetBacktestMode(backtestRegular);     // Other backtest modes may be appropriate here
2 Likes
SetOption("usecustombacktestproc", True); 

does the same thing as

SetCustomBacktestProc("");

Since true setting of 2nd argument of SetCustomBacktestProc is default one!

enable = True (default) - enables custom backtesting procedure (the same as SetOption("UseCustomBacktestProc", True );
enable = False - disables custom proc

So if you add SetCustomBacktestProc("") it already does ensure executing CBT.

4 Likes

@fxshrat: good to know, thanks!

1 Like

Hey @fxshrat - Could you take a look at this code...I am trying to exit all trades when the cumulative profit is some amount x. The problem is that it appears it's not computing the cumulative amount correctly. In the code I want to:

  1. Compute current profit of ALL trades using trade.GetProfit() function
  2. Exit All when sum > some amount when Sum( trade.GetProfit() > some amount)

Thanks...

PosSize = 2000;

maxpos =  40; // maximum number of open positions
SetOption("InitialEquity", 100000 ); // set initial equity = 50K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 5.0, spsPercentOfEquity );
SetPositionSize( PosSize, spsValue ); 

SetTradeDelays( 0, 0, 0, 0 );
SetOption( "ActivateStopsImmediately", True );

ShortPrice  = Open;
 
Stocks = 

        TimeNum() >= 093000
	AND TimeNum() <= 093100;
         
   
Short  = Stocks;

Cover = 
	TimeNum() >= 155000
AND TimeNum() <= 160000;

Buy = 0;
Sell = 0;


ApplyStop( stopTypeProfit, stopModePercent, 3.0, 1) ;
ApplyStop( stopTypeLoss,  stopModePercent, 8.0, 1 );
ApplyStop( stopTypeNBar, stopModeBars, 390, ExitAtStop = 0 );

//////////////////////////////////////////////////////////////////////////

SetOption("usecustombacktestproc", True);
SetCustomBacktestProc("");
SetBacktestMode(backtestRegular);     // Other backtest modes may be appropriate here

SetCustomBacktestProc( "" );
if ( Status( "action" ) == actionPortfolio ) {
	bo = GetBacktesterObject();
	bo.PreProcess();
	//bo.Backtest(1);

	totProfit = 0.0;

	for ( i = 0; i < BarCount; i++ ) {		
		
                // Compute profitability of ALL current trades here...
		totProfit = 0.0;
		for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) {
			totProfit += trade.GetProfit();
		}		
		
                // Exit if sum of all trades > some amount
		if ( totProfit >= 500 ) {
			for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos()) {
				bo.ExitTrade(i, trade.Symbol, trade.GetPrice(i, "C"), 3);
			}
		}
		bo.ProcessTradeSignals( i );
	}  
	
	//totProfit = 0.0;
	for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) {
		trade.AddCustomMetric( "Tot. Profit", totProfit );
	}
	
	//bo.ListTrades();
	bo.PostProcess(); 
}

@pmfiorini, how do you know that your AFL is not computing cumulative profit correctly? I would advise adding some _TRACE() statements so that you can actually get some insight into how the code is behaving. That will also allow you to ask more specific questions.

2 Likes

I'll look at trace - thanks

Ok - looking at the _Trace() statements worked...after testing, it appears this code works to the best of my knowledge. It also includes Low/High bounding for trade Entries/Exits price points for more accurate modeling due to some quirky thing with AmiBroker that incorporate trades into its analysis that are not possible (please refer to this thread: https://forum.amibroker.com/t/buystop-estimatedlow/7376/17) - Thanks to @fxshrat for the Low/High bounding codes...

PosSize = 2000;

maxpos =  40; // maximum number of open positions
SetOption("InitialEquity", 75000 ); // set initial equity = 50K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 5.0, spsPercentOfEquity );
SetPositionSize( PosSize, spsValue ); 


SetTradeDelays( 0, 0, 0, 0 );
SetOption( "ActivateStopsImmediately", True );

ShortPrice  = Open * 1.000;
 
Stocks = 

	    Open > MA( Open, 20 )
	AND Open > MA( Open, 50 )
	AND Open > MA( Open, 200 )
	
	AND TimeNum() >= 093000
	AND TimeNum() <= 093100;
	        
   
Short  = Stocks;

Cover = 

	TimeNum() >= 094500
    AND TimeNum() <= 094600;

Buy = 0;
Sell = 0;

ApplyStop( stopTypeProfit, stopModePercent, 2.0, 1) ;
ApplyStop( stopTypeLoss,  stopModePercent, 8.0, 1 );
ApplyStop( stopTypeNBar, stopModeBars, 390, ExitAtStop = 0 );

//////////////////////////////////////////////////////////////////////////

SetOption("usecustombacktestproc", True);
SetCustomBacktestProc("");
SetBacktestMode(backtestRegular);     // Other backtest modes may be appropriate here

StaticVarSet( "L_" + Name(), L );
StaticVarSet( "H_" + Name(), H );

if ( Status( "action" ) == actionPortfolio ) {

	bo = GetBacktesterObject();
	bo.PreProcess();
	//bo.Backtest(1);

	totProfit = 0.0;

	for ( i = 0; i < BarCount; i++ ) {		
	
		for ( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) {
			if ( sig.IsEntry ) {
				_L = StaticVarGet( "L_" + sig.Symbol );	
				_H = StaticVarGet( "H_" + sig.Symbol );				
				if ( sig.Price <= _L[i] || sig.Price >= _H[i] ) {
					sig.Price = -1; //sig.PosSize = 0;	
				}				
			} 
		}

		totProfit = 0.0; maxProfit = 0.0;
		for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) {
			totProfit += trade.GetProfit();
			if ( totProfit > maxProfit ) {
				maxProfit = totProfit;
			}
			//if ( maxProfit >= 500 )
			//	break;
			_TRACE("maxProfit: " + NumToStr( maxProfit ) ); 
		}
		if ( maxProfit >= 200 ) {
			//_TRACE("maxProfit: " + NumToStr( maxProfit ) ); 
			for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) {
				//_TRACE("Made it here...");
				//_TRACE("trade.GetPrice(i, C): " + NumToStr( trade.GetPrice(i, "C") ) ); 
				bo.ExitTrade(i, trade.Symbol, trade.GetPrice(i, "C"), 3);
			}	
		}
		bo.ProcessTradeSignals( i );
	}  
	
	//totProfit = 0.0;
	for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) {
		trade.AddCustomMetric( "Tot. Profit", totProfit );
	}
	
	for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) {
		_H = StaticVarGet( "H_" + trade.Symbol );
		_L = StaticVarGet( "L_" + trade.Symbol );
		trade.AddCustomMetric( "Entry Diff", Lookup((trade.EntryPrice - _L), trade.EntryDateTime) );
		trade.AddCustomMetric( "Exit Diff", Lookup((_H - trade.ExitPrice), trade.ExitDateTime) ); 
	}

	for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) {
		_H = StaticVarGet( "H_" + trade.Symbol );
		//_L = StaticVarGet( "L_" + trade.Symbol );
		trade.AddCustomMetric( "Entry", Lookup((trade.EntryPrice - _L), trade.EntryDateTime) );
		//trade.AddCustomMetric( "Exit", Lookup((_H - trade.ExitPrice), trade.ExitDateTime) ); 
	}
	
	//bo.ListTrades();
	bo.PostProcess(); 
}
1 Like