Back to Community
Just pipeline -- entry/exit logic? nanfill to combine two factors?

Anybody have any tips on how to implement an entry/exit-signal style strategy using just Pipeline? e.g. enter when a certain threshold has been met, and sell 10 days later.

How about nanfilling when combining two factors within Pipeline? e.g. if one had separate long and short criteria that have different masks?

8 responses

This will fill your factor's NaN with 0 values by default, so you can combine factors within pipeline:

import numpy as np


class NanToNum(CustomFactor):  
    window_length = 1  
    def compute(self, today, assets, out, factor):  
        out[:] = np.nan_to_num(factor[-1])


factor_filled = NanToNum(inputs=[factor.zscore(mask=factor1_universe)])

Should work when having different masks for each factor.

Anybody have any tips on how to implement an entry/exit-signal style strategy using just Pipeline? e.g. enter when a certain threshold has been met, and sell 10 days later.

This I've wanted to do as well, but don't know how to. E.g. enter position based on factor1, exit based on factor2.

This will fill your factor's NaN with 0 values

Thanks Joakim. As soon as I saw the answer I realized you've shown me this before! haha. Thanks again.

E.g. enter position based on factor1, exit based on factor2.

The one idea I've had so far for entry criteria logic would be to use a loop to create a factor1 filter for each day (today, yesterday, the day before, etc. using CustomFactor to access the previous date's values) and then or them all together in a mask. I guess you could do the same for factor2 and get recursive in the construction of the mask such that it recreates historical entry and exit logic. Gets a bit complex, and might be pretty slow, especially if you want to scan far back in time for the signal. Of course you have to choose some arbitrary distance back in time to look, which limits you, but does make it at least deterministic.

psuedocode for the mask construction, where x is how far back in time you are looking:

(entry_criteria[x] and not (exit_criteria[x-1] or exit_criteria[x-2] or exit_criteria[x-3]  ... or exit_criteria[x-x]))
or  
(entry_criteria[x-1] and not (exit_criteria[x-2] or exit_criteria[x-3] ... or exit_criteria[x-x]))
or  
(entry_criteria[x-2] and not (exit_criteria[x-3] ...or exit_criteria[x-x]))
...
or  
entry_criteria[x-x]  

@Viridan - I think I understand the part where you are combining exit criteria from the last N days (I'd recommend using different letter variables to represent current day and 'N days ago'). However, it's not clear to me what the purpose is of defining the combined entry and not (combined_exit) criteria for the last several days. Can you elaborate on that step a bit more?

Thanks!

Disclaimer

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.

Maybe I just haven't thought it through well enough. This is my thought process...

Pipeline is very easy to use to rank/score and mask stocks based on current data, but it's not immediately apparent to me how to use it on more dynamically-timed strategies.

Lets say, for the sake of example, we have a basic strategy where we enter a stock once it is under RSI 20 and then exit once it is over RSI 80. Inside of an algorithm one could simply return the RSI from Pipeline and add/remove stocks from a context. list depending on the criteria. However, purely within pipeline I'm not aware of any way to remember a state from days previous. So my solution is to basically recreate history each day to determine the current state.

So you start at the furthest you can be bothered to look back, say 100 days. So you check what the RSI was 100 days ago: if it was under 20, then you'd be "in" the stock unless any day 99 days ago through today it was over 80 (because then you would have already exited as well, and thus no longer "in" the stock). Then you'd do the same for 99 days ago, etc.

I guess efficiency-wise, it'd be best to reverse it (start checking today's RSI, then yesterday's, etc.).

I'm a visual thinker, so this helps me:

days ago:  10   9   8   7   6   5   4   3   2   1   0  
RSI:       50   10  50  90  50  10  50  50  90  10  50  
action:    -    B   -   S   -   B   -   -   S   B   -  
are we in: N    Y   Y   N   N   Y   Y   Y   N   Y   Y  

So you basically traverse backwards through the action columns (via chain of ored together clauses) . If you hit a - you keep going until you hit a S (in which case you not in the stock any longer, if you ever were) or a B (currently in).

I think I've answered my own question. I'll post a prototype when I have some more time over the weekend. But maybe somebody has a more elegant solution.

So this is along the lines of what I was thinking, but I got stuck here. I guess my folly is treating the filter like a bool. I still haven't totally wrapped my head around filters.

lookback_window = 100

are_we_in = False  
for n in range(lookback_window, 0):  
    rsi_n_days_ago = offset_rsi_factor(n,  
                        inputs=[EquityPricing.close],  
                        window_length=14,  
                        mask=univ_filter)  
    entry_signal = rsi_n_days_ago < 20  
    exit_signal  = rsi_n_days_ago > 80  
    are_we_in    = (not exit_signal) and (entry_signal or ( are_we_in ) )  
Loading notebook preview...

VH: Thanks for the clarification! You're right , the backtester is better suited for simulating the type of entry/exit logic you're describing. However, I think you can achieve something similar in pipeline, it just requires a bit more thought (exactly what you're doing!), because the definition won't be a set of serial operations, like you can do in the backtester.

In this case, I wonder if it would be a little easier (or maybe, a little easier to read for an outsider?) to implement the above as a CustomFactor that checks the 'state' of the theoretical portfolio. For example, maybe you could pass the regular RSI factor as input to the CustomFactor (with a 10-day lookback), and for each asset, check if the entry condition is met without the exit condition occurring later in that window. Does that make any sense?