Custom backtest that use stats per trade for position sizing

Hi guys,
I am trying to develop a system that use the following formula for Position sizing based on Avg.Profit % and Win rate %:

Position size = Current Equity * X / (-7%)

with X = (2% - Avg. Profit * Win rate)/(1 - Win rate)

Also, I have the following code to open only 1 position during backtest everyday:

limit_daily_entries = 1;

SetCustomBacktestProc( "" );

if( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();	//  Get backtester object
    bo.PreProcess();	//  Do pre-processing (always required)

    for( i = 0; i < BarCount; i++ )	//  Loop through all bars
    {
        count = 0;

        for( sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
        {
            if( sig.IsEntry() )
            {
                if( count < limit_daily_entries )
                    count ++;
                else
                    sig.Price = -1 ; // ignore entry signal
            }
        }

        bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
    }

    bo.PostProcess();	//  Do post-processing (always required)
}

I am still new to custom backtesting, and I have been trying to read a lot of document on this.
The problem is to be able to calculate Win rate % and Avg Profit % of the system up to every trade, while also being able to combine that CBT procedure with the 1 single trade/day code above.

Thank you so much!

You can loop through the closed trade list on each bar to calculate the metrics up to this point in the bar loop and then use the results to adjust entries in the signal loop (along with your other processing) before finally processing the signals.

SetCustomBacktestProc("");
if (Status("action") == actionPortfolio) 
{
    bo = GetBacktesterObject();	
    bo.PreProcess();	
    DetailedLog = GetOption("PortfolioReportMode") == 1;
    dt = DateTime();

    for (i = 0; i < BarCount; i++)	
    {
		if (DetailedLog) bo.RawTextOutput("Bar Date: " + DateTimeToStr( dt[i] ));    
    
		// Loop through trades closed up to this point
		TotalTradePnL = 0;
		TotalWins = 0;
		TradeCount = 0;
		for (trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade())
		{
			TradeCount++;
			
			TradePnL = trade.GetPercentProfit();
			TotalTradePnL += TradePnL;
			
			if (TradePnL > 0)
				TotalWins++;
		}
		
		// if there are closed trades, then do the calculations and use the results
		if (TradeCount > 0)
		{
			WinRateToDate = (TotalWins / TradeCount) * 100;
			AvgPnLToDate = TotalTradePnL / TradeCount;
			
			if (DetailedLog) bo.RawTextOutput("\tWinRateToDate: " + WinRateToDate);
			if (DetailedLog) bo.RawTextOutput("\tAvgPnLToDate: " + AvgPnLToDate);

			for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) )
			{	
				if (sig.IsEntry())
				{
					// Set Pos Size based on values
				}
			}	
		}
        
        bo.ProcessTradeSignals( i );	
    }	  

    bo.PostProcess();	
}

Values are output to the Detailed Log.
image

That should be enough to get you started.

2 Likes

That's absolutely fantastic sir! I am gonna work on this and get back my full code as soon as I finish it. Briliant code.

There are different ways to calculate the Kelly formula, while i am not sure that this is the right way to calculate it , here is a template you can use to further play around with the idea.


