@vladisld Hey Vlad, thanks again for your help! I've spent some time reading the above (and associated) and I think that it is impossible to achieve what I want without forking. Just thought I would share my findings, let me know if you agree or not.
The reason why lines are only accepting floats is the fact that the array
in the LineBuffer
is an instance of array.array
set to hold double
. So if we create a flag on LineBuffer
, something like is_generic = True
, then inside reset
we can set array
to list
.
def reset(self):
if self.mode == self.QBuffer:
self.array = collections.deque(maxlen=self.maxlen + self.extrasize)
self.useislice = True
elif self.is_generic:
self.array = list()
self.useislice = False
else:
self.array = array.array(str('d'))
self.useislice = False
self.lencount = 0
self.idx = -1
self.extension = 0
The above works. However, we need to inform LineBuffer
which lines are supposed to be generic
. And here starts the painful part. The buffer is instantiated inside Lines
and the Lines
are created inside MetaLineSeries
. The best place to add the information about lines being "generic" is (in my opinion) in the init
method of the Lines
:
for line, linealias in enumerate(self._getlines()):
kwargs = dict()
self.lines.append(LineBuffer(**kwargs))
can be changed to
for line, linealias in enumerate(self._getlines()):
kwargs = dict()
if linealias in genric_lines:
kwargs['is_generic'] = True
self.lines.append(LineBuffer(**kwargs))
However, there is no way (or at least I have not found one) to inject that custom Lines
object into MetaLineSeries
(it is set in the __new__
method via
lines = getattr(cls, 'lines', Lines)
So it means that one will need to re-build the whole structure, from bt.DataBase
(which the data feed inherits from) to LineSeries
to change the pointer inside MetaLinesSeries
from backtrader's original Lines
to the modified ones.
This is doable but it creates a new issue: datafeeds that inherit from the custom LineSeries
do not pass the equality inside the LineSeriesMaker
:
def LineSeriesMaker(arg, slave=False):
if isinstance(arg, LineSeries):
return arg
return LineSeriesStub(arg, slave=slave)
because the arg
is obviously not bt.LineSeries
but myown.LineSeries
.
And the LineSeriesMaker
is actually called as a part of the LineIterator
across all conceptual parts of the framework. And changing LineSeriesMaker
would require updating all those parts (basestrategy, baseindicator, baseobserver, etc.). In this case forking would be much easier and neater but I am somewhat unwilling to go that way.
This is where I am at the moment. TLDR: cannot inject custom LineBuffer()
as a dependency and fork seems to be the only (highly undesirable) way. Any advice?