For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

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!


  • administrators

    @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 assign data=d to the get_value, so I am quite lost now/ Really appreciate your help please.

    Thank you.


  • administrators

    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.


Log in to reply
 

});