Notify_trade: trade.size is zero at trade closed
-
Hey All,
I've added a new sizer to enable partial contracts to buy based on cash available (crypto space). Algo seems to work fine except that at closed trades the trade.size is printed as zero.
Any thoughts on the reason of this behaviour?
How could I easily get the given trade's quantity, price data?Thanks a lot
here're the main elements:
class maxRiskSizer(bt.Sizer): params = (('risk', 1),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('Risk parameter is not ok!') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy == True: size = (cash * self.p.risk) / data[0] else: size = ((cash * self.p.risk) / data[0]) * -1 return size class SmaCross(bt.Strategy): ... def notify_trade(self, trade): if trade.justopened: print('----TRADE OPENED----') print('Size: {:.3f}, value: {:.3f}'.format(trade.size, trade.value)) elif trade.isclosed: print('----TRADE CLOSED----') print('Profit: {} Gross {}, Net {}'.format(trade.size, round(trade.pnl,2), round(trade.pnlcomm,2))) else: return
This gives the following output:
----TRADE OPENED---- Size: 0.670, value: 9997.320 ----TRADE CLOSED---- Profit: 0.0 Gross 361.16, Net 361.16 ----TRADE OPENED---- Size: 0.728, value: 10361.163 ----TRADE CLOSED---- Profit: 0.0 Gross -802.0, Net -802.0 ----TRADE OPENED---- Size: 0.688, value: 9557.100 ...
-
Seems logical: trade already closed, all sold or covered, now size is equal zero. Why it should be different?
If you want to keep size of the trade after it is closed, then keep size from
trade.open
event. If you are changing trade size, then work with the appropriate orders data - Orders. Or trackposition
size during trading - Position. -
@julianus said in Notify_trade: trade.size is zero at trade closed:
Any thoughts on the reason of this behaviour?
@ab_trader said in Notify_trade: trade.size is zero at trade closed:
If you are changing trade size
The answer by @ab_trader is already pointing out the reason: the size of a trade can change. It would seem that you think a trade is made up solely of a single order, but a
Trade
can have many different sizes from its birth until it dies.See this simple example:
- You open a long trade with size
10
- You sell to reduce the size to
5
- You buy to increase size to
25
- You sell to close the trade (size is
0
) and you actually sell so much with a single order, that you actually open a 2nd (new) trade with size-5
See Docs - Trade
- You open a long trade with size
-
@ab_trader, @backtrader thanks.
What's strange is that other trade subclasses (trade.pnl, trade.pnlcomm) give the correct figure, while trade.value did not at the same call. Or these are handled differently by bt? -
In your code different outputs are called for
tradejust.opened
state andtrade.isclosed
state. So it is impossible to compare outputs fortrade.value
,trade.pnl
andtrade.pnlcomm
for different trade states. Not sure how you did it, probably used another code. Onlytrade.size
appeared in both states, but it is named asProfit
(why?) second time.I am more than sure that
bt
returns correct figures every time, but it is difficult to check correctly due to some inconsistency in the code. -
@julianus said in Notify_trade: trade.size is zero at trade closed:
while trade.value did not at the same call
What is wrong with
trade.value
? You print it once and it shows the value. What are you expecting?You a printing
"Profit: {}"
and usingtrade.size
for it. That's for sure giving the wrong idea when one is reading the output.@julianus said in Notify_trade: trade.size is zero at trade closed:
What's strange is that other trade subclasses (trade.pnl, trade.pnlcomm)
Those are NOT subclasses. They are attributes (call them values if you wish)
-
@backtrader, @ab_trader, thanks for the prompt answer.
I've cleaned the code a little, unfortunately zero still appears ('Profit' stuck there incorrectly during my tries, should've been switched like below).Full code:
from collections import OrderedDict class maxRiskSizer(bt.Sizer): params = (('risk', 1),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('Risk parameter is not ok!') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy == True: size = (cash * self.p.risk) / data[0] else: size = ((cash * self.p.risk) / data[0]) * -1 return size class SmaCross(bt.Strategy): params = ( ('pfast', 15), ('pslow', 100), ('printlog', False), ) def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.datetime(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): self.dataclose = self.datas[0].close self.order = None self.buyprice = None self.buycomm = None self.sma1 = bt.ind.SimpleMovingAverage(self.data.close, period=self.params.pfast) self.sma2 = bt.ind.SimpleMovingAverage(self.data.close, period=self.params.pslow) self.Cross = bt.ind.CrossOver(self.sma1, self.sma2) def next(self): if self.order: return if not self.position: if self.Cross and pd.notna(self.sma1[0] and self.sma2[0]): self.buy() else: if self.Cross == -1: self.close() def notify_trade(self, trade): if trade.justopened: print('----TRADE OPENED----') print('Size: {:.3f}, value: {:.3f}'.format(trade.size, trade.value)) elif trade.isclosed: print('----TRADE CLOSED----') print('Size: {:.3f} Profit: Gross {:.3f}, Net {:.3f}'.format(trade.size, trade.pnl, trade.pnlcomm)) else: return if __name__ == '__main__': startcash = 10000 cerebro = bt.Cerebro() cerebro.addstrategy(SmaCross) modpath = os.path.dirname('D:\\_projectPy\\') datapath = os.path.join(modpath, 'test4.csv') data = bt.feeds.GenericCSVData( dataname=datapath, timeframe=bt.TimeFrame.Minutes, compression=60, datetime=0, open = 1, high = 3, low = 4, close = 2, volume = 5, openinterest = -1, fromdate = datetime(2018, 1, 1, 1, 0, 1), todate = datetime(2018, 1, 20, 0, 0, 1), separator=',', dtformat=('%Y-%m-%d %H:%M:%S') ) cerebro.adddata(data) cerebro.broker.setcash(startcash) cerebro.addsizer(maxRiskSizer, risk=1) strategies = cerebro.run(maxcpus=1)
Output:
----TRADE OPENED---- Size: 0.670, value: 9997.320 ----TRADE CLOSED---- Size: 0.000 Profit: Gross 361.163, Net 361.163 ----TRADE OPENED---- Size: 0.728, value: 10361.163 ----TRADE CLOSED---- Size: 0.000 Profit: Gross -801.999, Net -801.999 ----TRADE OPENED---- Size: 0.688, value: 9557.100 ----TRADE CLOSED---- Size: 0.000 Profit: Gross -496.562, Net -496.562
-
@julianus said in Notify_trade: trade.size is zero at trade closed:
unfortunately zero still appears
And it will always appear. As stated above by @ab_trader and myself: when the trade is closed, it is closed because the size is
0
.You may want to re-elaborate what your problem actually is and what you are missing, because right not it is unclear.
-
@backtrader, ok thanks understood.
I asked this one as the second question in my initial post:
"How could I easily get the given trade's quantity, price data?" -
@ab_trader said in Notify_trade: trade.size is zero at trade closed:
If you want to keep size of the trade after it is closed, then keep size from trade.open event. If you are changing trade size, then work with the appropriate orders data - Orders. Or track position size during trading - Position.
-
@backtrader, ok.
I'm going to deep-dive in the platform once again from the beginning, so then hopefully those questions/topics will be clearer.
Don't you consider having a discord channel for very interactive chats?
Thanks anyway.