Buy at open price and close at close price in the same day
-
I have the following data
date,open,close 19-May-20,155.6,169.78 20-May-20,153.39,149.51 21-May-20,151,153.6
What i want to do is : buy at open price and close at close price in the same day
Expected result2020-05-19, BUY EXECUTED, Price: 155.6, 2020-05-19, SELL EXECUTED, Price: 169.78 2020-05-20, BUY EXECUTED, Price: 153.39 2020-05-20, SELL EXECUTED, Price: 149.51 2020-05-21, BUY EXECUTED, Price: 151 2020-05-21, SELL EXECUTED, Price: 153.6
I have read the section
Cheat-on-open
and an old post
https://community.backtrader.com/topic/1864/a-day-buy-and-close-trade-with-cheat-on-open-and-stop-loss
but I still cant solve the problem.My code:
class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].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 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') self.order = None def next_open(self): self.buy(price=self.data.open[0], coc=False) def next(self): pos = self.getposition() if pos: self.close(price=self.data.close[0], coc=False) cerebro = bt.Cerebro(cheat_on_open=True) cerebro.broker.set_coc(True) ...
The actual outcome:
2020-05-20, BUY EXECUTED, Price: 153.39, Cost: 153.39, Comm 0.00 2020-05-21, SELL EXECUTED, Price: 151.00, Cost: 153.39, Comm 0.00 2020-05-21, BUY EXECUTED, Price: 151.00, Cost: 151.00, Comm 0.00
-
@zevcc-gh said in Buy at open price and close at close price in the same day:
self.close(price=self.data.close[0], coc=False)
you may want to remove
coc=False
from theself.close
.coc=False
deactivatescheat-on-close
for the order.
-
@ab_trader
I have removedcoc=False
from theself.close
but the result is the same
-
@zevcc-gh said in Buy at open price and close at close price in the same day:
but the result is the same
If the results are the same, than
coc=False
was not removed correctly. Results should be different. The approach proposed above works for me. This script buysopen
and sellsclose
on every bar:import backtrader as bt class TestStr(bt.Strategy): def log(self, txt, dt=None): dt = dt or self.data0.datetime.date(0) tt = self.data.datetime.time(0) print('%s, %s, %s' % (dt.isoformat(), tt.isoformat(), txt)) def __init__(self): pass def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, %.2f' % order.executed.price) elif order.issell(): self.log('SELL EXECUTED, %.2f' % order.executed.price) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') 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_open(self): self.buy(coc=False) def next(self): self.log('NEXT o %0.2f, h %0.2f, l %0.2f, c %0.2f' % (self.data.open[0], self.data.high[0], self.data.low[0], self.data.close[0])) if self.position: self.close() cerebro = bt.Cerebro(cheat_on_open=True) cerebro.addstrategy(TestStr) data = ... data feed setup ... cerebro.adddata(data) cerebro.broker.setcash(100000.0) cerebro.broker.set_coc(True) cerebro.run()
-
@ab_trader
I have tried your code, the result is not as expectedcsv file:
date,open,close 19-May-20,155.6,169.78 20-May-20,153.39,149.51 21-May-20,151,153.6
Code:
import backtrader as bt class TestStr(bt.Strategy): def log(self, txt, dt=None): dt = dt or self.data0.datetime.date(0) tt = self.data.datetime.time(0) print('%s, %s, %s' % (dt.isoformat(), tt.isoformat(), txt)) def __init__(self): pass def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, %.2f' % order.executed.price) elif order.issell(): self.log('SELL EXECUTED, %.2f' % order.executed.price) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') 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_open(self): self.buy(coc=False) def next(self): self.log('NEXT o %0.2f, h %0.2f, l %0.2f, c %0.2f' % (self.data.open[0], self.data.high[0], self.data.low[0], self.data.close[0])) if self.position: self.close() cerebro = bt.Cerebro(cheat_on_open=True) cerebro.addstrategy(TestStr) data = btfeeds.GenericCSVData(dataname='test.csv', nullvalue=0.0, dtformat=('%d-%b-%y'), datetime=0, open=1, high=-1, low=-1, close=2, volume=-1, openinterest=-1,) cerebro.adddata(data) cerebro.broker.set_cash(cash=10000) cerebro.broker.set_coc(True) cerebro.run() cerebro.plot()
The actual result:
2020-05-19, 23:59:59.999989, NEXT o 155.60, h 0.00, l 0.00, c 169.78 2020-05-20, 23:59:59.999989, BUY EXECUTED, 153.39 2020-05-20, 23:59:59.999989, NEXT o 153.39, h 0.00, l 0.00, c 149.51 2020-05-21, 23:59:59.999989, SELL EXECUTED, 149.51 2020-05-21, 23:59:59.999989, BUY EXECUTED, 151.00 2020-05-21, 23:59:59.999989, OPERATION PROFIT, GROSS -3.88, NET -3.88 2020-05-21, 23:59:59.999989, NEXT o 151.00, h 0.00, l 0.00, c 153.60
Two problems:
- No trade record on
2020-05-19
- The remaining records are incorrect (the executed date).
I want to execute buy and sell orders in the same day.
For the first problem, I have overridden the
start
method for the record on2020-05-19
, but cannot close the order as welldef start(self): self.buy(coc=False) self.close()
Result:
2020-05-19, 23:59:59.999989, BUY EXECUTED, 155.60 2020-05-19, 23:59:59.999989, NEXT o 155.60, h 0.00, l 0.00, c 169.78 2020-05-20, 23:59:59.999989, SELL EXECUTED, 169.78 2020-05-20, 23:59:59.999989, BUY EXECUTED, 153.39 2020-05-20, 23:59:59.999989, OPERATION PROFIT, GROSS 14.18, NET 14.18 2020-05-20, 23:59:59.999989, NEXT o 153.39, h 0.00, l 0.00, c 149.51 2020-05-21, 23:59:59.999989, SELL EXECUTED, 149.51 2020-05-21, 23:59:59.999989, BUY EXECUTED, 151.00 2020-05-21, 23:59:59.999989, OPERATION PROFIT, GROSS -3.88, NET -3.88 2020-05-21, 23:59:59.999989, NEXT o 151.00, h 0.00, l 0.00, c 153.60
For the second problem, I am really exhausted, I have tried
coc=True/False
,coo=True/False
in different place, but still cannot solve it.
- No trade record on
-
@zevcc-gh orders executed as you want: buy order at open price, sell order at close price. For sell order notification comes next day, but this is how the
cheat-on-close
was implemented. First bar is typically skipped due tobt
internal mechanics.
-
@ab_trader
Thanks! I understand more on howcheat-on-close
works!I have two more problems
- As the sell order notification always comes next day, the graph from
cerebro.plot()
is always "incorrect" (buy/sell symbols are on the wrong places)
I cannot correct the graph without modify the code inbacktrader
- How to handle the last bar? for the last bar, the sell order will not be executed as there is no next bar.
- As the sell order notification always comes next day, the graph from
-
@zevcc-gh as an idea - there is a data feed filter 'DaySplittter_Close
(https://www.backtrader.com/docu/filters-reference/) which returns two sub-bars per each bar of data feed. Using this filter with
cheat-on-openmight help: use
next_open()for operations, and issue
buyorder on the first sub-bar and
sell` order on the second sub-bar. This solution may fix both items for you.