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

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.