Plotting Number of stocks held over time
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 :)
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_longbased 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 = self._owner.num_long
I think this should work.
That's a nice approach. A couple of variations on the topic
class MyStrategy(bt.Strategy): lines = ('numlong',) ...
which avoids using
LineNumby 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])
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.
itemsalways returns a tuple and that evaluates to
True. It should have said
values. The answer has been updated to avoid future miscopying.