Settings lines and params on __init__



  • Ok, for my factor and index strategy I have created a Feed like this:

    class MultiFactorFeed(bt.feeds.GenericCSVData):
    
        factors = ("DIV_YIELD", "EBITDA", "EPS")
        indices = ("SP50", "DOW")
    
        lines = factors + indices
    
        params = (
            ('dtformat', '%Y-%m-%d'),
            # This avoids time adjustment to the end of the session
            ('timeframe', bt.TimeFrame.Minutes),
    
            ('datetime', 0),
            ('time', -1),
            ('open', 1),
            ('high', 1),
            ('low', 1),
            ('close', 1),
            ('volume', -1),
            ('openinterest', -1)
        ) + tuple((el, i + 2) for i, el in enumerate(lines))
    

    Explanation is simple:

    • "factors" cols contain the additional data items, beyond price, for my multi-factor strategy
    • "indices" cols contain the market index membership, in binary. 1 means that equity A is in index B at time T. 0 means it is not.
    • I use daily price data, no time portion (-1), only with close price (all to position 1), without volume (-1) or open interest (-1).
    • All the other columns starting from 2 are first factors, then indices.

    A few questions:

    1. Is there anyway to make MultiFactorFeed more abstract, so that I could pass factors and indices on init and reuse the class when I change factor or index composition? There seems to be a lot of MetaClass black magic that interferes with that. Something like this fails:
    class MultiFactorFeed(bt.feeds.GenericCSVData):
    
        def __init__(self, dataname=dataname, name=name, factors=factors, indices=indices):
            self.factors = factors
            self.indices = indices
    
            self.lines = factors + indices
    
            self.params = (
                         ('dtformat', '%Y-%m-%d'),
                         # This avoids time adjustment to the end of the session
                         ('timeframe', bt.TimeFrame.Minutes),
    
                         ('datetime', 0),
                         ('time', -1),
                         ('open', 1),
                         ('high', 1),
                         ('low', 1),
                         ('close', 1),
                         ('volume', -1),
                         ('openinterest', -1)
                     ) + tuple((el, i + 2) for i, el in enumerate(self.lines))
            
            super().__init__(dataname, name)
    
    1. I am using ('timeframe', bt.TimeFrame.Minutes) to avoid my dates being turned from:

    2002-12-27 00:00:00

    into:

    2002-12-27 23:59:59.999989

    And be missaligned with other data sources. Is there a better, cleaner way to disable that "end of session" feature?

    Thank you!


  • administrators

    @Tester said in Settings lines and params on __init__:

    Is there anyway to make MultiFactorFeed more abstract, so that I could pass factors and indices on init and reuse the class when I change factor or index composition? There seems to be a lot of MetaClass black magic that interferes with that. Something like this fails:

    lines is a declaration and all instances of the MultiFactorFeed class are expected to have the same lines.

    What you need is to create a class on-the-fly with type, which defines the extra lines you are defining.

    MyDynamicLinesClass = type(give_it_a_random_name, bt.feeds.GenericCSVData, dct={'lines': factors + indices})
    data = MyDynamicLinesClass(*some_args, **kwargs)
    cerebro.adddata(data)
    

    @Tester said in Settings lines and params on __init__:

    And be missaligned with other data sources. Is there a better, cleaner way to disable that "end of session" feature?

    Not automatically. The reason to push daily timeframes to the limit of the day is to avoid them being overtaken by lower resolution timeframes. Because if the time of the daily resolution is 00:00:00 and is put in the same scheme as a data feed with minute resolution, a time 00:00:01 in the minute resolution data feed will surpass the daily resolution, which cannot happen in real life.



  • It works! Though apparently the second argument has to be a tuple, correct?

    AssetFeed = type("AssetFeed", (bt.feeds.GenericCSVData,), {"lines" : lines, "params" : params})
    

    Thank you very much.


  • administrators

    @backtrader said in Settings lines and params on __init__:

    Not automatically. The reason to push daily timeframes to the limit of the day is to avoid them being overtaken by lower resolution timeframes. Because if the time of the daily resolution is 00:00:00 and is put in the same scheme as a data feed with minute resolution, a time 00:00:01 in the minute resolution data feed will surpass the daily resolution, which cannot happen in real life.

    Correction: use the sessionend=datetime.time(hh, mm, ss, us) parameter when instantiating a data feed and that will be the end of session.


Log in to reply
 

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