Notebook
In [1]:
# Imports;
from quantopian.research import run_pipeline
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import Fundamentals,morningstar
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import Latest,CustomFactor, SimpleMovingAverage, AverageDollarVolume, Returns, RSI
from quantopian.pipeline.filters import Q500US#, Q1500US
import pandas as pd
In [2]:
# define Morningstar fields to check

def make_factors():
    def dividend_yield():
        return morningstar.valuation_ratios.dividend_yield.latest
        
    def dividend_rate():
        return morningstar.valuation_ratios.dividend_rate.latest

    def forward_dividend_yield():
        return morningstar.valuation_ratios.forward_dividend_yield.latest
    
    # returns an error that this field doesn't exist?
    #def trailing_dividend_yield():
    #    return morningstar.valuation_ratios.trailing_dividend_yield.latest

    def forward_dividend():
        return Fundamentals.forward_dividend.latest

    def dividends_payable():
        return Fundamentals.dividends_payable.latest
 
    def cash_dividends_paid():
        return Fundamentals.cash_dividends_paid.latest

    def dividend_per_share_earnings_reports():
        return Fundamentals.dividend_per_share_earnings_reports.latest    
     
    
    all_factors = {
        'dividend_yield ': dividend_yield,
        'dividend_rate': dividend_rate,
        'forward_dividend_yield': forward_dividend_yield,
        #'trailing_dividend_yield': trailing_dividend_yield,
        'forward_dividend': forward_dividend,
        'dividends_payable': dividends_payable,
        'cash_dividends_paid': cash_dividends_paid,
        'dividend_per_share_earnings_reports' : dividend_per_share_earnings_reports,
    }        
    
    return all_factors
In [3]:
universe = Q500US()
factors = make_factors()
n_fwd_days = 30 # number of days to compute returns over
In [4]:
def make_history_pipeline(factors, universe, n_fwd_days=n_fwd_days):
    # Call .rank() on all factors and mask out the universe
    factor_ranks = {name: f().rank(mask=universe) for name, f in factors.iteritems()}
    # Get cumulative returns over last n_fwd_days days. We will later shift these.
    factor_ranks['Returns'] = Returns(inputs=[USEquityPricing.open],
                                      mask=universe, window_length=n_fwd_days)
    pipe = Pipeline(screen=universe, columns=factor_ranks)
    
    return pipe
In [5]:
history_pipe = make_history_pipeline(factors, universe, n_fwd_days=n_fwd_days)
In [6]:
start = pd.Timestamp("2019-09-01")
end   = pd.Timestamp("2019-11-01")
results = run_pipeline(history_pipe, start_date=start, end_date=end)
results.index.names = ['date', 'security']

Pipeline Execution Time: 8.79 Seconds
In [7]:
results = results.loc[results['forward_dividend'] > 0]
In [8]:
results.head()
Out[8]:
Returns cash_dividends_paid dividend_per_share_earnings_reports dividend_rate dividend_yield dividends_payable forward_dividend forward_dividend_yield
date security
2019-09-03 00:00:00+00:00 Equity(2 [ARNC]) 0.034624 356.0 23.0 7.0 32.0 NaN 7.0 12.0
Equity(24 [AAPL]) 0.035887 3.0 304.0 303.0 113.0 NaN 303.0 125.0
Equity(62 [ABT]) -0.021635 61.0 149.0 141.0 114.0 109.0 141.0 129.0
Equity(67 [ADSK]) -0.155716 285.0 1.0 6.0 4.0 NaN 6.0 177.0
Equity(76 [TAP]) -0.054820 252.0 200.0 253.0 299.0 NaN 253.0 380.0

TODO: Check portfolio value on day of dividend deliveries

Are dividends properly accounted for in the backtesting environment?

Simulate holding shares of a company at the time of a dividend, check that the cash balance increased by the appropriate amount.

Check that the 'div payable' dates are enforced -- so dividends should be earned if bought before the payable date, and not if bought after but held when the dividend was paid.

In [ ]: