Select Page

You don’t want to miss stocks which are beginning to pickup momentum. However you are busy on your day job. You want to see which stocks are trading higher today compared to the previous days, but you can’t keep an eye on the market. The solution? Write a Python program that will screen the stocks’ current trading volume and compare them to previous days’ volume. Once your program gives you the list of stocks that you could potentially play, you grab your phone or the computer to place trade order(s).

Above is a sample result of the stocks screener. The output lists down the stocks that are trading higher along with other information:

  • Stock Ticker Symbol
  • %Change in Price
  • %Change to the Day’s High Price
  • Last Traded Price
  • Yesterday’s Close Price
  • Estimated $ Value Traded Today
  • Today’s Volume
  • %Change in Volume
  • 5-Day Volume Average
  • Target Price
  • Float Shares

This tutorial will be using free API:

  • Yahoo yFinance – for retrieving the company information such as name, market cap, target price, float shares. It was also used in downloading historical trading data and today’s data.

Here are the pre-requisite to accomplish this goal:

  • A little bit of programming background.
  • Python (e.g. Visual Studio, Pycharm, Google Collab or Jupyter)
  • A CSV file with S&P 500 tickers and name it sp500tickers.csv
  • To speed up loading of company information from the yFinance API, it is best to preload the data into a local CSV file. Below is preloadSp500.py. You may tweak which companies to include by updating and running. This will generate a new file named sp500companies.csv file which will be later on used in the stocks screener program.
import yfinance as yf
import csv
from datetime import datetime

now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Start Time = ", current_time)

def human_format(num):
    magnitude = 0
    formatted = ""
    if num is not None:
        while abs(num) >= 1000:
            magnitude += 1
            num /= 1000.0
        formatted = '%.2f%s' % (num, ['', 'K', 'M', 'B', 'T', 'P'][magnitude])
    else:
        formatted = "None"
    return formatted

def getInfo(info, tag):
    try:
        infoStr = info[tag]
        if infoStr is not None and tag == "shortName":
            infoStr = infoStr.replace(',', '')
        if infoStr is None:
            infoStr = ""
            if tag == "floatShares" or tag == "targetMeanPrice" or tag == "marketCap":
                infoStr = 0
    except Exception as e:
        print(f"error {e}")
        infoStr = ""
        if tag == "floatShares" or tag == "targetMeanPrice" or tag == "marketCap":
            infoStr = 0
        pass
    return infoStr

fileContents = ""
tickers = []
ctr = 0
with open('sp500tickers.csv') as f:
    for row in csv.reader(f):
        tickers.append(row[0])
        ctr += 1
i = 0

file = open('sp500companies.csv', 'a')
file.write("Ticker,Name,Country,MktCap,Float,Target,Yahoo URL")
while i < len(tickers):
    try:
        stock = tickers[i]  # Gets the current stock ticker
        print(f" {i} : {stock}")
        temp = yf.Ticker(str(stock))
        info = temp.info

        fileContents += f"\n{stock},{getInfo(info, 'shortName')},{getInfo(info, 'country')},{getInfo(info, 'marketCap')},{getInfo(info, 'floatShares')},{getInfo(info, 'targetMeanPrice')},https://finance.yahoo.com/quote/{stock}"
        i += 1  # Iteration to the next ticker
    except Exception as ex:
        i += 1
        print(ex)
        pass
file.write(fileContents)
file.close()

now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("End Time = ", current_time)

The above Python code should create a file named sp500companies.csv with the list of companies that you will screen.

  • After creating sp500companies.csv, the stocks’ historical data should also be created. This is done by running the snapshot.py This will create csv files for each ticker under the datasets directory. If there are 500 stocks in sp500companies.csv, there will also be 500 files under the datasets directory.

Here is snapshot.py that will automatically download historical prices

import yfinance as yf

with open('sp500tickers.csv') as f:
    lines = f.read().splitlines()
    for cell in lines:
        data = yf.download(cell, start="2021-06-01", end="2021-07-07")
        data.to_csv("datasets/{}.csv".format(cell))