SetCustomBacktestProc("");

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
    
    for (i = 0; i < BarCount; i++)	//  Loop through all bars
    {
		winning_trades = 0;
		losing_trades = 0;
		closed_trades = 0;
		luck = 0;
		payoff = 0;
		sumPayoff = 0;
		kelly = 0;
		payoffWIN = 0;
		payoffLose = 0;
		dt = DateTime();
		sumpayoffWIN = 0;
		sumpayoffLose = 0;
		k2 = 0;
		
		for(trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )

		{	
			closed_trades++;
			payoff = trade.getprofit() / trade.GetEntryValue;
			sumPayoff +=payoff;
		
			if(trade.GetPercentProfit > 0)
			{
			winning_trades++ ;
			payoffWIN = trade.getprofit / trade.GetEntryValue;
			sumpayoffWIN += payoffWIN;
			}
			
			if(trade.GetPercentProfit < 0)
			{
			losing_trades++;
			payoffLose = trade.getprofit / trade.GetEntryValue;
			sumpayoffLose +=payoffLose;
			}
		}
	
		Complete_Flip = winning_trades >= 1 AND losing_trades >= 1;
		sumPayoff = sumpayoffWIN /abs(sumpayoffLose);
		luck = winning_trades / closed_trades;
		kelly = IIf ( Complete_Flip >=1 ,kelly = luck - (1 - luck) / sumPayoff,kelly ==0);
		
	
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
    

           if( sig.IsEntry() && sig.IsLong() ) 
                
                bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, IIf(Complete_Flip AND kelly > 0,-(kelly * 100),0.05*bo.Equity ));
    
           if( sig.IsExit() && sig.IsLong() )
                bo.ExitTrade( i, sig.Symbol, sig.Price ); 

        }	
        
        bo.HandleStops( i );	//  Handle programmed stops at this bar
        bo.UpdateStats( i, 2 );	//  Update stats at bar's end
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}

The position size is adjusted after a complete flip of the "coin". IE one losing trade and one winning trade. After that you can use the formula to see how much of a percentage of your equity to invest.
Before the complete flip you can enter any value of your equity for the first few trades.
Again, not sure this is the proper way to calculate it, but that part you can research yourself.
Hope it helps.

1 Like

@constantinpantea and @MacAllan,
You guys' codes have been very helpful for me to figure this out. So I think the following code I write seems to generate the correct outcome that I need. Here it is. Before that, I should explain a few things.

This CBT code aim to generate position size for each trade based on current win rate and avg Win % and some additional system parameters that I aim to optimize (a.k.a system_losers and system_return). For winning trades, my position size should increase, for losing trade, my position size should decrease according to the formula I mentioned in the first post.
I also would like to open only 1 new trade everyday (limit daily entries)
The minimum position size should be 5% equity and maximum 25% equity for each trade. Hence, the following code were built based on everyone's suggestion:

SetCustomBacktestProc("");
limit_daily_entries = 1;

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
    isDetailedReport = GetOption("PortfolioReportMode") == 1;
	dt = DateTime();
	
    for (i = 0; i < BarCount; i++)	//  Loop through all bars
    {	
		if (isDetailedReport) bo.RawTextOutput(NumToStr(dt[i], formatDateTime)+"\t--------");	
		
		winning_trades = 0; //count win trades
		losing_trades = 0; //count lose trades
		closed_trades = 0; //Total number of trades that are closed
		luck = 0; //Win rate in decimal
		payoff = 0; //gain/loss in decimal
		sumPayoff = 0; //Sum of all return in decimal
		payoffWIN = 0; //Gain in decimal
		payoffLose = 0; //Lose in decimal
		dt = DateTime();
		sumpayoffWIN = 0; //Sum of gain in decimal
		sumpayoffLose = 0; //Sum of loss in decimal
		
		system_return = 1; //optimizable
		system_losers = -5; //optimizable
		
		for(trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )

		{	
			closed_trades++;
			payoff = trade.getprofit() / trade.GetEntryValue;
			sumPayoff +=payoff;
		
			if(trade.GetPercentProfit > 0)
			{
			winning_trades++ ;
			payoffWIN = trade.getprofit / trade.GetEntryValue; //i.e: profit $500k / $1M entry = 0.5
			sumpayoffWIN += payoffWIN; //Add up all the profit in decimal
			}
			
			if(trade.GetPercentProfit < 0) //Not necessary in this formula.
			{
			losing_trades++;
			payoffLose = trade.getprofit / trade.GetEntryValue;
			sumpayoffLose +=payoffLose;
			}
		}
	
		Complete_Flip = winning_trades >0 AND losing_trades >0;
		luck = winning_trades / closed_trades; //decimal win rate
		AvgWinPnL = sumpayoffWin / winning_trades; //decimal profit/trade
		
		X = (system_return - AvgWinPnL * 100 * luck)/(1 - luck);
		Link = X / system_losers; //Normally a positive fraction number (2 negative numbers divide)
		Linkvermore = IIf(Link>1,1,IIf(Link<0.1,0.1,Link)); //Limit Linker in the 0.1 to 1 range
		
		start_size = -25;
		min_size = -5;
		all_losers = losing_trades > 0 AND winning_trades == 0;
		
		Linker0 = IIf(Complete_Flip , -25*Linkvermore, start_size);
		Linker = IIf(all_losers, Min_size, Linker0);
		
		//bo.AddCustomMetric("Flip",Complete_Flip);
		bo.AddCustomMetric("Link",Linker);
	
		count = 0;
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
			if( sig.IsEntry() && sig.IsLong() ) 
            {	
				if ( count < limit_daily_entries ) 
				{	count ++;	
					bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price, Linker);
				}
				else
					sig.Price = -1; //ignore entry signal
			}
			
			if( sig.IsExit() && sig.IsLong() )
                bo.ExitTrade( i, sig.Symbol, sig.Price ); 
        }	
        
        //bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
        bo.HandleStops( i );			//  Handle programmed stops at this bar
        bo.UpdateStats( i, 2 );			//  Update stats at bar's end
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}

