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

More on multi-symbol portfolio tracking...



  • For those of us who have a habit of mixing trading with investing :), I thought that a portfolio tracking observer/plot might be of value. Sharing it to solicit feedback and further ideas. A (naive) portfolio below, rebalancing every month to have SPY, QQQ and AGG represent 33% each of the overall portfolio (actually 100% - 5% buffer then 1/3 of that each). The idea is to visualize a portion of each investment in the overall portfolio, so the $CASH line is cash, then SPY line is $CASH+SPY, then QQQ is $CASH+SPY+QQQ etc. It would look better with filled plots (since these are cumulative contributions of each investment to the overall portfolio value), but alas, no controls to fill the plot... Vertical ticks on the bottom represent rebalancing events (trades) --

    Screenshot 2020-12-31 145742.png

    Implementation --

    class PortfolioObserver0(bt.observer.Observer):
    
        _stclock = True
    
        lines = ()
    
        CASH_LINE = '$CASH'
        REBALANCE_LINE = '_REBALANCE'
    
        plotinfo = dict(plot=True, subplot=True, plotlinelabels=True, plotlinevalues=False)
    
        plotlines = dict(_REBALANCE=dict(marker='|', markersize=8.0, color='gray'))
    
        def next(self):        
    
            # add cash
            cumsum = self._owner.broker.get_cash()
            self.set_line(self.CASH_LINE, 0, cumsum)
            
            # add symbol positions
            for data in self.datas:
                dname = data._name
                cumsum += self._owner.broker.get_value([data])
                self.set_line(dname, 0, cumsum)
    
            # is this a rebalancing day?
            if self._owner._orderspending:
                self.set_line(self.REBALANCE_LINE, 0, 0)
    
        def set_line(self, dname, ind, value):
            """Set named line value at index"""
            getattr(self.lines, dname)[ind] = value
    

    ...then --

    def make_portfolio_observer(symbols: tuple):
        """Make portfolio observer with customized list of symbols"""
        return type('PortfolioObserver', (PortfolioObserver0,), {'lines': (symbols + (PortfolioObserver0.CASH_LINE, PortfolioObserver0.REBALANCE_LINE))})
    

    ...then in __main__ --

    symbols = ('SPY', 'QQQ', 'AGG',)   
    cerebro.addobserver(make_portfolio_observer(symbols))
    

    Thoughts? Reinventing the wheel here?



  • ...and an alternative implementation showing % contribution of each asset to overall portfolio value --
    Screenshot 2020-12-31 153450.png

    class PortfolioObserverPercent0(bt.observer.Observer):
    
        _stclock = True
    
        lines = () 
    
        CASH_LINE = '$CASH'
        REBALANCE_LINE = '_REBALANCE'
    
        plotinfo = dict(plot=True, subplot=True, plotlinelabels=True, plotlinevalues=False, plothlines=[100.0])
    
        plotlines = dict(_REBALANCE=dict(marker='|', markersize=8.0, color='gray'))
    
        def next(self):        
    
            # total portfolio value
            tot_value = self._owner.broker.get_value()
    
            # add cash
            cumsum = self._owner.broker.get_cash()
            self.set_line(self.CASH_LINE, 0, cumsum / tot_value * 100)
            
            # add symbol positions
            for data in self.datas:
                dname = data._name
                cumsum += self._owner.broker.get_value([data])  
                self.set_line(dname, 0, cumsum / tot_value * 100)
    
            # is this a rebalancing day?
            if self._owner._orderspending:
                self.set_line(self.REBALANCE_LINE, 0, 0)
    
        def set_line(self, dname, ind, value):
            """Set named line value at index"""
            getattr(self.lines, dname)[ind] = value
    
    
    def make_portfolio_observer_percent(symbols: tuple):
        """Make portfolio observer with customized list of symbols"""
        return type('PortfolioObserverPercent', (PortfolioObserverPercent0,), {'lines': (symbols + (PortfolioObserver0.CASH_LINE, PortfolioObserver0.REBALANCE_LINE))})
    

Log in to reply
 

});