Finally, you are ready to build the stocks screener in less than 100 lines of code. Below is a sample Python program that will do the job.

import yfinance as yf
import pandas
import os
import csv


def human_format(num):
    magnitude = 0
    formatted = ""
    if num is not None:
        try:
            if isinstance(num, str):
                num = float(num)
            while num >= 1000:
                magnitude += 1
                num /= 1000.0
            formatted = '%.2f%s' % (num, ['', 'K', 'M', 'B', 'T', 'P'][magnitude])
        except Exception as ex:
            formatted = num
    else:
        formatted = ""
    return formatted


fileContents = ""
Stocks_Not_Imported = 0
tickers = []
stocks = {}
ctr = 0
with open('sp500companies.csv') as f:
    for row in csv.reader(f):
        stocks[row[0]] = {'shortName': row[1], 'country': row[2], 'marketCap': row[3], 'floatShares': row[4], 'targetMeanPrice': row[5] }
        tickers.append(row[0])
        ctr += 1
total = len(tickers)
print("# of Stocks Filtered by Market Cap: " + str(total))
i = 0
error_symbols = []
stockTicker = ""

history = {}
for filename in os.listdir('datasets'):
    df = pandas.read_csv('datasets/{}'.format(filename))
    symbol = filename.split('.')[0]
    history[symbol] = df

while i < total:
    try:
        stockTicker = tickers[i]  # Gets the current stock ticker
        temp = yf.Ticker(stockTicker)
        hist = history[stockTicker]
        previous_avg_vol = hist['Volume'].iloc[1:4:1].mean()
        latestHist = temp.history(period="0d")

        todays_vol = latestHist['Volume'][0]
        if 9 <= now.hour <= 16:  # market hours: from 9am to 4pm
            factor = now.hour + (now.minute / 60) - 8
        else:  # premarket: from 12mn to 7am  and after market hours: 4pm to 12mn
            factor = 8
        prorated_avg = (previous_avg_vol / 12) * factor
        min_inc_factored = 2 + (.018 * factor)
        if todays_vol > (prorated_avg * min_inc_factored) and previous_avg_vol > 80000:
            todaysHigh = latestHist['High'][0]
            prevClose = hist['Close'][24]
            percent_change_dayhigh = (100 * ((todaysHigh / prevClose) - 1))

            if percent_change_dayhigh > 4:  # If the highest price for the day went up to 2%
                close = latestHist['Close'][0]
                percent_change = (100 * ((close / prevClose) - 1))
                inc = (todays_vol / prorated_avg) * 100

                printContents += f"\n{i} of {total} : Stk *{stockTicker} %Chng_Price={percent_change:.2f}% %Chng_DayHi={percent_change_dayhigh:.2f}% Price={close:.2f} Close_Price={prevClose:.2f} Est_$Vol=${human_format(todays_vol * close)} Vol={human_format(todays_vol)} %Chng_Vol={inc:.2f}% 5Day_Vol_Mean={human_format(previous_avg_vol)} Target_Price={stocks[stockTicker]['targetMeanPrice']} Float={human_format(stocks[stockTicker]['floatShares'])} MktCap={human_format(stocks[stockTicker]['marketCap'])} Factor={factor:.2f} Min_Vol={human_format(prorated_avg * min_inc_factored)} Min_%Chng_Vol={100 * min_inc_factored:.2f}% Country={stocks[stockTicker]['country']} ({stocks[stockTicker]['shortName']}) https://finance.yahoo.com/quote/{stockTicker}"

                print(f"\n{printContents}")
        i += 1  # Iteration to the next ticker
    except Exception as ex:
        i += 1
        Stocks_Not_Imported += 1
        print(ex)
        error_symbols.append(stockTicker)
        pass
print(
    f"The number of stocks we successfully screened: {i - Stocks_Not_Imported}. {Stocks_Not_Imported} stocks have errors.")

for index in range(len(error_symbols)):
    print(f"error_symbols: {error_symbols[index]}")

Once you are able to run the Python code smoothly, you may later on upgrade your program so that you receive an email or text message every time there is a volume increase on selected stocks.

Cheers!