I think it works wells as intended. However, some problems arise. Here are the problems:

  1. My detail log changed. I no longer can see which position is currently open. At least I can see the date, thanks to @mradtke solution in this post Different Detailed Log after implement CBT
    However, I would also like to see the Open positions like the normal detail log. Do you guys know how I could add this line to the detail log?

  2. My system also implement scale-out. I am not sure how to add that function to my CBT code above.

Thanks a lot to everyone here, I have learned a lot about Amibroker code since I join this forum!

2 Likes

You're using Low-Level CBT, when there's no need to. Mid-Level will do just fine and make life easier for you, including solving issue number 1. To make the change, that means not using bo.EnterTrade and bo.ExitTrade plus bringing bo.ProcessTradeSignals( i ); back in.

Scale outs can be done by looping through the open trade list on each bar and checking for the criteria that you want to use to scale out. The only decision then, is where in the process that should occur - before any other processing, or after the signals have been processed for the current bar. Scale out example:

// Scale outs
for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos())
{
	if (trade.BarsInTrade == 10) // If trade has been open for 10 bars - add your own criteria here.
	{
		bo.ScaleTrade(i, trade.Symbol, False, trade.GetPrice(i, "C"), trade.GetPositionValue() / 2); // Scale out half of position.
	}
}

Here's the full updated mid-level code with the scale outs added after signal processing.

