Dividend stocks does not appear from function

Viewed 26

I'm trying to gather dividend yields from multiple stocks via yfinance. I have a loop which creates a CSV-file for each ticker with historical data.

When I've downloaded dividend data via a function previously, it has worked - basically I created a function with a for-loop and then appended a dataframe with the stocks. However, now I want to do it the same way but with a boolean expression instead, and it's not working.. I'm not getting any errors but I'm not receiving any ticker symbols (which I know satisfy the condition). I've tried to formulate the boolean loop differently, without success. What am I doing wrong? Below is my code:

import yfinance as yf
import pandas as pd
import os

df = pd.read_csv(r'C:\\Users\Name\Stocks\Trading\teststocks.csv')
tickers = df["Symbol"].tolist()
i=0
listlength = len(tickers)
for ticker in tickers:
    i=i+1
    print("Downloading data for",ticker,",",i,"of",listlength)
    df = yf.download(ticker, period = "max", interval = "1wk", rounding = True)
    df.dropna(inplace=True)
    df.to_csv(os.path.join("C:\\Users\Name\Stocks\dataset",ticker + ".csv"))
def dividend(df):
    info = yf.Ticker(ticker).info
    div = info.get("dividendYield")
    if div is None:
        pass
    elif div > 0.04:
        return True
    else:
        return False
for filename in os.listdir("C:\\Users\Name\Stocks\dataset"):
    df = pd.read_csv("C:\\Users\Name\Stocks\dataset\{}".format(filename))
    if dividend(df):
        print("{}".format(filename))

So this function is looping through the ticker symbols from the dataset folder and getting the dividend data from yfinance, however it's not returning with the ticker that satisfy the condition - which in this case is if the dividend yield is higher than 4%. The first dataframe being read is a CSV file with the ticker symbols in the OMXS30 - so for example HM-B.ST should appear from the dividend function..

Another thing that I want to add is that I'm using the same logic for a function for marketcap, which does work. See below:

def marketcap(df):
    info = yf.Ticker(ticker).info
    mcap = info.get("marketCap") 
    if mcap is None:
        pass
    elif mcap > 10000000000:
        return True
    else:
        return False
for filename in os.listdir("C:\\Users\Name\Stocks\dataset"):
    df = pd.read_csv("C:\\Users\Name\Stocks\dataset\{}".format(filename))
    if marketcap(df):
        print("{}".format(filename))

I do not know why the dividend boolean expression does not work, when the marketcap does work. Thanks in advance.

2 Answers

Neither the function dividend nor marketcap is working as it should. The reason has to do with the following:

for ticker in tickers:
    # do stuff

Here you are taking a list of tickers and doing some stuff for each ticker in this list. This means that by the end of your loop, the variable ticker equals the last item in the list. E.g. suppose tickers = ['HM-B.ST','AAPL'], then ticker will at the end equal AAPL.

Now, let's have a look at your function dividend:

def dividend(df):
    info = yf.Ticker(ticker).info
    div = info.get("dividendYield")
    if div is None:
        pass
    elif div > 0.04:
        return True
    else:
        return False

This function has one argument (df), but it is not actually using it. Instead you are applying yf.Ticker(...).info to a variable ticker, which is no longer being updated at all. If the function is not returning any True values, this must simply mean that the last ticker (e.g. "AAPL") does not represent a dividend stock. So, to fix this you want to change the input for the function: def dividend(ticker). Write something like:

for filename in os.listdir("C:\\Users\Name\Stocks\dataset"):
    df = pd.read_csv("C:\\Users\Name\Stocks\dataset\{}".format(filename))
    
    # e.g. with filename like "HM-B.ST.csv", split at "."
    # and select only first part
    ticker = filename.split('.')[0]
    if dividend(ticker):
        print("{}".format(filename))

You need to make the same change for your function marketcap. Again, if this function is currently returning True values, this just means that your last list item references a stock has a higher mcap than the threshold. The reason why it seems to be working, is that you are using print("{}".format(filename)). But you are not actually passing the ticker that is connected to this filename.

Two further suggestions:

  • Use scientific notation for large numbers; instead of elif mcap > 10000000000, write elif mcap > 1E10. Less chance of inadvertently missing a zero, and easier to read for other users.
  • In terms of refactoring, try to use just one loop; you are basically doing the same loop twice. Also try to turn your functions into one function, or at least write it in such a way that you only have to make one call to yh.Ticker per ticker. I mean: you are reusing info = yf.Ticker(ticker).info unnecessarily.

New function looks like this:

def buy_dividend(ticker):
    if df.empty:
        pass
    else:
        last_close = df[-1:]['Close'].values[0]
        mean = df["Close"].mean()
        if last_close < mean:
            info = yf.Ticker(ticker).info
            mcap = info.get("marketCap") 
            if mcap is None:
                pass
            elif mcap > 1E10:
                PE = info.get('trailingPE')
                if PE is None:
                    pass
                elif PE < 20:
                    div = info.get("dividendYield")
                    if div is None:
                        pass
                    elif div > 0.04:
                        return True

for filename in os.listdir("C:\\Users\Andreas\Aktieanalys\dataset"):
    df = pd.read_csv("C:\\Users\Andreas\Aktieanalys\dataset\{}".format(filename))
    if buy_dividend(ticker):
        print("{} is a good buy".format(filename))

But somehow the dividend yield are messing things up. If the rows containing "div" are being #, then the function works perfect and correctly. Why is that?

Related