How can I visualize correctly my trades in backtesting.py?

343 views Asked by At

Im trying to backtest a RSI and Bollinger Bands based strategy to a OHCLV BTC dataset. When I plot the strategy, trades do not look like open and close at the given conditions and I really do not understand what's wrong with my code. In particular I want to open a long position and close the short position when the RSI in below 25 and the closing price is below the lowest Bollinger band. Whereas, I want to open a short and close the long position when the price in above the highest Bollinger band and the RSI is above 85.

import pandas as pd
import talib as ta
from backtesting import Backtest, Strategy
from backtesting.lib import crossover

df = pd.read_csv('XBTEUR_60.csv')
df["Date"] = pd.to_datetime(df["Date"], unit="s")
df.set_index('Date', inplace=True)
df = df.rename(columns={'open': 'Open', 'high': 'High', 'low': 'Low', 'close': 'Close', 'volume': 'Volume'})
df = df.drop('trades', axis=1)

#functions variables
alfaL=0.9
alfaS=1.05
timeperiod_BB=20
timeperiod_RSI=14
nbdevup=1
nbdevdn=1

class BollingerBands(Strategy):
    
    #functions variables
    RSI_UB=85
    RSI_LB=25

    def init(self):
        self.BBands = self.I(ta.BBANDS, self.data.Close, timeperiod_BB, nbdevup, nbdevdn)
        self.rsi = self.I(ta.RSI, self.data.Close, timeperiod_RSI)

    def next(self):
        
        if (self.data.Close[-1]>self.BBands[2][-1] and self.rsi[-1]> self.RSI_UB):
            if self.position.is_long or not self.position:
                self.position.close()
                self.sell(size= 0.1, sl=alfaS*self.data.Close[-1])
        
        elif (self.data.Close[-1]<self.BBands[0][-1] and self.RSI_LB> self.rsi[-1]):
            if self.position.is_short or not self.position:
                self.position.close()
                self.buy(sl=alfaL*self.data.Close[-1])


bt = Backtest(df, BollingerBands, cash=10_000, commission=0.00023)
stats = bt.run()

print(stats)

bt.plot()

this is the result when plotting

1

There are 1 answers

0
user14019504 On

Do yourself a favor and calc you signal OUTSIDE the strategy class as a column in your DF that you are going to use. Then you can see if you are getting proper signals. Then run the backtest on the signal for example:

df['signal'] = 0
if (self.data.Close[-1]>self.BBands[2][-1] and self.rsi[-1]> self.RSI_UB):
   df['signal'] = 1 #long
elif (self.data.Close[-1]<self.BBands[0][-1] and self.RSI_LB> self.rsi[-1]):
  df['signal'] = 2 #short

then you can pass it in class BreadthStrat(Strategy):
# atr_f = 0.2 atr_f = 1

def init(self):
    super().init()
    self.signal1 = self.I(SIGNAL)

def next(self):
    super().next()
    for trade in self.trades: 
        if trade.is_long: 
            trade.sl = max(trade.sl or -np.inf, self.data.Close[-1] - self.data.Close[-1] * PER_F)


    if self.signal1==2 and len(self.trades)==0: # trades number change!
        sl1 = self.data.Close[-1] - self.data.Close[-1] * PER_F
        self.buy(sl=sl1)