SetCustomBacktestProc("");
limit_daily_entries = 1;

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
    isDetailedReport = GetOption("PortfolioReportMode") == 1;
	dt = DateTime();
	
    for (i = 0; i < BarCount; i++)	//  Loop through all bars
    {	
		if (isDetailedReport) bo.RawTextOutput(NumToStr(dt[i], formatDateTime)+"\t--------");	
		
		winning_trades = 0; //count win trades
		losing_trades = 0; //count lose trades
		closed_trades = 0; //Total number of trades that are closed
		luck = 0; //Win rate in decimal
		payoff = 0; //gain/loss in decimal
		sumPayoff = 0; //Sum of all return in decimal
		payoffWIN = 0; //Gain in decimal
		payoffLose = 0; //Lose in decimal
		dt = DateTime();
		sumpayoffWIN = 0; //Sum of gain in decimal
		sumpayoffLose = 0; //Sum of loss in decimal
		
		system_return = 1; //optimizable
		system_losers = -5; //optimizable
		
		for(trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )

		{	
			closed_trades++;
			payoff = trade.getprofit() / trade.GetEntryValue;
			sumPayoff +=payoff;
		
			if(trade.GetPercentProfit > 0)
			{
			winning_trades++ ;
			payoffWIN = trade.getprofit / trade.GetEntryValue; //i.e: profit $500k / $1M entry = 0.5
			sumpayoffWIN += payoffWIN; //Add up all the profit in decimal
			}
			
			if(trade.GetPercentProfit < 0) //Not necessary in this formula.
			{
			losing_trades++;
			payoffLose = trade.getprofit / trade.GetEntryValue;
			sumpayoffLose +=payoffLose;
			}
		}
	
		Complete_Flip = winning_trades >0 AND losing_trades >0;
		luck = winning_trades / closed_trades; //decimal win rate
		AvgWinPnL = sumpayoffWin / winning_trades; //decimal profit/trade
		
		X = (system_return - AvgWinPnL * 100 * luck)/(1 - luck);
		Link = X / system_losers; //Normally a positive fraction number (2 negative numbers divide)
		Linkvermore = IIf(Link>1,1,IIf(Link<0.1,0.1,Link)); //Limit Linker in the 0.1 to 1 range
		
		start_size = -25;
		min_size = -5;
		all_losers = losing_trades > 0 AND winning_trades == 0;
		
		Linker0 = IIf(Complete_Flip , -25*Linkvermore, start_size);
		Linker = IIf(all_losers, Min_size, Linker0);
		
		//bo.AddCustomMetric("Flip",Complete_Flip);
		bo.AddCustomMetric("Link",Linker);
	
		count = 0;
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
			if( sig.IsEntry() && sig.IsLong() ) 
            {	
				if ( count < limit_daily_entries ) 
				{	
					count ++;	
				}
				else
					sig.Price = -1; //ignore entry signal
			}
			
        }	
        
        bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
        
        // Scale outs
        for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos())
		{
			if (trade.BarsInTrade == 10) // If trade has been open for 10 bars - add your own criteria here.
			{
				bo.ScaleTrade(i, trade.Symbol, False, trade.GetPrice(i, "C"), trade.GetPositionValue() / 2); // Scale out half of position.
			}
		}
        
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}
1 Like

@MacAllan,

Great idea! Thanks to your code, I nailed it exactly the way I want.
I have to clarify though, I did not need to write a loop for scale-out. A much simple solution can be adopt in the main code. Here is my main code for scale-out:

DoScaleOut = RSI(14)>75; //A dummy example
Buy = Buy + sigScaleOut * DoScaleout; 
SetPositionSize( 20, spsPercentOfPosition * ( Buy == sigScaleOut * DoScaleout ) ); //Scale_out 20% of position

Here is the final code, using only mid-level CBT:

