python dividend screener
|

2. Python Dividend Stock Screener

Welcome Back! In our first post, we laid the groundwork by building a Python screener to identify potential value stocks. Now, we’ll expand our toolkit by focusing on a different, yet equally popular strategy: dividend investing. This guide will walk you through creating a Python script to find stocks offering attractive dividend yields potentially backed by sustainable payout practices.

Why Focus on Dividend Stocks?

Dividend investing centers on acquiring shares in companies that distribute a portion of their profits back to shareholders regularly. These dividend payments appeal to investors for several key reasons:

  • Regular Income: Dividends provide a predictable cash flow stream, ideal for income generation or reinvestment (compounding).
  • Signals of Stability: Companies with long, consistent histories of paying (and ideally increasing) dividends are often mature, financially healthy businesses with stable earnings.
  • Total Return Component: An investment’s total return comes from both capital appreciation (stock price increase) and dividends received.

Screening helps us cut through the noise and pinpoint companies meeting specific dividend-related criteria.

Our Dividend Screener Logic: Balancing Yield and Sustainability

A high dividend yield looks attractive, but it’s meaningless if the company can’t afford to maintain the payment. Therefore, we need to balance yield with sustainability. Our criteria will be:

  1. Dividend Yield (> 2.5%): Calculated as (Annual Dividend Per Share) / (Current Stock Price), this shows the income return relative to the share price. We’ll set a minimum threshold of 2.5% to focus on stocks offering a yield noticeably above the broader market average (historically).
    • Context & Caution: Be wary of extremely high yields (e.g., >>10%). This can be a “yield trap” – the high yield might result from a drastically falling stock price, often signaling market concern that the dividend is unsustainable and might be cut soon. We’re generally looking for reasonable, potentially growing yields. Note that yfinance often provides dividendYield (trailing) and sometimes forwardDividendYield(based on expected future dividends) – we’ll primarily use the trailing yield here.
  2. Payout Ratio (less than 70% and more than 0%): Calculated as (Dividends Per Share) / (Earnings Per Share), this shows how much of the company’s profit is paid out as dividends.
    • Sustainability: A lower ratio (we’ll use less than 70% or 0.7) suggests the company retains earnings for growth, debt reduction, or weathering economic downturns, making the dividend safer.
    • Lower Bound: We’ll also ensure the payout ratio is greater than 0 to exclude companies with negative earnings (which makes the payout ratio calculation less meaningful or misleading).
    • Industry Nuance: Payout ratios vary. Mature, stable sectors like Utilities or Consumer Staples might naturally have higher sustainable ratios than fast-growing tech companies. Real Estate Investment Trusts (REITs) have specific rules often leading to very high payout ratios (>90%) by design. Our less than 70% is a general starting point.

Our goal: Find stocks with an appealing yield whose payout seems manageable based on recent earnings.

Python Implementation: Building the Dividend Detective

We’ll stick with our core tools: pandas and yfinance.

# Import necessary libraries
import pandas as pd
import yfinance as yf
import warnings

# Ignore specific warnings from yfinance if necessary (optional)
warnings.filterwarnings("ignore", category=FutureWarning)
warnings.filterwarnings("ignore", message="Passing literal json to 'read_json' is deprecated")

def screen_dividend_stocks(tickers):
    """
    Screens a list of stock tickers for dividend yield and payout ratio criteria.

    Args:
        tickers (list): A list of stock ticker symbols (strings).

    Returns:
        pandas.DataFrame: A DataFrame containing stocks that meet the criteria,
                          including Ticker, Company Name, Dividend Yield (%),
                          and Payout Ratio (%). Returns an empty DataFrame if none pass.
    """
    filtered_stocks = [] # List to hold dictionaries of passing stocks

    print(f"Screening {len(tickers)} tickers for dividend criteria...")

    # Loop through each ticker symbol
    for ticker in tickers:
        try:
            # Create a Ticker object
            stock = yf.Ticker(ticker)
            info = stock.info

            # --- Define Screening Criteria Thresholds ---
            min_yield_threshold = 2.5 # 2.5%
            max_payout_threshold = 0.70  # 70%
            min_payout_threshold = 0.0   # 0% (must be positive)
            # -------------------------------------------

            # Safely get dividend yield and payout ratio using .get()
            # Returns None if the key doesn't exist (e.g., non-dividend stock)
            dividend_yield = info.get('dividendYield')
            payout_ratio = info.get('payoutRatio')
            company_name = info.get('shortName', 'N/A')

            # --- Data Validation and Filtering Logic ---
            # 1. Check if data exists (not None)
            if dividend_yield is not None and payout_ratio is not None:
                # 2. Ensure data is numeric (sometimes yfinance might return non-numeric)
                 if isinstance(dividend_yield, (int, float)) and isinstance(payout_ratio, (int, float)):
                    # 3. Apply the core criteria
                    if (dividend_yield > min_yield_threshold and
                        payout_ratio < max_payout_threshold and
                        payout_ratio > min_payout_threshold):

                        # Criteria met, store details
                        filtered_stocks.append({
                            'Ticker': ticker,
                            'Company Name': company_name,
                            # Format as percentage string for display
                            'Dividend Yield (%)': f"{dividend_yield:.2f}%",
                            'Payout Ratio (%)': f"{payout_ratio * 100:.2f}%"
                        })
                        print(f"  [PASS] {ticker} (Yield: {dividend_yield:.2f}%, Payout: {payout_ratio*100:.2f}%)")

        except Exception as e:
            # Handle potential errors during data fetching for a specific ticker
            print(f"  [ERROR] Could not process {ticker}: {e}")
            continue # Skip to the next ticker

    print("\nScreening complete.")

    # Convert list of dictionaries to DataFrame
    if filtered_stocks:
        results_df = pd.DataFrame(filtered_stocks)
        results_df = results_df[['Ticker', 'Company Name', 'Dividend Yield (%)', 'Payout Ratio (%)']]
    else:
        results_df = pd.DataFrame(columns=['Ticker', 'Company Name', 'Dividend Yield (%)', 'Payout Ratio (%)'])

    return results_df

