Discrepancy with PnL in the Stop function vs TradeAnalyzer Net PnL
-
I'm trying to figure out what I'm doing wrong.
I've been calculating PnL using the Stop function and am switching to using TradeAnalyzer and Returns from the analyzers.
def stop(self): # calculate the actual returns self.roi = (self.broker.get_value() / self.val_start) - 1.0 self.PNL = (self.broker.get_value() - self.val_start ) print('Starting value: {:.4f}'.format(self.val_start)) print('Final value: {:.4f}'.format(self.broker.get_value())) print('PNL: {:.4f}'.format(self.PNL)) print('ROI: {:.4f}%'.format(100.0 * self.roi)) print('\n')
PnL_Net:
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="ta")
PnL: 8441.32, Pnl_Net: 3595.05
PnL: 3455.63, Pnl_Net: -78.39
And then sometimes they two measures of PnL match.
PnL: -3047.4, Pnl_Net: -3047.4Any help would be much appreciated. TIA
-
Your calculation is the full value of the account at the end minus the beginning. The trade list analyzer calculates the pnl of closed trades. Perhaps at the end of your backtests there are open trades?
-
Thank you. That would make sense.
If there is an open trade and price has increased then the value of that trade would be a paper gain in the account. -
Agree - I ran into this as well.
@overcash
My solution was:# if we're backtesting and out of data, close open positions so they get counted properly. # must be done on the 2nd to last, as market orders wait to get another candle, to execute based on open price. if self.position and len(self.data) == self.data.buflen() - 1 and "live" not in self.environment: logger.debug("Closing open position to conclude backtesting") self.close()
-
Thanks for posting. Does it matter where you put that block of code?
-
@overcash apologies, I didn't get a notification of your reply :)
I have that at the end of my stategy's next() method.
-
@manos You rock, thanks for checking back-in. Works great!
-
Great code snippet - thanks
-
@manos would it make a better sense to put it in the stop() method?
-
def stop(self): # if we're backtesting and out of data, close open positions so they get counted properly. # must be done on the 2nd to last, as market orders wait to get another candle, to execute based on open price. for data in self.datas: if self.position and len(self.data) == self.data.buflen() - 1 and "live" not in self.environment: logger.debug("Closing open position to conclude backtesting") self.close(data=d)
-
Errata corr.:
@federico-bld said in Discrepancy with PnL in the Stop function vs TradeAnalyzer Net PnL:
def stop(self): # if we're backtesting and out of data, close open positions so they get counted properly. # must be done on the 2nd to last, as market orders wait to get another candle, to execute based on open price. for data in self.datas: if self.getposition(data) and len(data) == data.buflen() - 1 and "live" not in self.environment: logger.debug("Closing open position to conclude backtesting") self.close(data=data)