Sizer problem
-
So I tried using an example sizer from Backtest-Rookies and implemented it to my own code
https://backtest-rookies.com/2017/07/24/developing-sizers-backtrader-part-1/
#This is the example code that they provided:
class MaxRiskSizer(bt.Sizer): ''' Returns the number of shares rounded down that can be purchased for the max rish tolerance ''' params = (('risk', 0.03),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('The risk parameter is a percentage which must be' 'entered as a float. e.g. 0.5') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: size = math.floor((cash * self.p.risk) / data[0]) else: size = math.floor((cash * self.p.risk) / data[0]) * -1 return size cerebro.addsizer(MaxRiskSizer, risk=0.5)
...............................................................................................................................................................
I set the risk at (risk = 0.5) , so it should mean I am going to use 50% of the portfolio to enter a trade right?#This is my code(I seperated the stategy class and main):
- Main:
import backtrader as bt import datetime import math from Strategy import TestStrategy cerebro = bt.Cerebro() cerebro.broker.set_cash(100000) cerebro.broker.setcommission(0.01) data = bt.feeds.YahooFinanceCSVData( dataname="oracle.csv", fromdate=datetime.datetime(2000,3,1), todate=datetime.datetime(2000,4,29), reverse=False) class MaxRiskSizer(bt.Sizer): ''' Returns the number of shares rounded down that can be purchased for the max rish tolerance ''' params = (('risk', 0.03),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('The risk parameter is a percentage which must be' 'entered as a float. e.g. 0.5') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: size = math.floor((cash * self.p.risk) / data[0]) else: size = math.floor((cash * self.p.risk) / data[0]) * -1 return size cerebro.adddata(data) #Insert Data. cerebro.addstrategy(TestStrategy) #cerebro.addsizer(bt.sizers.FixedSize, stake=2) cerebro.addsizer(MaxRiskSizer, risk=0.5) print("Starting Portfolio :%.2f" % cerebro.broker.getvalue()) print() cerebro.run() print("Final Portfolio Value:%.2f" % cerebro.broker.getvalue()) cerebro.plot(style="candlestick",barup='green', bardown='red')
- Strategy class :
import backtrader as bt class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # 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]: return # Check if an order has been completed. Broker could reject 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 elif order.issell(): 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 Cancled/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)) print() def next(self): # Simply log the closing price of the series from the reference #self.log('Close, %.2f' % self.dataclose[0]) if self.order: return #If we are not in the market, we might buy. if not self.position: if self.dataclose[0] < self.dataclose[-1]: # current close less than previous close if self.dataclose[-1] < self.dataclose[-2]: # previous close less than the previous previous close # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATED, %.2f' % self.dataclose[0]) self.order = self.buy() else: if len(self) >= (self.bar_executed + 5): self.log("SELL CREATED {}".format(self.dataclose[0])) self.order = self.sell()
...............................................................................................................................................................
Starting Portfolio :100000.002000-03-02, BUY CREATED, 30.47
2000-03-03, BUY EXECUTED,Price: 31.63, Cost: 51873.20, Comm 518.73
2000-03-10, SELL CREATED 36.3
2000-03-13, SELL EXECUTED,Price: 34.91, Cost: 20717.65, Comm 228.66
2000-03-20, SELL CREATED 34.75
2000-03-21, SELL EXECUTED,Price: 34.63, Cost: 30289.80, Comm 349.76
2000-03-21, OPERATION PROFIT, GROSS 5103.40 NET 4014.902000-03-28, SELL CREATED 38.5
2000-03-29, SELL EXECUTED,Price: 38.28, Cost: -52099.08, Comm 520.99
2000-04-05, SELL CREATED 34.8
2000-04-06, SELL EXECUTED,Price: 35.86, Cost: -80577.42, Comm 805.77
2000-04-13, SELL CREATED 31.99
2000-04-14, SELL EXECUTED,Price: 31.10, Cost: -114821.20, Comm 1148.21
2000-04-24, SELL CREATED 32.22
2000-04-25, SELL EXECUTED,Price: 33.30, Cost: -180785.70, Comm 1807.86
Final Portfolio Value:75467.86
...............................................................................................................................................................Problem is:
-
Just on the first buy, my portfolio starts at $100k but it uses $51.8k instead of amount < $50k. (Note: risk is 0.5)
-
Some of the costs are negative. :/
so,
how do I fix the negative, is there something I am missing out or don't understand? -
@Edward-Owen said in Sizer problem:
Just on the first buy, my portfolio starts at $100k but it uses $51.8k instead of amount < $50k. (Note: risk is 0.5)
int(100,000$ x 0.5 / 30.47$ (close price)) * 31.63$ (execution price) = 51,873.2$
-
@Edward-Owen said in Sizer problem:
Some of the costs are negative.
cost = size x price
size
is negative for short position, therforecost
is also negative. -
@ab_trader okay that makes sense
-
@ab_trader said in Sizer problem:
@Edward-Owen said in Sizer problem:
Some of the costs are negative.
cost = size x price
size
is negative for short position, therforecost
is also negative.I am quite new to python and backtrader, can you point me out which code is shorting my trades, I thought that my code only goes long.
-
@Edward-Owen said in Sizer problem:
can you point me out which code is shorting my trades,
if len(self) >= (self.bar_executed + 5): self.log("SELL CREATED {}".format(self.dataclose[0])) self.order = self.sell()
This is what you are doing in your code:
- 03/03 bought 100,000$ x 0.5 / 30.47 = 1,640 shares, 47,608.07$ cash left, long 1640 shares
- 03/13 sold 47,608.07$ x 0.5 / 36.3 = 655 shares, 70,245.46$ cash left, long 985 shares
- 03/21 sold 70,245.64$ x 0.5 / 34.75 = 1,010 shares, closed long position and open short position for 1,010 - 985 = 25 shares
starting from this time every 5 bars you will be adding to short position.
-
thankss!
-
So is this the code to short or exit a trade, im kind of confused.
and sorry but what does len(self) mean?else: if len(self) >= (self.bar_executed + 5): self.log("SELL CREATED %.2f" % self.dataclose[0]) self.order = self.sell()
-
@Gleetche said in Sizer problem:
So is this the code to short or exit a trade, im kind of confused.
this code sells shares/futures. it can (1) decrease existing long position, (2) close existing long position, (3) open new short position or (2) and (3) at the same time.
and sorry but what does len(self) mean?
-
@ab_trader okay that clears it up