Back to Community
Python noob question - how can I create a parameterized CustomFactor in Pipeline?

I'd like to create a CustomFactor class which has constructor arguments, so I can parameterize it and make several versions of it... I tried adding an init but it doesn't work, and I am not sure of myself in Python enough to know if this is me being dumb, or something intentional in the Pipeline API.

3 responses

@Simon it's probably not a great idea to try to change the __init__ of CustomFactor at this time. We're doing a bunch of fancy stuff in the Engine to cache instances of Factorthat are passed the same arguments. This makes it easier for the engine to ensure that it doesn't re-compute Factors that appear in the computation tree multiple times, but has the downside of making Factor significantly more complex than a normal Python class.

If you really want to change the initialization of CustomFactor you'd probably want to look at the implementation of Rank in Zipline, which is the class returned by the rank() method. The relevant functions are __new__, _init and the static_identity classmethod. I'm not super happy with how that system works right now though, so I'd say you should regard the CustomFactor constructor as a private API for the moment.

A simpler way to accomplish what you want is probably to just define a function that returns a new subclass of CustomFactor that closes over the arguments.

An example (with illustrative but very verbose names):

def make_custom_factor_subclass(arg1, arg2):  
    """Define and return a new **class** that closes over arg1 and arg2."""  
    class MyCustomFactor(CustomFactor):  
        inputs = [...]  
        def compute(self, ...):  
            # Do something that depends on arg1 and arg2.

    return MyCustomFactor

# This returns a new type.  
MyCustomFactor_12 = make_custom_factor_subclass(1, 2)

# Make an instance for use with a pipeline  
my_custom_factor_12_instance = MyCustomFactor_12()  

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

The function-creating-new-type solution works, by the way, because the type itself is part of the cache key used to determine whether or not Factor.__new__ creates a new instance.

Yeah that works, silly me. Thanks!