Notebook
# Works but outputs do not correspond to my calculations of gaps. Figure out if the CustomFactor args are wrong # (e.g. window length, close, open etc) # to make CustumFactor return only non NaN value # filter_not_nan = signed_gap_pct.notnan(). This implements .notnan() method for any factor, # output TRUE for any non NaN value, I used this filter as screen for return Pipeline()
In [37]:
# Import statements
# Need the following to run pipeline and make custom factors
from quantopian.pipeline import CustomFactor, Pipeline
from quantopian.research import run_pipeline

# Get some data
from quantopian.pipeline.data.builtin import USEquityPricing

# Import a few built in filters
from quantopian.pipeline.filters import Q1500US, StaticAssets
In [38]:
# Define class for a CustomFactor outputting signed gaps as %

class SignedGapPct(CustomFactor):
    # Default input
    inputs = [USEquityPricing.close, USEquityPricing.open]
    
    # Need a window length of 2 because we want 2 days of data (yesterday and the day before that)
    window_length = 2
    def compute(self, today, asset_ids, out, close, open):
        # Calculates the column-wise gaps, how to ignore NaNs?
        # Take yesterdays open (-1) and divide by the previous days close (-2)
        out[:] = (open[-1] - close[-2]) / close[-2]
In [55]:
def make_pipeline():
    """
    Create our pipeline.
    """

    # Base universe set to the Q1500US.
    base_universe = Q1500US()

    # Factor to calculate gap up/down (signed) in percent normalised to previous day close
    signed_gap_pct = SignedGapPct(mask=base_universe)
    open_price = USEquityPricing.open.latest
    close_price = USEquityPricing.close.latest

    # filter out NaN
    # This isn't really necessary (though doesn't hurt) since the top and bottom
    # methods don't look at NaN values
    #filter_not_nan = signed_gap_pct.notnan()
    
    # filter for top 5 gap up
    filter_top_gap_up = signed_gap_pct.top(5)
    
    # filter for bottom 5 gap down
    filter_bottom_gap_down = signed_gap_pct.bottom(5)
    
    # aggregated filter for pipeline screen
    aggr_screen = filter_top_gap_up | filter_bottom_gap_down

    return Pipeline(
        columns={
            'signed_gap_pct': signed_gap_pct,
            'open_price': open_price,
            'close_price': close_price,

        },
        screen = (aggr_screen),
        )
In [56]:
my_pipe = make_pipeline()
In [57]:
result = run_pipeline(my_pipe, '2017-12-17', '2017-12-19')
In [62]:
result
Out[62]:
close_price open_price signed_gap_pct
2017-12-18 00:00:00+00:00 Equity(216 [HES]) 43.390 44.01 0.037727
Equity(1937 [CSX]) 52.810 52.04 -0.091956
Equity(8383 [FL]) 45.650 46.11 0.039684
Equity(8468 [DDR]) 8.865 8.53 0.072282
Equity(26335 [ALNY]) 125.510 130.16 0.052563
Equity(36930 [DISC_A]) 20.860 20.77 0.036427
Equity(46871 [RDUS]) 29.980 27.47 -0.042190
Equity(49139 [FIT]) 6.300 6.38 -0.065886
Equity(49335 [GBT]) 36.250 37.60 -0.045685
Equity(50320 [ELF]) 22.470 21.11 -0.045228
2017-12-19 00:00:00+00:00 Equity(1937 [CSX]) 53.690 51.70 -0.021019
Equity(2169 [CVA]) 16.450 15.70 0.050167
Equity(4499 [LNCE]) 50.040 49.92 0.066667
Equity(16609 [EEFT]) 84.860 89.63 -0.025231
Equity(20680 [AKAM]) 65.680 66.33 0.148571
Equity(21366 [OCLR]) 7.045 7.08 -0.023448
Equity(25705 [XPER]) 26.500 25.70 0.088983
Equity(26191 [CORT]) 16.550 15.72 -0.053582
Equity(37849 [IPXL]) 17.800 18.20 -0.024129
Equity(45815 [TWTR]) 24.695 23.23 0.045455

The above checks out. Take CSX for example. The close from 12-18 (remember thats actually the close on the previous trading day 12-15) is 52.81. The open from 12-19 (again actually the 12-18 open) is 51.70. The "gap up" is (51.70/52.81)-1 which equals -0.021019. This matches the value in the dataframe above.