# --- Main Execution Block ---
if __name__ == "__main__":
    # Define the list of stock tickers to screen
    # Example list - consider adding Utilities, REITs, more Consumer Staples
    ticker_list = [
        'AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', # Tech (often low/no yield)
        'JPM', 'BAC', 'WFC', # Banks
        'PFE', 'JNJ', 'MRK', # Pharma (often pay dividends)
        'XOM', 'CVX', # Energy (often pay dividends)
        'WMT', 'COST', 'TGT', # Retail
        'INTC', 'AMD', 'QCOM', # Semiconductors
        'F', 'GM', # Auto
        'DIS', 'NFLX', # Entertainment
        'KO', 'PEP', 'PG', # Consumer Staples (often pay dividends)
        'DUK', 'NEE', # Utilities (examples)
        'O', 'SPG', # REITs (examples - expect high payout)
        'RDDT'
    ]

    # Run the screener
    dividend_stocks_df = screen_dividend_stocks(ticker_list)

    # Display the results
    print("\n--- Dividend Stock Screener Results ---")
    if not dividend_stocks_df.empty:
        print(dividend_stocks_df.to_string(index=False))
    else:
        print("No stocks from the list met the specified dividend criteria.")

    print("\nDisclaimer: This information is for educational purposes only and not financial advice.")

Dissecting the Code

  1. Setup: Imports pandasyfinance, and warnings.
  2. screen_dividend_stocks Function: Organizes the logic, taking tickers and returning a DataFrame.
  3. Looping & Fetching: Iterates tickers, creates yf.Ticker objects, and fetches the info dictionary.
  4. Critical Data Handling:
    • We use info.get('dividendYield') and info.get('payoutRatio'). This safely returns None if a company doesn’t pay dividends or if data is missing, preventing errors.
    • We explicitly check if dividend_yield is not None and payout_ratio is not None: before attempting comparisons.
    • We add a check isinstance(dividend_yield, (int, float)) to ensure the retrieved data is actually numeric before comparing.
  5. Applying Filters: The core if statement combines our checks: data must exist, yield > 2.5%, and payout ratio between 0% and 70%.
  6. Storing & Formatting Results: Passing stocks are stored as dictionaries. Importantly, the payout_ratio are multiplied by 100 and formatted into percentage strings (f"{value * 100:.2f}%"only when added to the results dictionary for display purposes. The logical comparisons use the original decimal values.
  7. Error Handling & DataFrame: The try...except block handles errors per ticker, and the final list is converted to a pandas DataFrame.
  8. Execution: The if __name__ == "__main__": block runs the process with an example ticker_list.

Interpreting the Output

Python dividend screener

Screening Process: The script processed 31 stock tickers. The [PASS] lines indicate which specific stocks met the defined criteria (likely Dividend Yield > 2.5%, Payout Ratio > 0% and < 70%, plus data sanity checks) during the run. Stocks like BAC, JNJ, MRK, XOM, CVX, TGT, QCOM, F, and PG passed.

The section under --- Dividend Stock Screener Results --- presents a formatted table (using pandas) summarizing the stocks that passed the entire screening process.

The yields range from 2.53% to 7.67%, and payout ratios are all below 70% and positive, aligning with the likely screening logic.

Vital Considerations & Next Steps

This screener is a solid start, but dividend investing requires more homework:

  1. Dividend History is Key: Does the company have a long track record of paying and, ideally, growing its dividend? This screener doesn’t check history.
  2. Financial Health Check: Is the dividend supported by strong free cash flow? How much debt does the company have? A company prioritizing dividends over debt repayment or essential investments might be risky.
  3. Future Prospects: Are the company’s earnings expected to grow, stagnate, or decline? Future earnings support future dividends.
  4. Context Still Matters: Why is the payout ratio what it is? Is it appropriate for the industry? (e.g., don’t screen out REITs just because payout > 70%).

Actionable Next Steps:

  • Research the dividend history (consistency and growth rate) of screened candidates. Check investor relations pages or sites like Seeking Alpha or Dividend.com.
  • Analyze the company’s balance sheet (especially debt levels) and cash flow statements.
  • Read recent earnings reports and analyst opinions on future prospects.

Future Enhancements:

  • Add dividend growth rate (e.g., 5-year average) as a screening criterion.
  • Filter based on the number of consecutive years of dividend increases.
  • Incorporate basic debt metrics (e.g., Debt-to-Equity).

Up next in our series, we’ll tackle growth stock screening, focusing on metrics that signal rapid expansion!


Disclaimer: This content is purely educational. It’s not financial advice. Dividend screening is just one piece of the puzzle. Always do thorough research or consult a qualified financial advisor. This blog post was drafted with the assistance of AI tools and reviewed and edited by the author.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *