Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Alpha Factor Returns (PnL) in IDE

Hi,

Is there a way to get the Returns() from individual alpha factors in the IDE over a specified (rolling) window period, ideally when using the Optimize API ( with opt.MaximizeAlpha objective) or if not, returns of the top and bottom quantiles/deciles of a factor?

Any kind python black-belt who knows if this is possible, maybe using the class object (with CustomFactor?), passing in the factor (or the top and bottom quantiles of the factor) and the desired window length? I've tried searching the forum for this, but couldn't find anything, and I'm pretty hopeless with python. Something like the below maybe?

class AlphaFactorReturns(CustomFactor, alpha_factor, window):

        returns = Returns(window_length=63)  

        top_quantile = alpha_factor.deciles(9)  
        bottom_quantile = alpha_factor.deciles(0)

        inputs = [returns, top_quantile, bottom_quantile, window]

        window_length = 63  [or window]??

            def compute(self, today, assets, out, returns, top_quantile, bottom_quantile):  
                out[:] =  Returns(top_quantile) - Returns(bottom_quantile)  

I'd really appreciate any help with this from anyone. Thank you.

Joakim

5 responses

Here's a nudge in the right direction. Note that .deciles gives you a Filter, and what you want instead is a Factor input. So, add 'alpha_factor' to your list of inputs; then, in 'compute' use either Numpy or Pandas to generate an index of the top and bottom, and use that index on 'returns' to get the top and bottom. Note that window_length = 1 would give you the past returns associated with the current top and bottom alpha_factors. If instead you wanted the forward returns, window_length = 63 as you have suggested and you use the date index [0] alpha_factor and the date index [-1] returns. To much better understand what is going on, in Research Notebook place print statements after def compute() to print out all of your *inputs, mask the CustomFactor to just a few symbols, and run the pipeline for one day only. As you add logic within compute, print out each result, such as the top and bottom indexes.

By the way, inputs = [returns, top_quantile, bottom_quantile] might work. I don't know since I have never used a filter as an input to a factor. However, if you try it and it does input correctly, within def compute() it will be an array of real numbers which you could convert to boolean and use as the index for returns, something like returns[top_quantile.astype(bool)]. This is all meant to suggest a solution. Work is needed, and print statements are your friend.

Good luck.

On further thought, no CustomFactor is needed.

universe = ?  
alpha_factor = AlphaFactor( window_length = ? , mask = universe & ? )  
pipeline = Pipeline(  
    columns = {  
        returns = Returns(  
            window_length = 63,  
            mask = alpha_factor.deciles().element_of( [ 0, 9 ] )  
        ),  
    },  
    screen = universe # or alpha_factor.deciles().element_of( [ 0, 9 ] )  
)

Caveats stated above regarding forward and past returns still apply. For instance, if AlphaFactor window_length = 64, AND the factor only uses data from index[0], then the factor will be calculated from data of 64 days prior to the current execution date, and returns will be the returns generated over the 63 day period after the alpha signal.

Another caveat is that universe can change over a 64 trading day window length, so the AlphaFactor and its deciles may differ to some degree if calculated using stale data with the current universe.

A better way might be to simply copy your IDE alpha_factor as-is into a Notebook, and then use AlphaLens to generate your forward returns from price data. This is the simplest, most failsafe method, and assures the universe will match the IDE backtest universe on each trading day.

Thanks Doug, and greetings from Down Under,

I'm looking to get the past returns of each single alpha factor over a specified window_length (say past 3 months), not the forward returns. Basically I'm looking to use the past recent alpha factor returns, either in absolute terms (end-points), or smoothed out using SMA or EWMA, to determine and dynamically change the weight of each individual alpha factor. For example, you could 'surf' from one factor that's done the best (100% weight) over the past rolling window_length, to the next. You could also do something like:

alpha_factor1_weight = alpha_factor1_63d_returns /  (alpha_factor1_63d_returns + alpha_factor2_63d_returns + alpha_factor3_63d_returns)  # or total returns in the denominator in other words.

Or, if you also had the mean returns (and variance) you could also try a mean reversion weight of the factors (less weight to factors that have outperformed recently and significantly over its mean).

Not exactly rocket science, and I'm sure it's been tried before, but I'd like to try it as well, and with my kung fu python skillz I'll figure out how to do it any year now! ;)

Thanks again for your responses and help, I really appreciate it!

Joakim

Right, so that's like...

universe = ?  
alpha_factor_1_past = AlphaFactor_1( window_length = 64 , mask = universe & ? )  
alpha_factor_1_now = AlphaFactor_1( window_length = 1 , mask = universe & ? )  
alpha_factor_2_past = AlphaFactor_2( window_length = 64 , mask = universe & ? )  
alpha_factor_2_now = AlphaFactor_2( window_length = 1 , mask = universe & ? )  
pipeline = Pipeline(  
    columns = {  
       ' returns_1' : Returns(  
            window_length = 63,  
            mask = alpha_factor_1_past.deciles().element_of( [ 0, 9 ] )  
        ),  
        'alpha_1_past' : alpha_factor_1_past,  
        'alpha_1_now' : alpha_factor_1_now,  
       ' returns_2' : Returns(  
            window_length = 63,  
            mask = alpha_factor_2_past.deciles().element_of( [ 0, 9 ] )  
        ),  
        'alpha_2_past' : alpha_factor_2_past,  
        'alpha_2_now' : alpha_factor_2_now,  
    },  
    screen = universe  
)

AlphaFactor_x must only use the [0] indexed values, and will yield the alpha on the day before your returns with window_length = 64, and also the alpha for today with window_length = 1. The 'returns' will be only those returns associated with alpha_past. In a single pipeline you can do this for a collection of factors, and then daily choose which alpha_past you like based on returns, then use alpha_now as an input to your optimal order weights.

This is likely the simplest, but not necessarily most computationally efficient way to achieve your goal, and should help. Good luck.