Confused about closing orders
I have a csv with daily EURUSD OHLC data that I read in using an extension of
bt.feeds.PandasData. I then added an RSI and Stochastic and set up the following simple entry and exit rules:
- Buy entry: 2nd last RSI was below 30 but last RSI was above it.
- Buy exit: Stochastic K line has been above 60 for the last two closed candles AND a crossover took place between K and D lines of the Stochastic.
What I want to achieve is to have multiple RSI entries based on the buy entry condition, and exiting them all as soon as the buy exit condition is met.
Based on the documentation it seemed clear to me that for the buy exit condition I'll need to use the
self.close()function. However, when doing so, and using
cerebro.plot(), I get several sell entries as well, even though I did not add any sell condition logic in my code so far. This made me doubt in the entire approach I have taken.
My full code is below:
class MyPandasData(PandasData): params = ( ('formatted_date', None), ('open', -1), ('high', -1), ('low', -1), ('close', -1), ('adjclose', -1),('volume', -1), ) class MyStrategy(bt.Strategy): def log(self, txt, dt=None): dt = dt or self.datas.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Indicators for the plotting show self.rsi = bt.indicators.RSI(self.datas, period=14) self.stoch = bt.indicators.StochasticSlow(self.datas, period_dslow=5) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enough cash if order.status in [order.Completed]: if order.isbuy(): self.log( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.datas.close) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return # ENTRY CONDITION if self.rsi[-2] < 30 and self.rsi[-1] > 30: self.log('BUY CREATE, %.2f' % self.datas.close) # EXIT CONDITION if self.stoch.percK[-2] > 60 and self.stoch.percK[-1] > 60: if self.stoch.percK[-2] > self.stoch.percD[-2] and self.stoch.percK[-1] < self.stoch.percD[-1]: self.close() self.log(f"BUYEXIT @ %.2f" % self.datas.close) if __name__ == '__main__': df = pd.read_csv(Path(DIR + "/EURUSD_D1.csv"), index_col=0, parse_dates=True) data = MyPandasData(dataname=df) cerebro = bt.Cerebro() cerebro.broker.setcash(10000.0) cerebro.broker.setcommission(commission=0.001) cerebro.addsizer(bt.sizers.PercentSizer, percents=1) cerebro.addstrategy(MyStrategy) cerebro.adddata(data) cerebro.run() cerebro.plot()
This is how my output looks like. The sell orders are clearly visible, even though the code has no
vladisld last edited by
closemethod will just issue a sell/buy order to nullify (close) whatever position you have - so in case of long position the sell order will be issued, vice versa for short one.
BTW, the issued order is returned by the 'close' method - so you may examine what order was issued.