SetCustomBacktestProc("");
limit_daily_entries = 1;

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
	
    for (i = 0; i < BarCount; i++)	//  Loop through all bars
    {	
		winning_trades = 0; //count win trades
		losing_trades = 0; //count lose trades
		closed_trades = 0; //Total number of trades that are closed
		luck = 0; //Win rate in decimal
		payoff = 0; //gain/loss in decimal
		sumPayoff = 0; //Sum of all return in decimal
		payoffWIN = 0; //Gain in decimal
		payoffLose = 0; //Lose in decimal
		sumpayoffWIN = 0; //Sum of gain in decimal
		sumpayoffLose = 0; //Sum of loss in decimal
		
		system_return = 1; //optimizable
		system_losers = -5; //optimizable
		
		for(trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )

		{	
			closed_trades++;
			payoff = trade.getprofit() / trade.GetEntryValue;
			sumPayoff +=payoff;
		
			if(trade.GetPercentProfit > 0)
			{
			winning_trades++ ;
			payoffWIN = trade.getprofit / trade.GetEntryValue; //i.e: profit $500k / $1M entry = 0.5
			sumpayoffWIN += payoffWIN; //Add up all the profit in decimal
			}
			
			if(trade.GetPercentProfit < 0) //Not necessary in this formula.
			{
			losing_trades++;
			payoffLose = trade.getprofit / trade.GetEntryValue;
			sumpayoffLose +=payoffLose;
			}
		}
	
		Complete_Flip = winning_trades >0 AND losing_trades >0;
		luck = winning_trades / closed_trades; //decimal win rate
		AvgWinPnL = sumpayoffWin / winning_trades; //decimal profit/trade
		
		X = (system_return - AvgWinPnL * 100 * luck)/(1 - luck);
		Link = X / system_losers; //Normally a positive fraction number (2 negative numbers divide)
		Linkvermore = IIf(Link>1,1,IIf(Link<0.1,0.1,Link)); //Limit Linker in the 0.1 to 1 range
		
		start_size = -25;
		Max_size = -25;
		Min_size = -5;
		all_losers = losing_trades > 0 AND winning_trades == 0;
		
		Linker0 = IIf(Complete_Flip , Max_size * Linkvermore, start_size);
		Linker = IIf(all_losers, Min_size, Linker0);
		
		//bo.AddCustomMetric("Flip",Complete_Flip);
		bo.AddCustomMetric("Link",Linker);
	
		count = 0;
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
			if( sig.IsEntry() && sig.IsLong() ) 
            {	
				if ( count < limit_daily_entries ) 
				{	
					count ++;	
					sig.PosSize = Linker;
				}
				else
					sig.Price = -1; //ignore entry signal
			}
        }	
        bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
        
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}
1 Like

Okay, so I thought the code above solve everything. However, one big problem arise when I try to use the CBT for backtest on 1 ticker 100% of the account.
The problem is that for trades that have Sell signal on the same day of another ticker's buy signal, the backtest system will not count the trade that has the Sell signal as a closed trade.
As the result, my system of calculating the win rate did not include that ticker which has Sell Signal today. Hence, the position size was calculated wrong because it didn't account for the position that close today.

Can someone please help me with this while it seems like minor problem, but actually a big problem for me?

My CBT code is here:

SetCustomBacktestProc("");
limit_daily_entries = 1;

if (Status("action") == actionPortfolio)
{
    bo = GetBacktesterObject();	//  Get backtester object
    
    bo.PreProcess();	//  Do pre-processing
	
    for (i = 0; i < BarCount; i++)	//  Loop through all bars
    {	
		winning_trades = 0; //count win trades
		losing_trades = 0; //count lose trades
		total_trades = 0; //Total number of trades that are closed
		luck = 0; //Win rate in decimal
		payoff = 0; //gain/loss in decimal
		sumPayoff = 0; //Sum of all return in decimal
		payoffWIN = 0; //Gain in decimal
		payoffLose = 0; //Lose in decimal
		sumpayoffWIN = 0; //Sum of gain in decimal
		sumpayoffLose = 0; //Sum of loss in decimal
		
		system_return = 1; //optimizable
		system_losers = -5; //optimizable
		
		for(trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade())
		{	
			total_trades++;
			payoff = trade.getprofit() / trade.GetEntryValue;
			sumPayoff +=payoff;
		
			if(trade.GetPercentProfit > 0)
			{
			winning_trades++ ;
			payoffWIN = trade.getprofit / trade.GetEntryValue; //i.e: profit $500k / $1M entry = 0.5
			sumpayoffWIN += payoffWIN; //Add up all the profit in decimal
			}
			
			if(trade.GetPercentProfit < 0) 
			{
			losing_trades++;
			payoffLose = trade.getprofit / trade.GetEntryValue;
			sumpayoffLose +=payoffLose;
			}
		}
	
		Complete_Flip = winning_trades >0 AND losing_trades >0;
		luck = winning_trades / total_trades; //decimal win rate
		AvgWinPnL = sumpayoffWin / winning_trades; //decimal profit/trade
		
		start_size = -100;
		Max_size = -100;
		Min_portion = 0.1;//Optimizable from 0.1 to 1
		Min_size = -5;
		
		X = (system_return - AvgWinPnL * 100 * luck)/(1 - luck);
		Link = X / system_losers; //Normally a positive fraction number (2 negative numbers divide)
		Linkvermore = IIf(Link>1,1,IIf(Link<Min_portion, Min_portion, Link)); //Limit Linker in the 0.1 to 1 range
		
		all_losers = losing_trades > 0 AND winning_trades == 0;
		
		Linker0 = IIf(Complete_Flip , Max_size * Linkvermore, start_size);
		Linker = IIf(all_losers, Min_size, Linker0);

	
		count = 0;
        for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
			if( sig.IsEntry() && sig.IsLong() ) 
            {	
				if ( count < limit_daily_entries ) 
				{	
					count ++;	
					sig.PosSize = Linker;
				}
				else
					sig.Price = -1; //ignore entry signal
			}
        }	
        bo.ProcessTradeSignals( i );	//  Process trades at bar (always required)
        
    }	//  End of for loop over bars
    
    bo.PostProcess();	//  Do post-processing
}

