Assigning independent value for multi assets
-
Hi all,
I have a multiple data feed strategy and I want to assign the starting cash and value for each and every data in the strategy to be independent in order for my Stop loss/Take Profit strategy to work (Something like
data_d_cash = portfolio_cash * (1/len(datalist)
).I need each data to have its own independent proportion for the stop loss/ take profit to work for each
d
in the strategy below.from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import datetime as dt import pytz import math cn1='XXX' cn2='YYY' datalist = [cn1,cn2] csh=100000 stdt=dt.datetime(2019,07,2,9,30) enddt=dt.datetime(2019,07,2,16,00) SL=0.01 TP=2*SL SU=0.005 SUpct=SU*100 prop=1/len(datalist) #proportion of portfolio batch=10 #rounding entrytime = dt.time(9,45) exittime = dt.time(15,55) stakesize=10 lwbnd=40 upbnd=90 commis=0.05 TPpct=TP*100 SLpct=SL*100 def rounddown(x): return int(math.floor(x / 1)) * 1 class IBCommission(bt.CommInfoBase): """A :class:`IBCommision` charges the way interactive brokers does. """ params = (('stocklike', True), ('commtype', bt.CommInfoBase.COMM_FIXED),) def _getcommission(self, size, price, pseudoexec): return self.p.commission class PropSizer(bt.Sizer): """A position sizer that will buy as many stocks as necessary for a certain proportion of the portfolio to be committed to the position, while allowing stocks to be bought in batches (say, 100)""" params = {"prop": prop, "batch": batch} def _getsizing(self, comminfo, cash, data, isbuy): """Returns the proper sizing""" for i, d in enumerate(self.datas): if isbuy: # Buying target = csh * self.params.prop # Ideal total value of the position price = self.data.close[0] shares_ideal = target / price # How many shares are needed to get target batches = int(shares_ideal / self.params.batch) # How many batches is this trade? shares = batches * self.params.batch # The actual number of shares bought if shares * price > cash: return 0 # Not enough money for this trade else: return shares else: # Selling return self.broker.getposition(d).size # Clear the position class MainSt(bt.Strategy): data_live = False def notify_data(self, data, status, *args, **kwargs): print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args) if status == data.LIVE: self.data_live = True def log(self, txt, dt=None, vlm=None): dt = dt or self.datas[0].datetime.datetime(0) vlm = vlm or self.data.volume[0] print('%s) %s, %s' % (len(self), dt.isoformat(), txt)) def __init__(self): self.order = {} self.buyprice = {} self.buycomm = {} self.bar_executed = {} self.inds = dict() self.o = dict() self.lendata = dict() for i, d in enumerate(self.datas): self.order[d] = None self.buyprice[d] = None self.buycomm[d] = None self.bar_executed[d] = None self.inds[d] = dict() self.inds[d]['sma'] = bt.indicators.SimpleMovingAverage(d.close, period=54) self.inds[d]['rsi'] = bt.indicators.RelativeStrengthIndex(d.close, period=14,safediv=True, upperband=upbnd,lowerband=lwbnd) 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('%s: BUY EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' % (order.data._name, order.executed.price, order.executed.value, order.executed.size, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm self.last_executed_price = order.executed.price self.order = None self.bar_executed = len(self) else: # Sell self.log('%s: SELL EXECUTED, Price: %.2f, Cost: %.2f, Size: %.2f, Comm %.2f' % (order.data._name, order.executed.price, order.executed.value, order.executed.size, order.executed.comm)) self.last_executed_price = order.executed.price self.order = None self.bar_executed = len(self) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('%s Order Canceled/Margin/Rejected' % (order.data._name)) # Write down: no pending order[order.data._name] 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): for i, d in enumerate(self.datas): pv = self.broker.get_value(None) pvd = self.broker.get_value()*prop cshd = self.broker.get_cash()*prop self.stakes = abs(rounddown(pv/d.close[0])) target = csh * prop # Ideal total value of the position price = d.close[0] shares_ideal = pvd / price # How many shares are needed to get target batches = int(shares_ideal / batch) # How many batches is this trade? shares = batches * batch if not self.getposition(d).size: if (pv >= csh*(1+TP)): return if (pv <= csh*(1-SL)): return if (d.datetime.time(-1) >= exittime): return if ((self.inds[d]['rsi'][0] <= lwbnd)and(d.datetime.time(0) >= entrytime)): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: BUY CREATE, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], shares)) self.order = self.buy(data=d, size=shares) else: if (self.inds[d]['rsi'][0] >= upbnd): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: SELL CREATE (RSI>Upbnd), %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size = abs(self.getposition(d).size)) else: if (d.close[0] >= ((self.getposition(d).price*(1+SU)))): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: SELL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SUpct, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size = abs(self.getposition(d).size)) else: if (d.close[0] <= ((self.getposition(d).price*(1-SU)))): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: SELL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SUpct, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size = abs(self.getposition(d).size)) ''' else: if (pvd >= target*(1+TP)): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: TAKE PROFIT VAL CREATE (>%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, TPpct, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size=abs(self.getposition(d).size)) else: if (pvd <= target*(1-SL)): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: STOPLOSS VAL CREATE (<%.2fpct), %.2f, VLM BOUGHT: %.2f' % (d._name, SLpct, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size=abs(self.getposition(d).size)) ''' else: if (d.datetime.time(0) >= exittime): print('%s pv: %.2f, cash:%.2f, rsi: %.2f'% (d._name, pvd, cshd, self.inds[d]['rsi'][0])) self.log('%s: EOD STOP, %.2f, VLM BOUGHT: %.2f' % (d._name, d.close[0], self.getposition(d).size)) self.order = self.sell(data=d, size=abs(self.getposition(d).size)) def runstrat(): # Get a pandas dataframe cerebro = bt.Cerebro() ibstore = bt.stores.IBStore(port=7497, host='127.0.0.1', clientId=12345) #create our data list is_first = True #Loop through the list adding to cerebro. for i in datalist: data = ibstore.getdata(dataname=i,fromdate=stdt, historical =True, useRTH=True, tz = pytz.timezone('US/Eastern'), todate=enddt, timeframe=bt.TimeFrame.Seconds, compression=15) ''' if i in datalist: if is_first: data_main_plot = data is_first = False else: data.plotinfo.plotmaster = data_main_plot else: data.plotinfo.plot = False ''' cerebro.adddata(data) cerebro.broker.setcash(csh) comminfo = IBCommission(commission=commis) cerebro.broker.addcommissioninfo(comminfo) cerebro.addwriter(bt.WriterFile, csv=True, rounding=2, out="C:\\Users\\User\\Desktop\\Backtest Library\\TestResults.csv") start_value = cerebro.broker.getvalue() cerebro.addstrategy(MainSt) # Run over everything cerebro.run() # Plot the result cerebro.plot(volume=False) # Print out the starting conditions print(' ') print('--','Summary','--') print('Start capital: %.2f' % start_value) # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) print('Final Portfolio Cash: %.2f' % cerebro.broker.getcash()) print('Final PnL Value: %.2f' % (cerebro.broker.getvalue()-start_value)) if __name__ == '__main__': runstrat()
Appreciate your help. Thanks!
-
@jabbarabdullah said in Assigning independent value for multi assets:
data_d_cash = portfolio_cash * (1/len(datalist)).
Apply then that in your loop.
-
But that will simply divide the total portfolio amount with number of data feeds right? I was thinking of something like
self.broker.get_value(data=d)
for each asset because my take profit is based on the increase in value of data d
(ie.self.getposition(d).size*d.close[0] >= self.broker.get_cash(d)*(1+take_profit)
). However, we cannot simply assigndata=d
to theget_value
, so I am quite lost now/ Really appreciate your help please.Thank you.
-
Sincerely: you need to make up your mind as to what you want. What you post makes no sense. You probably have an idea about the direction in which you want to go.
If your take-profit/stop-loss is based on the value increase/decrease of an asset you have acquired, record the initial value and exit when the value has gone beyond your limits.