Notebook
In [1]:
import pandas as pd
import numpy as np
# Pipeline imports
from quantopian.pipeline import CustomFactor, CustomFilter, Pipeline
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import SimpleMovingAverage
# Import run_pipeline method
from quantopian.research import run_pipeline
In [5]:
#Custom factor to calculate number of days where close price < 50 day SMA
class LTUptrend(CustomFactor):
    inputs = [USEquityPricing.close]
    window_length = 50
    
    def compute(self, today, assets, out, last_close_price):
        
        #*inputs are M x N numpy arrays, where M (axis=0) is the window_length and N (axis=1) is the number of securities. find mean of all the rows for each security
        #50 day SMA
        sma50cf = np.nanmean(last_close_price[0:-1], axis=0)
        
        # 'True' (=1) to detect bad days whenever last_close_price < sma50cf, otherwise it will be 0 (good day)
        # we need to find the last date for this event for each day
        #Since it is date descending, we want to find the last '1' in the series. or we can flip it upside down, and find the first 1 in series
        bad_day = last_close_price < sma50cf
        
        # Flip this array to now have the most recent date as row 0 (it's normally -1)  
        bad_day_flipped = np.flipud(bad_day)
        
        # Now find the first occurrence of a bad day for each stock (find first '1' so use argmax)
        days_since_last_bad_day = np.argmax(bad_day_flipped, axis=0)

        # There is a special case where all days in the window are good days (all 0's)
        # The argmax method will return 0 for such day (so will make it look like it was a bad day when it was in fact all good days)
        # We want it to return the max days or the window_length for such cases where it is all 0's
        #use np.any to deal with such cases to just reutrn the max window length where its all good days
        all_good_days = np.any(bad_day_flipped, axis=0)
        days_since_last_bad_day = np.where(all_good_days==False, self.window_length, days_since_last_bad_day)
        
        out[:] = days_since_last_bad_day

#Just a custom filter so we can run it for AAPL only later on
class SidInList(CustomFilter):
    inputs = []
    window_length = 1
    params = ('sid_list',)

    def compute(self, today, assets, out, sid_list):
        out[:] = np.in1d(assets, sid_list)

#Make pipeline
def make_pipeline():
    
    sma50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50)
    last_close_price = USEquityPricing.close.latest
    
    #run through customfactor
    bad_day = last_close_price < sma50
    days_since_last_bad_day = LTUptrend()
    
    #filter for AAPL only
    include_filter = SidInList(sid_list = (24)) # SID for APPL

    return Pipeline(columns={'bad_day':bad_day,'bad_days_count': days_since_last_bad_day,'last_close_price':last_close_price,'sma50':sma50},screen=include_filter)

# Specify a time range to evaluate
period_start = '2020-01-12'
period_end = '2020-03-08'

# Execute pipeline over evaluation period
pipeline_output = run_pipeline(
    make_pipeline(),
    start_date=period_start,
    end_date=period_end
)

pipeline_output     

Pipeline Execution Time: 0.73 Seconds
Out[5]:
bad_day bad_days_count last_close_price sma50
2020-01-13 00:00:00+00:00 Equity(24 [AAPL]) False 19.0 310.370 273.303273
2020-01-14 00:00:00+00:00 Equity(24 [AAPL]) False 20.0 316.940 274.790838
2020-01-15 00:00:00+00:00 Equity(24 [AAPL]) False 20.0 312.690 276.082735
2020-01-16 00:00:00+00:00 Equity(24 [AAPL]) False 21.0 311.500 277.211251
2020-01-17 00:00:00+00:00 Equity(24 [AAPL]) False 22.0 315.170 278.380465
2020-01-21 00:00:00+00:00 Equity(24 [AAPL]) False 23.0 318.670 279.626260
2020-01-22 00:00:00+00:00 Equity(24 [AAPL]) False 19.0 316.640 280.829660
2020-01-23 00:00:00+00:00 Equity(24 [AAPL]) False 20.0 317.700 281.993660
2020-01-24 00:00:00+00:00 Equity(24 [AAPL]) False 21.0 319.290 283.176660
2020-01-27 00:00:00+00:00 Equity(24 [AAPL]) False 22.0 318.200 284.296660
2020-01-28 00:00:00+00:00 Equity(24 [AAPL]) False 21.0 309.030 285.237660
2020-01-29 00:00:00+00:00 Equity(24 [AAPL]) False 22.0 317.760 286.303460
2020-01-30 00:00:00+00:00 Equity(24 [AAPL]) False 23.0 324.320 287.536060
2020-01-31 00:00:00+00:00 Equity(24 [AAPL]) False 24.0 323.850 288.698060
2020-02-03 00:00:00+00:00 Equity(24 [AAPL]) False 25.0 309.390 289.543460
2020-02-04 00:00:00+00:00 Equity(24 [AAPL]) False 24.0 308.710 290.391860
2020-02-05 00:00:00+00:00 Equity(24 [AAPL]) False 25.0 318.860 291.504660
2020-02-06 00:00:00+00:00 Equity(24 [AAPL]) False 25.0 321.580 292.696060
2020-02-07 00:00:00+00:00 Equity(24 [AAPL]) False 26.0 324.440 293.267442
2020-02-10 00:00:00+00:00 Equity(24 [AAPL]) False 26.0 320.040 294.352459
2020-02-11 00:00:00+00:00 Equity(24 [AAPL]) False 27.0 321.530 295.503987
2020-02-12 00:00:00+00:00 Equity(24 [AAPL]) False 28.0 319.230 296.543274
2020-02-13 00:00:00+00:00 Equity(24 [AAPL]) False 27.0 327.150 297.755326
2020-02-14 00:00:00+00:00 Equity(24 [AAPL]) False 26.0 324.910 298.984231
2020-02-18 00:00:00+00:00 Equity(24 [AAPL]) False 27.0 324.950 300.305121
2020-02-19 00:00:00+00:00 Equity(24 [AAPL]) False 28.0 319.000 301.462715
2020-02-20 00:00:00+00:00 Equity(24 [AAPL]) False 29.0 323.620 302.636091
2020-02-21 00:00:00+00:00 Equity(24 [AAPL]) False 29.0 320.300 303.640910
2020-02-24 00:00:00+00:00 Equity(24 [AAPL]) False 30.0 313.030 304.575750
2020-02-25 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 298.500 305.186070
2020-02-26 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 288.350 305.551091
2020-02-27 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 292.860 305.991945
2020-02-28 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 273.080 305.961380
2020-03-02 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 272.270 305.824229
2020-03-03 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 298.220 306.193508
2020-03-04 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 289.258 306.397714
2020-03-05 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 302.905 306.868474
2020-03-06 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 292.920 307.145920
2020-03-09 00:00:00+00:00 Equity(24 [AAPL]) True 0.0 288.980 307.259567
In [ ]: