Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Composite inputs for CustomFactors?

Is there a way to pass composite inputs into a CustomFactor? I mean, for example, for a CustomFactor like this:

class Scorer (CustomFactor):  
    window_length = 1  
    def compute(self, today, assets, out, data):  
        def score (x):  
            return x / (x + 10)  
        score_all = numpy.vectorize(score)  
        out[:] = score_all(data)

being able to do something like this:

    poms = Scorer(inputs = [ operation_ratios.operation_margin + operation_ratios.gross_margin ])  

Currently, doing that will spew out something like this:

TypeError: unsupported operand type(s) for +: 'BoundColumn' and 'BoundColumn'  

Oh, and a little background: The reason I want to do it like this rather than just having a scorer(x) function which does the same thing is so I can apply a mask to the items being scored. I'm currently using a scorer(x) function for several scores and with that I am occassionally getting timeout errors.

Thoughts?

. Topher

4 responses

You can use more than one boundcolumn from multiple datasets as inputs to a custom factor. Is that what you need? See the documentation https://www.quantopian.com/help#creating-custom-factors. Apply a mask when instantiating the custom factor.

import quantopian.pipeline.data.morningstar as ms

class Scorer (CustomFactor):  
    inputs = [ms.operation_ratios.operation_margin, ms.operation_ratios.gross_margin]  
    window_length = 1  

    def compute(self, today, assets, out, op_margin, gross_margin):  
        def score_all (x, y):  
            # your logic  
        out[:] = score_all(op_margin, gross_margin)

    poms = Scorer(mask = my_filter)


Not quite. If I do that, I have to know how all those inputs are related. In some cases they may be added (as I showed in the example), in others they may be subtracted or divided. Using that method, I would need to create a new CustomFactor for every variation of scoring I wanted to do.

. Topher

Yup.

Just to tie this off, you know, for the kids: Using subclassing I was able to come up with a solution that didn't make me twitch too much.

class Scorer (CustomFactor):  
    window_length = 1  
    def calculate_score (self, x):  
        return x / (x + 10)  
    def score_compute (self, values):  
        score_all = numpy.vectorize(self.calculate_score)  
        return score_all(values)

    def compute (self, today, asset_ids, out, values):  
        out[:] = self.score_compute(values)

class Sum2Scorer (Scorer):  
    def compute (self, today, asset_ids, out, first, second):  
        out[:] = self.score_compute(first + second)  

So then in my initialize() method I can do like so:

    oms = Scorer(inputs = [ operation_ratios.operation_margin ], mask = maskier)  
    pms = Scorer(inputs = [ operation_ratios.gross_margin ], mask = maskier) # sic  
    poms = Sum2Scorer(inputs = [ operation_ratios.operation_margin, operation_ratios.gross_margin], mask = maskier)  

I still have to create a custom factor for every different type of calculation, but at least I don't have to duplicate the scorer code all over the place.