self.buy() does not create a buy position
-
I have a scenario where I am providing both self.buy() and self.sell() as part of separate buy and sell conditions.
I am noticing the position is not getting created on buy side and the position is getting created on the sell side even though the buy condition fulfils. -
def next(self): self.current_date=self.datetime.date(0) self.current_time=self.datetime.time(0) self.current_datetime=self.datetime.datetime(0) if self.current_time==self.morningtick.time(): self.buycounter=0 self.sellcounter=0 if not self.position: if self.current_time>=self.morningtick.time() and self.current_time<=self.eveningtick.time(): if self.dataclose[0]>self.sma20[0] and self.dataclose[0]>self.sma50[0] and self.buycounter==0: self.log("Entering BUY order:"+str(self.current_datetime)+str(self.dataclose[0])) self.stopbuy=self.datalow[0] self.order=self.buy() self.candletracker=0 print("BUY CANDLETRACKER",self.candletracker) if self.dataclose[0]<self.sma20[0] and self.dataclose[0]<self.sma50[0] and self.sellcounter==0: self.log("Entering SELL order:"+str(self.current_datetime)+str(self.dataclose[0])) self.stopsell=self.datahigh[0] self.order=self.sell() self.candletracker=0 else: self.candletracker+=1 self.log("Candle position:"+str(self.candletracker)) if self.current_time==self.closetime.time(): self.log("Closing current position:"+str(self.current_datetime)+str(self.dataclose[0])) self.close() self.log("Updated balance:"+str(cerebro.broker.getvalue())) if self.order.isbuy(): self.buycounter+=1 print("BUY COUNTER:",self.buycounter) if (self.dataclose[0]<=self.stopbuy) or (self.datalow[0]<=self.stopbuy) or (self.dataopen[0]<=self.stopbuy) or (self.candletracker==self.params.exitbars): self.log("Closing buy position:"+str(self.current_datetime)+str(self.dataclose[0])) self.close() self.log("Updated balance:" + str(cerebro.broker.getvalue())) if self.order.issell(): self.sellcounter+=1 print("SELL COUNTER:",self.sellcounter) if (self.dataclose[0]>=self.stopsell) or (self.datahigh[0]>=self.stopsell) or (self.dataopen[0]>=self.stopsell) or (self.candletracker==self.params.exitbars): self.log("Closing sell position:"+str(self.current_datetime)+str(self.dataclose[0])) self.close() self.log("Updated balance:" + str(cerebro.broker.getvalue()))
-
@bismoy You are probably running out of cash. Try sell first, buy second.
-
@run-out Hi Mate thank you very much.
I did increase the cash limit and buy started triggering.
However stuck in another issue-
Whenever i issue a stop loss order I am unable to go to the next iteration from there.
Also limit order didnt seem to work as i have manually verified the limit order notification timing along with the manual ohlc data for that particular minute and there is no match.Your thoughts on this?
-
if not self.position: if self.current_time>self.secondcandlestop.time() and self.current_time<=self.eveningtick.time() and self.buy_counter==0: self.order=self.buy(exectype=bt.Order.Limit,price=self.maxhigh+2) self.log(self.datetime.datetime()) self.log("BUY ENTERED:"+str(self.maxhigh)) self.buy_counter+=1 self.stoporder=self.sell(exectype=bt.Order.Stop,price=self.minlow-2) else: if self.dataclose[0]-self.maxhigh>=2*(self.maxhigh-self.minlow): self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:"+str(cerebro.broker.getvalue())) if self.current_time==self.closetime.time(): self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:" + str(cerebro.broker.getvalue()))
-
Could you include your logs and the commentary as to where the problem is?
-
@run-out Hi Here you go:-
Code:-
from future import (absolute_import, division, print_function,
unicode_literals)
import backtrader as bt
import datetime as dt
import pandas as pd
import csv
import numpy as np
import talib as ta
import matplotlib.pyplot as plt
from datetime import datetime,time,date,timedeltaclass CommInfo(bt.CommInfoBase):
params=(
('stocklike',False),
('commtype',bt.CommInfoBase.COMM_PERC),) def _getcommission(self, size, price, pseudoexec): return abs(size)*price*self.p.commission*self.p.mult
class FirstStrategy(bt.Strategy):
params=( ('exitbars',12), ) def log(self,txt): print(txt) def notify_order(self, order): if order.status in [order.Submitted,order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): print("BUY TRIGGERED "+str(self.datetime.datetime())+str(" ")+str(self.order.price)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) if order.issell(): #print("BUY EXIT possible price 1 "+str(self.datetime.datetime())+str(self.sellorder.price)) print("BUY EXIT possible price " + str(self.datetime.datetime()) +str(" ") + str(self.stoporder.price)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) self.bar_executed=len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: pass def __init__(self): self.datetime = self.datas[0].datetime self.dataclose = self.datas[0].close self.dataopen = self.datas[0].open self.datahigh = self.datas[0].high self.datalow = self.datas[0].low self.morningtick=datetime.now().replace(hour=9,minute=15,second=0,microsecond=0) self.eveningtick=datetime.now().replace(hour=15,minute=00,second=0,microsecond=0) self.closetime=datetime.now().replace(hour=15,minute=14,second=0,microsecond=0) self.secondcandlestart=datetime.now().replace(hour=9,minute=30,second=0,microsecond=0) self.secondcandlestop=datetime.now().replace(hour=9,minute=44,second=0,microsecond=0) self.stoporder=None self.sellorder=None def next(self): self.current_date=self.datetime.date(0) self.current_time=self.datetime.time(0) self.current_datetime=self.datetime.datetime(0) if self.current_time==self.morningtick.time(): self.highlist=[] self.lowlist=[] self.buy_counter=0 if self.current_time>=self.secondcandlestart.time() and self.current_time<=self.secondcandlestop.time(): self.highlist.append(self.datahigh[0]) self.lowlist.append(self.datalow[0]) self.maxhigh=max(self.highlist) self.minlow=min(self.lowlist) print("Max high",self.maxhigh) print("Min low",self.minlow) if not self.position: if self.current_time>self.secondcandlestop.time() and self.current_time<=self.eveningtick.time() and self.buy_counter==0: self.order=self.buy(exectype=bt.Order.StopLimit,price=self.maxhigh,plimit=self.maxhigh+2) self.log(self.datetime.datetime()) self.log("BUY ENTERED:"+str(self.maxhigh)) self.buy_counter+=1 self.stoporder=self.sell(exectype=bt.Order.StopLimit,price=self.minlow,plimit=self.minlow-2) else: if self.dataclose[0]-self.maxhigh>=2*(self.maxhigh-self.minlow): self.cancel(self.stoporder) self.sellorder=self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:"+str(cerebro.broker.getvalue())) if self.current_time==self.closetime.time(): self.cancel(self.stoporder) self.sellorder=self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:" + str(cerebro.broker.getvalue()))
if name=='main':
cerebro=bt.Cerebro()
commissions=CommInfo(
commission=0,
mult=25,
margin=60000
)
#cerebro.broker.addcommissioninfo(commissions)
cerebro.addstrategy(FirstStrategy)
datapath="D:/Trading/Backtesting_Course/testdata/banknifty2018_1min.csv"
data=bt.feeds.GenericCSVData(
dataname=datapath,
fromdate=dt.datetime(2011, 1, 1),
todate=dt.datetime(2018, 1, 15),
datetime=0,
timeframe=bt.TimeFrame.Minutes,
compression=1,
dtformat=('%Y-%m-%d %H:%M:%S'),
open=1,
high=2,
low=3,
close=4,
volume=None,
openinterest=None,
reverse=False,
header=0
)
cerebro.adddata(data)
# cerebro.adddata(data2)
cerebro.addsizer(bt.sizers.FixedSize, stake=25)
#cerebro.broker.setcommission(commission=0.001)
cerebro.broker.set_cash(2000000.00)
print("Starting portfolio value:" + str(cerebro.broker.getvalue()))
cerebro.run()
print("Final portfolio value:" + str(cerebro.broker.getvalue()))Logs:-
C:\Users\Sonu\AppData\Local\Programs\Python\Python38-32\python.exe C:/Users/Sonu/tradecoder/STA_Assigns_Bismoy/W07D39/2.py
Starting portfolio value:2000000.0
Max high 25599.55
Min low 25595.0
Max high 25599.55
Min low 25586.0
Max high 25599.55
Min low 25583.0
Max high 25599.55
Min low 25583.0
Max high 25599.55
Min low 25580.05
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
Max high 25599.55
Min low 25580.0
2018-01-01 09:45:00
BUY ENTERED:25599.55
BUY TRIGGERED 2018-01-01 10:06:00 25599.55
Updated balance:2000036.25
BUY EXIT possible price 2018-01-01 12:05:00 25580.0
Updated balance:1999511.25
Final portfolio value:1999511.25Process finished with exit code 0
Problems:-
1.As you can see I have different types of exit,it can be a sl/target/time based exit.How to get the exit price in order notification if we dont know which kind of exit will trigger.2.You can see in the logs the iteration stops after day1 itself where as i have given the dates from jan1 to jan 15.
-
@bismoy said in self.buy() does not create a buy position:
if self.current_time==self.morningtick.time():
self.highlist=[]
self.lowlist=[]
self.buy_counter=0When I run your code I'm running into problems with the above section. Now this might be because I'm using different data than you, I don't know, because I can't see your OHLCV and datetimes.
That said, the problem I had is that these variables weren't reset because my data didn't have 9:15.
An alternative and maybe better way is to track the day. You are alread using
self.current_date
. So, only reset the day when the date changes, and then reset your variables above at the same time.if self.datetime.date(0) != self.current_date: # Reset vars and date when date changes. self.highlist=[] self.lowlist=[] self.buy_counter=0 self.current_date = self.datetime.date(0)
By changing the dates this way, you can see the highs/lows changing.
2020-01-02 15:59:00, 15:59:00 == 09:15:00 2020-01-02 15:59:00, Max high: 3239.50, Min low: 3233.75 2020-01-02 16:00:00, 16:00:00 == 09:15:00 2020-01-02 16:00:00, Max high: 3239.50, Min low: 3233.75 2020-01-03 09:31:00, 09:31:00 == 09:15:00 2020-01-03 09:31:00, Max high: 3215.25, Min low: 3209.50 2020-01-03 09:32:00, 09:32:00 == 09:15:00 2020-01-03 09:32:00, Max high: 3219.25, Min low: 3209.50 2020-01-03 09:33:00, 09:33:00 == 09:15:00
I've recreated your code with some logs I use and made a few new ones for your code. Have a look. Not sure if this solves all your problems but might get you closer.
import backtrader as bt import datetime as dt from datetime import datetime class CommInfo(bt.CommInfoBase): params = ( ("stocklike", False), ("commtype", bt.CommInfoBase.COMM_PERC), ) def _getcommission(self, size, price, pseudoexec): return abs(size) * price * self.p.commission * self.p.mult class FirstStrategy(bt.Strategy): params = (("exitbars", 12),) def __init__(self): self.datetime = self.datas[0].datetime self.dataclose = self.datas[0].close self.dataopen = self.datas[0].open self.datahigh = self.datas[0].high self.datalow = self.datas[0].low self.morningtick = datetime.now().replace( hour=9, minute=15, second=0, microsecond=0 ) self.eveningtick = datetime.now().replace( hour=15, minute=00, second=0, microsecond=0 ) self.closetime = datetime.now().replace( hour=15, minute=14, second=0, microsecond=0 ) self.secondcandlestart = datetime.now().replace( hour=9, minute=30, second=0, microsecond=0 ) self.secondcandlestop = datetime.now().replace( hour=9, minute=44, second=0, microsecond=0 ) self.stoporder = None self.sellorder = None def log(self, txt, dt=None): """ Logging function for this strategy""" dt = dt or self.datas[0].datetime.datetime(0) print("%s, %s" % (dt, txt)) def notify_order(self, order): """ Triggered upon changes to orders. """ # Suppress notification if it is just a submitted order. if order.status == order.Submitted: return # Print out the date, security name, order number and status. dt, dn = self.datetime.date(), order.data._name type = "Buy" if order.isbuy() else "Sell" self.log( f"{dn:>7} " f"Order {order.ref:3d},\tType {type},\tStatus {order.getstatusname()} \t" f"Size: {order.created.size:9.4f}, Price: {order.created.price:9.4f}, " ) if order.status == order.Margin: return # Check if an order has been completed if order.status in [order.Completed]: self.log( f"{dn:>7} " f"{'BUY' if order.isbuy() else 'SELL'}, " f"Price: {order.executed.price:6.2f}, " f"Cost: {order.executed.value:6.2f}, " f"Comm: {order.executed.comm:4.2f}, " f"Size: {order.created.size:9.4f}, " ) def start(self): self.current_date = self.datetime.date(0) self.highlist = [] self.lowlist = [] self.buy_counter = 0 def next(self): # self.current_date = self.datetime.date(0) self.current_time = self.datetime.time(0) self.current_datetime = self.datetime.datetime(0) # self.log(f"{self.current_time} == {self.morningtick.time()}") if self.datetime.date(0) != self.current_date: # Reset vars and date when date changes. self.highlist = [] self.lowlist = [] self.buy_counter = 0 self.current_date = self.datetime.date(0) if ( self.current_time >= self.secondcandlestart.time() and self.current_time <= self.secondcandlestop.time() ): self.highlist.append(self.datahigh[0]) self.lowlist.append(self.datalow[0]) self.maxhigh = max(self.highlist) self.minlow = min(self.lowlist) # self.log(f"Max high: {self.maxhigh:7.2f}, Min low: {self.minlow:7.2f}") if not self.position: if ( self.current_time > self.secondcandlestop.time() and self.current_time <= self.eveningtick.time() and self.buy_counter == 0 ): self.order = self.buy( exectype=bt.Order.StopLimit, price=self.maxhigh, plimit=self.maxhigh + 2, ) self.log(self.datetime.datetime()) self.log("BUY ENTERED:" + str(self.maxhigh)) self.buy_counter += 1 self.stoporder = self.sell( exectype=bt.Order.StopLimit, price=self.minlow, plimit=self.minlow - 2, ) else: if self.dataclose[0] - self.maxhigh >= 2 * (self.maxhigh - self.minlow): self.cancel(self.stoporder) self.sellorder = self.close() self.log("BUY CLOSE:" + str(self.dataclose[0])) self.log("Updated balance:" + str(cerebro.broker.getvalue())) if self.current_time == self.closetime.time(): self.cancel(self.stoporder) self.sellorder = self.close() self.log("BUY CLOSE:" + str(self.dataclose[0])) self.log("Updated balance:" + str(cerebro.broker.getvalue())) if __name__ == "__main__": cerebro = bt.Cerebro() # commissions=CommInfo( # commission=0, # mult=25, # margin=60000 # ) cerebro.addstrategy(FirstStrategy) datapath = "data/dev.csv" data = bt.feeds.GenericCSVData( dataname=datapath, fromdate=dt.datetime(2020, 1, 1), todate=dt.datetime(2020, 1, 15), datetime=0, timeframe=bt.TimeFrame.Minutes, compression=1, dtformat=("%Y-%m-%d %H:%M:%S"), open=3, high=1, low=2, close=4, volume=6, openinterest=-1, reverse=False, header=0, ) cerebro.adddata(data) cerebro.addsizer(bt.sizers.FixedSize, stake=25) cerebro.broker.set_cash(2000000.00) print("Starting portfolio value:" + str(cerebro.broker.getvalue())) cerebro.run() print("Final portfolio value:" + str(cerebro.broker.getvalue()))
Here's an order log:
2020-01-02 09:45:00, 2020-01-02 09:45:00 2020-01-02 09:45:00, BUY ENTERED:3239.5 2020-01-02 09:46:00, dev Order 1, Type Buy, Status Accepted Size: 25.0000, Price: 3239.5000, 2020-01-02 09:46:00, dev Order 2, Type Sell, Status Accepted Size: -25.0000, Price: 3233.7500, 2020-01-02 09:47:00, dev Order 1, Type Buy, Status Completed Size: 25.0000, Price: 3239.5000, 2020-01-02 09:47:00, dev BUY, Price: 3239.50, Cost: 80987.50, Comm: 0.00, Size: 25.0000, 2020-01-02 10:12:00, dev Order 2, Type Sell, Status Completed Size: -25.0000, Price: 3233.7500, 2020-01-02 10:12:00, dev SELL, Price: 3233.75, Cost: 80987.50, Comm: 0.00, Size: -25.0000, 2020-01-03 09:45:00, 2020-01-03 09:45:00 2020-01-03 09:45:00, BUY ENTERED:3227.75 2020-01-03 09:46:00, dev Order 3, Type Buy, Status Accepted Size: 25.0000, Price: 3227.7500, 2020-01-03 09:46:00, dev Order 4, Type Sell, Status Accepted Size: -25.0000, Price: 3209.5000, 2020-01-03 09:46:00, dev Order 3, Type Buy, Status Completed Size: 25.0000, Price: 3227.7500, 2020-01-03 09:46:00, dev BUY, Price: 3227.75, Cost: 80693.75, Comm: 0.00, Size: 25.0000, 2020-01-03 15:14:00, BUY CLOSE:3230.25 2020-01-03 15:14:00, Updated balance:1999918.75 2020-01-03 15:15:00, dev Order 4, Type Sell, Status Canceled Size: -25.0000, Price: 3209.5000, 2020-01-03 15:15:00, dev Order 5, Type Sell, Status Accepted Size: -25.0000, Price: 3230.2500, 2020-01-03 15:15:00, dev Order 5, Type Sell, Status Completed Size: -25.0000, Price: 3230.2500, 2020-01-03 15:15:00, dev SELL, Price: 3230.50, Cost: 80693.75, Comm: 0.00, Size: -25.0000, 2020-01-06 09:45:00, 2020-01-06 09:45:00 2020-01-06 09:45:00, BUY ENTERED:3212.75 2020-01-06 09:46:00, dev Order 6, Type Buy, Status Accepted Size: 25.0000, Price: 3212.7500, 2020-01-06 09:46:00, dev Order 7, Type Sell, Status Accepted Size: -25.0000, Price: 3202.0000, 2020-01-06 09:46:00, dev Order 6, Type Buy, Status Completed Size: 25.0000, Price: 3212.7500, 2020-01-06 09:46:00, dev BUY, Price: 3212.75, Cost: 80318.75, Comm: 0.00, Size: 25.0000, 2020-01-06 15:14:00, BUY CLOSE:3230.25 2020-01-06 15:14:00, Updated balance:2000362.5 2020-01-06 15:15:00, dev Order 7, Type Sell, Status Canceled Size: -25.0000, Price: 3202.0000, 2020-01-06 15:15:00, dev Order 8, Type Sell, Status Accepted Size: -25.0000, Price: 3230.2500, 2020-01-06 15:15:00, dev Order 8, Type Sell, Status Completed Size: -25.0000, Price: 3230.2500, 2020-01-06 15:15:00, dev SELL, Price: 3230.25, Cost: 80318.75, Comm: 0.00, Size: -25.0000, 2020-01-07 09:45:00, 2020-01-07 09:45:00 2020-01-07 09:45:00, BUY ENTERED:3231.0 2020-01-07 09:46:00, dev Order 9, Type Buy, Status Accepted Size: 25.0000, Price: 3231.0000, 2020-01-07 09:46:00, dev Order 10, Type Sell, Status Accepted Size: -25.0000, Price: 3222.2500, 2020-01-07 09:46:00, dev Order 10, Type Sell, Status Completed Size: -25.0000, Price: 3222.2500, 2020-01-07 09:46:00, dev SELL, Price: 3222.00, Cost: -80550.00, Comm: 0.00, Size: -25.0000, 2020-01-07 10:59:00, dev Order 9, Type Buy, Status Completed Size: 25.0000, Price: 3231.0000, 2020-01-07 10:59:00, dev BUY, Price: 3231.00, Cost: -80550.00, Comm: 0.00, Size: 25.0000, 2020-01-08 09:45:00, 2020-01-08 09:45:00 2020-01-08 09:45:00, BUY ENTERED:3233.75 2020-01-08 09:46:00, dev Order 11, Type Buy, Status Accepted Size: 25.0000, Price: 3233.7500, 2020-01-08 09:46:00, dev Order 12, Type Sell, Status Accepted Size: -25.0000, Price: 3224.7500, 2020-01-08 09:46:00, dev Order 11, Type Buy, Status Completed Size: 25.0000, Price: 3233.7500, 2020-01-08 09:46:00, dev BUY, Price: 3233.75, Cost: 80843.75, Comm: 0.00, Size: 25.0000, 2020-01-08 15:02:00, BUY CLOSE:3251.75 2020-01-08 15:02:00, Updated balance:2000587.5 2020-01-08 15:03:00, dev Order 12, Type Sell, Status Canceled Size: -25.0000, Price: 3224.7500, 2020-01-08 15:03:00, dev Order 13, Type Sell, Status Accepted Size: -25.0000, Price: 3251.7500, 2020-01-08 15:03:00, dev Order 13, Type Sell, Status Completed Size: -25.0000, Price: 3251.7500, 2020-01-08 15:03:00, dev SELL, Price: 3251.75, Cost: 80843.75, Comm: 0.00, Size: -25.0000, 2020-01-09 09:45:00, 2020-01-09 09:45:00 2020-01-09 09:45:00, BUY ENTERED:3262.75 2020-01-09 09:46:00, dev Order 14, Type Buy, Status Accepted Size: 25.0000, Price: 3262.7500, 2020-01-09 09:46:00, dev Order 15, Type Sell, Status Accepted Size: -25.0000, Price: 3256.7500, 2020-01-09 09:46:00, dev Order 15, Type Sell, Status Completed Size: -25.0000, Price: 3256.7500, 2020-01-09 09:46:00, dev SELL, Price: 3256.50, Cost: -81412.50, Comm: 0.00, Size: -25.0000, 2020-01-09 10:40:00, dev Order 14, Type Buy, Status Completed Size: 25.0000, Price: 3262.7500, 2020-01-09 10:40:00, dev BUY, Price: 3262.75, Cost: -81412.50, Comm: 0.00, Size: 25.0000, 2020-01-10 09:45:00, 2020-01-10 09:45:00 2020-01-10 09:45:00, BUY ENTERED:3272.25 2020-01-10 09:46:00, dev Order 16, Type Buy, Status Accepted Size: 25.0000, Price: 3272.2500, 2020-01-10 09:46:00, dev Order 17, Type Sell, Status Accepted Size: -25.0000, Price: 3264.0000, 2020-01-10 09:46:00, dev Order 17, Type Sell, Status Completed Size: -25.0000, Price: 3264.0000, 2020-01-10 09:46:00, dev SELL, Price: 3264.00, Cost: -81600.00, Comm: 0.00, Size: -25.0000, 2020-01-10 10:06:00, dev Order 16, Type Buy, Status Completed Size: 25.0000, Price: 3272.2500, 2020-01-10 10:06:00, dev BUY, Price: 3272.25, Cost: -81600.00, Comm: 0.00, Size: 25.0000, 2020-01-13 09:45:00, 2020-01-13 09:45:00 2020-01-13 09:45:00, BUY ENTERED:3263.25 2020-01-13 09:46:00, dev Order 18, Type Buy, Status Accepted Size: 25.0000, Price: 3263.2500, 2020-01-13 09:46:00, dev Order 19, Type Sell, Status Accepted Size: -25.0000, Price: 3256.7500, 2020-01-13 09:46:00, dev Order 18, Type Buy, Status Completed Size: 25.0000, Price: 3263.2500, 2020-01-13 09:46:00, dev BUY, Price: 3263.25, Cost: 81581.25, Comm: 0.00, Size: 25.0000, 2020-01-13 15:14:00, BUY CLOSE:3272.75 2020-01-13 15:14:00, Updated balance:2000462.5 2020-01-13 15:15:00, dev Order 19, Type Sell, Status Canceled Size: -25.0000, Price: 3256.7500, 2020-01-13 15:15:00, dev Order 20, Type Sell, Status Accepted Size: -25.0000, Price: 3272.7500, 2020-01-13 15:15:00, dev Order 20, Type Sell, Status Completed Size: -25.0000, Price: 3272.7500, 2020-01-13 15:15:00, dev SELL, Price: 3272.75, Cost: 81581.25, Comm: 0.00, Size: -25.0000, 2020-01-14 09:45:00, 2020-01-14 09:45:00 2020-01-14 09:45:00, BUY ENTERED:3275.25 2020-01-14 09:46:00, dev Order 21, Type Buy, Status Accepted Size: 25.0000, Price: 3275.2500, 2020-01-14 09:46:00, dev Order 22, Type Sell, Status Accepted Size: -25.0000, Price: 3269.2500, 2020-01-14 09:52:00, dev Order 22, Type Sell, Status Completed Size: -25.0000, Price: 3269.2500, 2020-01-14 09:52:00, dev SELL, Price: 3269.25, Cost: -81731.25, Comm: 0.00, Size: -25.0000, 2020-01-14 10:33:00, dev Order 21, Type Buy, Status Completed Size: 25.0000, Price: 3275.2500, 2020-01-14 10:33:00, dev BUY, Price: 3275.25, Cost: -81731.25, Comm: 0.00, Size: 25.0000, Final portfolio value:2000312.5
-
Hi thank you very much :)
I have another doubt where in i noticed the results are not coming as expected and i am unable to validate certain conditions.For the 15 days thing I noticed if i run the code for 1 year it is taking all the dates and if i run it for 15 days it just takes day1.Anyways,I am doing a small code where in I am trying to enter at high of second 15 min bar(9.30-9.44) with low as stoploss.
Viceversa for sell where i enter at low of second 15 min bar with high as stoploss.As of now I am trying with only 2 exits-
Exit at 15:00 which is time_stop or exit when stoploss hitsHowever I also want to get the exact exit price when it happens.As i can see the placement of orders doesn't seem to work as per expectations and i get notifications in each iteration.Also in a day i can have only 2 orders i.e a buy and a sell.If buy side stoploss hits,then no second buy will be initiated for that day and if sell side stoploss hits then no second sell will be initiated for that day.
I have tried to change the code by placing orders.Please find the attached datafile used by me along with the code:-
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import datetime as dt [link text](link url)import pandas as pd import csv import numpy as np import talib as ta import matplotlib.pyplot as plt from datetime import datetime,time,date,timedelta class CommInfo(bt.CommInfoBase): params=( ('stocklike',False), ('commtype',bt.CommInfoBase.COMM_PERC), ) def _getcommission(self, size, price, pseudoexec): return abs(size)*price*self.p.commission*self.p.mult class FirstStrategy(bt.Strategy): params=( ('exitbars',12), ) def log(self,txt): print(txt) def notify_order(self, order): if order.status in [order.Submitted,order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): print(str(self.datetime.datetime(0))+" BUY TRIGGERED "+str(self.datetime.datetime())+str(" ")+str(self.buyorder.price)) self.log("Max high for {} is {}".format(self.current_date,self.ORH)) self.log("Max low for {} is {}".format(self.current_date, self.ORL)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) if order.issell(): #print("BUY EXIT possible price 1 "+str(self.datetime.datetime())+str(self.sellorder.price)) print(str(self.datetime.datetime(0))+" SELL TRIGGERED " + str(self.datetime.datetime()) +str(" ") + str(self.sellorder.price)) self.log("Max high for {} is {}".format(self.current_date, self.ORH)) self.log("Max low for {} is {}".format(self.current_date, self.ORL)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) self.bar_executed=len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: pass def __init__(self): self.datetime = self.datas[0].datetime self.dataclose = self.datas[0].close self.dataopen = self.datas[0].open self.datahigh = self.datas[0].high self.datalow = self.datas[0].low self.morning_start=datetime.now().replace(hour=9,minute=15,second=0,microsecond=0) self.evening_end=datetime.now().replace(hour=14,minute=45,second=0,microsecond=0) self.time_stop=datetime.now().replace(hour=15,minute=00,second=0,microsecond=0) self.secondcandle_start=datetime.now().replace(hour=9,minute=30,second=0,microsecond=0) self.secondcandle_stop=datetime.now().replace(hour=9,minute=44,second=0,microsecond=0) self.current_date=None self.current_time=None self.ORH=None self.ORL=None self.buyorder=None self.sellorder=None self.buystoporder=None self.sellstoporder=None def next(self): self.current_date=self.datetime.date(0) self.current_time=self.datetime.time(0) self.current_datetime=self.datetime.datetime(0) #print(self.current_date) #print(self.current_time) if self.current_time==self.morning_start.time(): self.highlist=[] self.lowlist=[] #self.buy_counter=0 if self.current_time>=self.secondcandle_start.time() and self.current_time<=self.secondcandle_stop.time(): self.highlist.append(self.datahigh[0]) self.lowlist.append(self.datalow[0]) self.ORH=max(self.highlist) self.ORL=min(self.lowlist) if not self.position: self.buyorder=None self.sellorder=None if self.current_time>self.secondcandle_stop.time() and self.current_time<=self.evening_end.time(): self.buyorder=self.buy(exectype=bt.Order.Stop,price=self.ORH,plimit=self.ORH+1) self.buystoporder=self.sell(exectype=bt.Order.StopLimit,price=self.ORL,plimit=self.ORL-1) self.sellorder=self.sell(exectype=bt.Order.Stop,price=self.ORL,plimit=self.ORL-1) self.sellstoporder=self.buy(exectype=bt.Order.StopLimit,price=self.ORH,plimit=self.ORH+1) else: if self.buyorder is not None: if self.current_time==self.time_stop.time(): self.cancel(self.buystoporder) self.close() self.log("BUY EXIT PRICE:"+str(self.close())) if self.sellorder is not None: if self.current_time==self.time_stop.time(): self.cancel(self.sellstoporder) self.close() self.log("SELL EXIT PRICE:"+str(self.close())) ''' if self.dataclose[0]-self.maxhigh>=2*(self.maxhigh-self.minlow): self.cancel(self.stoporder) self.sellorder=self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:"+str(cerebro.broker.getvalue())) if self.current_time==self.closetime.time(): self.cancel(self.stoporder) self.sellorder=self.close() self.log("BUY CLOSE:"+str(self.dataclose[0])) self.log("Updated balance:" + str(cerebro.broker.getvalue())) ''' def stop(self): self.log("Done with processing") if __name__=='__main__': cerebro=bt.Cerebro() commissions=CommInfo( commission=0.001, mult=25, margin=95000 ) cerebro.broker.addcommissioninfo(commissions) cerebro.addstrategy(FirstStrategy) datapath="D:/Trading/Backtesting_Course/testdata/banknifty2018_1min.csv" data=bt.feeds.GenericCSVData( dataname=datapath, fromdate=dt.datetime(2011, 1, 1), todate=dt.datetime(2019, 1, 1), datetime=0, timeframe=bt.TimeFrame.Minutes, compression=1, dtformat=('%Y-%m-%d %H:%M:%S'), open=1, high=2, low=3, close=4, volume=None, openinterest=None, reverse=False, header=0 ) cerebro.adddata(data) # cerebro.adddata(data2) cerebro.addsizer(bt.sizers.FixedSize, stake=1) #cerebro.broker.setcommission(commission=0.001) cerebro.broker.set_cash(1000000.00) print("Starting portfolio value:" + str(cerebro.broker.getvalue())) cerebro.run() print("Final portfolio value:" + str(cerebro.broker.getvalue()))
Please find the below link of the datafile:-
https://drive.google.com/drive/folders/1epAaDQhHZ0IYdfCJvnT3hhgOLSfwJqVF?usp=sharing
-
Also you can see I have tried with the oco order without much luck.Jan1 has run fine but jan2 has triggered a sell without a buy.Objective is to place the stops and targets only when the initial buy has happened.Below is the code snippet:-
from future import (absolute_import, division, print_function,
unicode_literals)
import backtrader as bt
import datetime as dt
import pandas as pd
import csv
import numpy as np
import talib as ta
import matplotlib.pyplot as plt
from datetime import datetime,time,date,timedeltaclass CommInfo(bt.CommInfoBase):
params=(
('stocklike',False),
('commtype',bt.CommInfoBase.COMM_PERC),) def _getcommission(self, size, price, pseudoexec): return abs(size)*price*self.p.commission*self.p.mult
class FirstStrategy(bt.Strategy):
params=( ('exitbars',12), ) def log(self,txt): print(txt) def notify_order(self, order): if order.status in [order.Submitted,order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): print(str(self.datetime.datetime(0))+" BUY TRIGGERED "+str(self.datetime.datetime())+str(" ")+str(order.executed.price)) self.log("Max high for {} is {}".format(self.current_date,self.ORH)) self.log("Max low for {} is {}".format(self.current_date, self.ORL)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) elif order.issell(): #print("BUY EXIT possible price 1 "+str(self.datetime.datetime())+str(self.sellorder.price)) print(str(self.datetime.datetime(0))+" BUY EXIT " + str(self.datetime.datetime()) +str(" ") + str(order.executed.price)) self.log("Max high for {} is {}".format(self.current_date, self.ORH)) self.log("Max low for {} is {}".format(self.current_date, self.ORL)) self.log("Updated balance:" + str(cerebro.broker.getvalue())) self.bar_executed=len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: pass def __init__(self): self.datetime = self.datas[0].datetime self.dataclose = self.datas[0].close self.dataopen = self.datas[0].open self.datahigh = self.datas[0].high self.datalow = self.datas[0].low self.morning_start=datetime.now().replace(hour=9,minute=15,second=0,microsecond=0) self.evening_end=datetime.now().replace(hour=14,minute=45,second=0,microsecond=0) self.time_stop=datetime.now().replace(hour=15,minute=00,second=0,microsecond=0) self.secondcandle_start=datetime.now().replace(hour=9,minute=30,second=0,microsecond=0) self.secondcandle_stop=datetime.now().replace(hour=9,minute=44,second=0,microsecond=0) self.current_date=None self.current_time=None self.ORH=None self.ORL=None self.buyorder=None self.sellorder=None self.buystoporder=None self.sellstoporder=None def next(self): self.current_date=self.datetime.date(0) self.current_time=self.datetime.time(0) self.current_datetime=self.datetime.datetime(0) #print(self.current_date) #print(self.current_time) if self.current_time==self.morning_start.time(): self.highlist=[] self.lowlist=[] self.buy_counter=0 self.buy_exit=0 if self.current_time>=self.secondcandle_start.time() and self.current_time<=self.secondcandle_stop.time(): self.highlist.append(self.datahigh[0]) self.lowlist.append(self.datalow[0]) self.ORH=max(self.highlist) self.ORL=min(self.lowlist) if not self.position: self.buyorder=None self.sellorder=None print("Current DateTime:",self.current_datetime) if self.current_time>self.secondcandle_stop.time() and self.current_time<=self.evening_end.time() and self.buy_counter==0: self.order=self.buy(exectype=bt.Order.Stop,price=self.ORH,plimit=self.ORH+1,valid=0) self.stoporder = self.sell(exectype=bt.Order.StopLimit, price=self.ORL, plimit=self.ORL - 1) self.targetorder=self.sell(exectype=bt.Order.Limit,plimit=self.ORH+2*(self.ORH-self.ORL),oco=self.stoporder) #print(self.order) #print(self.stoporder) #print(self.targetorder) #self.buystoporder=self.sell(exectype=bt.Order.StopLimit,price=self.ORL,plimit=self.ORL-1) self.buy_counter+=1 #self.sellorder=self.sell(exectype=bt.Order.StopLimit,price=self.ORL,plimit=self.ORL-1) #self.sellstoporder=self.buy(exectype=bt.Order.StopLimit,price=self.ORH,plimit=self.ORH+1) else: if self.current_time==self.time_stop.time(): self.cancel(self.stoporder) self.cancel(self.targetorder) self.close() self.log("BUY exit done:"+str(self.close())) self.log("Updated balance:"+str(cerebro.broker.getvalue())) def stop(self): self.log("Done with processing")
if name=='main':
cerebro=bt.Cerebro()
commissions=CommInfo(
commission=0.001,
mult=25,
margin=95000
)
cerebro.broker.addcommissioninfo(commissions)
cerebro.addstrategy(FirstStrategy)
datapath="D:/Trading/Backtesting_Course/testdata/banknifty2018_1min.csv"
data=bt.feeds.GenericCSVData(
dataname=datapath,
fromdate=dt.datetime(2011, 1, 1),
todate=dt.datetime(2019, 1, 1),
datetime=0,
timeframe=bt.TimeFrame.Minutes,
compression=1,
dtformat=('%Y-%m-%d %H:%M:%S'),
open=1,
high=2,
low=3,
close=4,
volume=None,
openinterest=None,
reverse=False,
header=0
)
cerebro.adddata(data)
# cerebro.adddata(data2)
cerebro.addsizer(bt.sizers.FixedSize, stake=1)
#cerebro.broker.setcommission(commission=0.001)
cerebro.broker.set_cash(1000000.00)
print("Starting portfolio value:" + str(cerebro.broker.getvalue()))
cerebro.run()
print("Final portfolio value:" + str(cerebro.broker.getvalue())) -
@bismoy said in self.buy() does not create a buy position:
if not self.position: self.buyorder=None self.sellorder=None if self.current_time>self.secondcandle_stop.time() and self.current_time<=self.evening_end.time(): self.buyorder=self.buy(exectype=bt.Order.Stop,price=self.ORH,plimit=self.ORH+1) self.buystoporder=self.sell(exectype=bt.Order.StopLimit,price=self.ORL,plimit=self.ORL-1) self.sellorder=self.sell(exectype=bt.Order.Stop,price=self.ORL,plimit=self.ORL-1) self.sellstoporder=self.buy(exectype=bt.Order.StopLimit,price=self.ORH,plimit=self.ORH+1) else: if self.buyorder is not None: if self.current_time==self.time_stop.time(): self.cancel(self.buystoporder) self.close() self.log("BUY EXIT PRICE:"+str(self.close())) if self.sellorder is not None: if self.current_time==self.time_stop.time(): self.cancel(self.sellstoporder) self.close() self.log("SELL EXIT PRICE:"+str(self.close()))
Your code has more of logical than coding problems. You are trying to create both buy and sell orders with corresponding stops all at the same time. This is a problem because there is no connectied cause and effect, you can cause yourself all sorts of problems.
I would recommend you use a oco order and just put in the long buy and short sell (oco) orders. No stops. Then when one of the two orders is triggered, the other is immediately cancelled, so you are only left with one valid order.
Then you check in
notify_orders
for completed orders. You alread have some logging there. In the completed section, if is_buy() enter your sell stop, and vice versa for short.You can get specific information in the
notify_orders
about the order usingorder
.For example, you can now find the fill price to set your new stop order.
self.buystoporder = order.exectued.price
.Now you can also check for completed orders for the stops and reset all of your order variables to None at that point. Or you can check at the beginning of next to see it there are no positions and no live orders, then reset your order variables. This free up more trades duing the day.
-
Hi,
Thanks for the above suggestion.I am trying with the oco orders here.However once the order is placed it keeps on going to notify orders and orders completed section after every iteration and repeatedly logs the same information.
Is there any ways to handle that and also while we place the stop orders for buy under order completion & vice versa for sell, do you mean the stop orders should also be oco orders? -
@bismoy said in self.buy() does not create a buy position:
Is there any ways to handle that and also while we place the stop orders for buy under order completion & vice versa for sell, do you mean the stop orders should also be oco orders?
Just place one stop order for the order that completed. -
@bismoy said in self.buy() does not create a buy position:
once the order is placed it keeps on going to notify orders and orders completed section after every iteration and repeatedly logs the same information.
You need to check for open orders and not create new orders if you have open orders and/or open positions.
-
Question is how to check for open orders?
Order.Status in ['Open']?
The thing is I have been trying to cancel all the orders around 3 pm so that my open orders also gets cancelled but without any luck.What I have noticed is for a given day if no trade is triggered as per the ORH levels given by me,then that trade is not getting cancelled and that particular order stays as open and got triggered in next day when price is ORH or more.This particular scenario i encountered in 2nd jan as per the datafile which i have shared with you.The trade gets triggered in the 3rd jan open which shouldn't be the case?
-
@bismoy
Try this beginning of next to cancel live orders:for open_order in [o for o in self.broker.orders if o.status < 4]: self.cancel(open_order)
-
@run-out
Hi,First of all i want to thank you very much for the inputs.I am now able to do the order management and cancel orders as well.But now I find a new issue where in I wish to execute a counter trade.
Suppose i am in a buy and my buy stop is hit (which means a sell is triggered ).Now once buy stop is hit i am issuing a fresh sell order and this stays in submitted-accepted-submitted status when i do a bar by bar backtesting instead of getting filled.
Any thoughts on this?
This is how i coded the notify order after issuing a buy-sell oco order in next()
Notify_order:-
elif order.issell(): if self.buystoporder is None: self.sellstoporder=self.buy(exectype=bt.Order.StopLimit, price=self.ORH, plimit=self.ORH + 1) if self.buystoporder is not None: self.sellorder=self.sell(exectype=bt.Order.Limit,price=self.ORL-1,valid=0)
-
Let me tell the sequence of events for better understanding.
1)Both buy and sell orders are placed with oco.
2)Buy triggers and sell automatically cancels out.Buyorder status is completed and sellorder status is cancelled.
3)Now at this stage buystop order is placed and is in accepted stage.Sellstop order is still None
4)Buystop order gets filled as completed and now i place a sellorder.Here comes the problem,this sell order is staying in submitted status instead of getting filled as completed even if the minute by minute price has been ranged in next candles itself.What could be the reason?
Do i need to set the cancelled status sellorder as None and then issue a fresh sellorder as the buystop is encountered? -
Another thing which i am very much surprised during the bar by bar where i am printing the orders for each min is:-
A sell order gets submitted,then moves to accepted and then again comes back to submitted where as all other orders status remains the same,it is very strange thing -
And then after a series of bars the status of sell order becomes Margin.
Submitted->Accepted->Submitted->MarginAlso the Ref gets changed.What relevance Ref has with respect to orders?