Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Are the 'pe ratio' wrong? Or my code has error?

Hi,

I wrote a simple and small program just want to hole the first 5 stocks with the largest 'pe ratio'. My code looks as follow:

import numpy as np

# This function is run once at the beginning of the algorithm, REQUIRED  
def initialize(context):  
    # AAPL stock  
    # context.stock = sid(24)  
    # SPY stock  
    # context.market = sid(8554)  
    pass  
# This function is run once per day before any calls to handle_data, OPTIONAL  
def before_trading_start(context, data):  
    #Fundamentals Reference Page: https://www.quantopian.com/help/fundamentals  
    context.fundamental_df = get_fundamentals(  
        query(  
            #fundamentals.income_statement.total_revenue  
            fundamentals.valuation_ratios.pe_ratio  
        )  
        .filter(  
            fundamentals.valuation.market_cap > 30000000000  
        )  
        .order_by(  
            #fundamentals.valuation.market_cap.desc()  
            fundamentals.valuation_ratios.pe_ratio.desc()  
        )  
        .limit(5)  
    )  
    update_universe(context.fundamental_df.columns.values)  
    for stock in data:  
        print '%s - pe ratio: %.2f' % (stock.symbol, context.fundamental_df[stock][0])  
# This function is run once per bar, REQUIRED  
def handle_data(context, data):  
    pass  
def check_mean(context, data):  
    pass  

(run daily from 2/15/2016 to 2/18/2016)

I got the running result as follow:
... 2016-02-17PRINT AGN - pe ratio: 652.35
2016-02-17PRINT SU - pe ratio: 481.12
2016-02-17PRINT AMZN - pe ratio: 392.55
2016-02-17PRINT CRM - pe ratio: 5000.00
2016-02-17PRINT RBS - pe ratio: 670.36
2016-02-18PRINT AGN - pe ratio: 652.35
2016-02-18PRINT SU - pe ratio: 481.12
2016-02-18PRINT AMZN - pe ratio: 403.23
2016-02-18PRINT CRM - pe ratio: 5000.00
2016-02-18PRINT RBS - pe ratio: 670.36
...

One can see the 'pe ratio' are much more largger than that from google/finance and barchart.com.

Who call tell me where is the problem?

Regards

8 responses

I decided to dig into this problem and found that fundamentals data contain incorrect pe_ratio values. To correct this issue, I created a custom factor PERatio. See how to use this in the attached notebook.

In short, you need to add the following code in your block:

def get_periodic(df, periods, interval_days=252):  
    """ Get periodic data  
    df: DataFrame object.  
    periods(int): Number of periods to go back for.  
    interval_days(int): Number of trading days, default to 252 (one year).  
    """  
    idx = [-1]  
    for i in range(1, periods):  
        idx.append(-i * interval_days)  
    idx.reverse()  
    periodic_data = df[idx]  
    return periodic_data  
class PERatio(CustomFactor):  
    inputs = [USEquityPricing.close,  
              Fundamentals.diluted_eps_earnings_reports]  
    outputs = ['pe', 'close', 'eps']  
    quarter_days = 252/4  
    quarters = 5  
    window_length = quarter_days*quarters  
    def compute(self, today, assets, out, close, eps):  
        close_p = get_periodic(close, self.quarters, interval_days=self.quarter_days)  
        eps_p = get_periodic(eps, self.quarters, interval_days=self.quarter_days)

        # For each company  
        for i in range(close_p.shape[1]):  
            uniq_eps_ids = np.unique(eps_p[:,i], return_index=True)[1]  
            uniq_eps = [eps_p[index, i] for index in sorted(uniq_eps_ids)]  
            out.close[i] = close_p[-1, i]  
            out.eps[i] = np.sum(uniq_eps[-4:])  
            out.pe[i] = close_p[-1, i] / out.eps[i]  

And to use it simply do as follows

pe_ratio = PERatio()  

Then add pe_ratio.eps in your pipeline.

More than two years later I got the answer. Many thanks! :-)

Lol. My pleasure. I hope someone from Quantopian team will see this thread and correct this bug in their database.

Great work. Do keep in mind they're just providing to us what is provided to them, I think you might consider corresponding with Morningstar, it seems they welcome it.
For anyone, is there something wrong with this? PE_ratio would change with price I presume and yet this implies there were only 254 companies where the value changed 245 times max (not 252) and 317 companies only had 1 value the whole year, etcetera, other details in the logging window and only takes a couple seconds to run.

Yep I actually have. Just a few hours ago I got an email from their dev team detailing their pe ratio calculation. I am not quite sure if I can share that here but I'll ask their permission. I'll implement the formula soon-ish (may take days to find a time).

For anyone, is there something wrong with this? PE_ratio would change with price I presume and yet this implies there were only 254 companies where the value changed 245 times max (not 252) and 317 companies only had 1 value the whole year, etcetera, other details in the logging window and only takes a couple seconds to run.

That is exactly the problem that I found and corrected, see my attached notebook above.

Price/Earnings Ratio
NASDAQ: The 3 Most Critical Fundamental Metrics For Stock Investors #2
Investopedia: 5 Must-Have Metrics for Value Investors #1

So one of the most highly recommended fundamentals is awfully broken here.

Thank you for sharing a workaround.

Using mask for speed:

universe = monthly_top_volume & base_universe  
pe_ratio = PERatio(mask=universe).eps 

Any update? Bug is closed? thanks