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

Plotting Number of stocks held over time



  • Hi,
    I am hoping to plot the number of stocks held over time on my final output chart.

    Are there any examples of this already?

    I believe I should create an observer, but not sure the best (/easiest) way to do this.

    I am currently logging how many stocks are held in each next() statement under a variable "num_long" which I add 1 unit to whenever a stock iteration has self.broker.getposition(d).size.

    Any examples here would be much appreciated :)

    Thank you!



  • First I would set the counter in the strategy __init__() as series object:

    self.num_long = bt.LineNum(0)
    

    then in the strategy next() I would change value of self.num_long[0] based on the counting rules. And then the following observer can be implemented:

    class StockCounter(bt.Observer):
    
        lines = ('num_long',)
    
        plotinfo = dict(plot=True, subplot=True)
    
        def next(self):
    
            self.lines.num_long[0] = self._owner.num_long[0]
    

    I think this should work.


  • administrators

    That's a nice approach. A couple of variations on the topic

    class MyStrategy(bt.Strategy):
        lines = ('numlong',)
        ...
    

    which avoids using LineNum by integrating the line definition in the definition of the strategy.

    And

    class StockCounter(bt.Observer):
        lines = ('num_long',)
        def __init__(self):
            self.lines.num_long = self._owner.lines.num_long
    

    should also work by establishing a binding between the 2 lines.

    The actual number of holding objects can be quickly calculated in the strategy with:

    holding = len([1 for d, p in self.getpositions() if p.size])
    

  • administrators

    With the latter also being possible as for example

    holding = sum(bool(pos) for pos in self.getpositions().values())
    
    # For 100% equivalence between Python2/3
    from backtrader.utils.py3 import itervalues
    holding = sum(bool(pos) for pos in itervalues(self.getpositions()))
    

    In practical terms it really shouldn't make a difference to use .values() even if that generates a copy in Python2, because the number of items being held is not going to have needed magnitude to matter.

    Updated
    To change items to values



  • Awesome thank you guys!

    @backtrader, when I use my old counting method it works perfectly, however when I use
    holding = sum(bool(pos) for pos in self.getpositions().items()) it always plots 200 as a flat line (i.e. it thinks I am holding every possible stock... so somehow this method is counting everything, not just those in market? Note: I am using Python 3.

    Thanks


  • administrators

    Because items always returns a tuple and that evaluates to True. It should have said values. The answer has been updated to avoid future miscopying.