As you can see in the trade report picture, PLC has sell Signal on the same day with HUT having Buy signal. In that case, my win rate should be 50% and my position size for HUT should be big, and not 5% like that which is the minimal rate I set.
I already use the following line of code as an attempt to solve the problem above

SetOption("SettlementDelay", 1 );

However, I still see my position size for HUT is calculated wrong

linker

Your issue here is that the trades closed on the current bar won't appear in the trade list your looping through until you've triggered bo.ProcessTradeSignals( i );. However, once the signals are processed with that command, your entry signals will also be turned into trades, meaning you lose the ability to adjust or exclude them ahead of time.

The easiest way around this is to insert a second signal loop between the trade loop you have and your current signal loop. The reason for this is, the exit signals for trades exiting on the current bar will also appear in the signal list and return true for sig.IsExit(). So you loop through the closed trade list, then loop through the signal list once, checking for exits and updating your stats from the trade loop, before looping through the signals once again to adjust your entries, and then finally trigger bo.ProcessTradeSignals( i ); where you have it now.

Hope that helps.

1 Like

Hi @MacAllan,

Thanks again for your very kind and helpful comment. I see your point here adding another loop to process exit signal with sig.IsExit()
So my understanding is that I will write another exit loop like this right under my loop through the close trade list:

		for (sig = bo.GetFirstSignal( i ); sig; sig = bo.GetNextSignal( i ) ) //  Loop through all signals at this bar
        {	
			if( sig.IsExit() )
                        {  //some condition 
                        }
        } //Close the loop with exit signal

And then all the formula and loop for 1 entry go under this line.

I wonder then how do I modify this loop to add to the number winning trades or losing trades? Do I have to call the loop for close trades again inside this additional signal loop?

Many thanks!

You can use bo.FindOpenPos() to get the trade object for the open position that's about to exit. Then you can replicate the lines from your earlier trade loop to update your stats (you should also consider putting these lines in a function or procedure and passing in the trade object, to avoid duplication - see DRY).

if (sig.IsExit())
{
	trade = bo.FindOpenPos(sig.Symbol); // Get the trade object for the signal's symbol
	
    // lines replicated from trade loop:
	total_trades++;
	payoff = trade.getprofit() / trade.GetEntryValue;
	sumPayoff +=payoff;

	if(trade.GetPercentProfit > 0)
	{
		winning_trades++ ;
		payoffWIN = trade.getprofit / trade.GetEntryValue; //i.e: profit $500k / $1M entry = 0.5
		sumpayoffWIN += payoffWIN; //Add up all the profit in decimal
	}
	
	if(trade.GetPercentProfit < 0) 
	{
		losing_trades++;
		payoffLose = trade.getprofit / trade.GetEntryValue;
		sumpayoffLose +=payoffLose;
	}
}
1 Like