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

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

    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.


    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.

    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.


  • 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.

Log in to reply