Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    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...

    General Discussion
    2
    3
    263
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • frontline
      frontline last edited by

      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?

      frontline 1 Reply Last reply Reply Quote 2
      • frontline
        frontline @frontline last edited by

        ...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))})
        
        1 Reply Last reply Reply Quote 1
        • L
          LongminXiao last edited by

          thx for sharing.
          i have been thinking about tracking the performance of different strategies, maybe the observer can also help

          1 Reply Last reply Reply Quote 0
          • 1 / 1
          • First post
            Last post
          Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors