A Python Program for a Stock Watchlist
7 April ’20
Simple Python Program for a Raspberry Pi
A little diversion from the usual data science posts Since I usually post an R script that does some data analysis, I thought it could not hurt to show I know some Python also.
<!DOCTYPE html>
StockWatch on Raspberry Pi Zero W¶
I created a Python program for my Raspberry Pi Zero W that could download stock data every night for a specific set of stocks I wanted to watch. For each stock ticker symbol, the program determines the company name, the most recent closing Price, the closing price from the previous day the market was open, and the percentage that the current price is off from the 52-week high. The data is stored in a CSV file. In the actual program, the CSV file is emailed to my phone, but I do not want to reveal my email information. I figured out how to email with the help of a Google search, and I did not do anything fancy.
# Load the required Python libraries
import pandas as pd # for Excel file
import pickle # for storing data - in a pickle named 'wsj_financials'
from datetime import date
from pandas_datareader import data
Function price(sym, today)¶
A function called prices takes the ticker symbol and the current date. It uses DataReader to access Yahoo! for the stock price data. I do not like using Yahoo! because they have changed things in the past, which broke my programs, but I do not know a better option at this time for what I am doing.
The output of this function is a Tuple that consists of the stock's current closing price, the closing price of the previous market session, and the computed percentage that the current price is off the 52-week-high.
def prices(sym, today):
"""Get the current price of a stock, the 52-week high,
and 52-week low.
Return the (price - high)/(high - low) ratio.
"""
# Get price data for the recent year
lastYear = date.fromordinal(today.toordinal()-365)
try:
price = data.DataReader(sym, start=lastYear,
end=today, data_source='yahoo')
except:
print("**** " + sym + " error!")
with open('./stock_errors.log', 'a') as out_file:
out_file.write(sym
+ " dropped due to price error! "
+ str(today) + "\n")
p = price['Close'] # 52-weeks (one year) of closing prices
high52 = p.max() # the 52-week high closing price
low52 = p.min() # the 52-week low closing price
latest = p[-1] # the most recent closing price
yesterdays = p[-2] # the closing price on the previous market session
try:
priceIndex = ((float(high52) - float(latest))
/ (float(high52) - float(low52))) # Compute the percentage off the 52-week-high
except: # if some stocks do not return sufficient data, save it in an error log
with open('./stock_errors.log', 'a') as out_file:
out_file.write(sym
+ " has insufficient data for 52-week range - price set to 0.0 "
+ str(today) + "\n")
priceIndex = 0.0
priceTuple = (latest, yesterdays, priceIndex) # Return the desired data
return priceTuple
The Main Section¶
The list of stock ticker symbols is saved in an Excel file. This Excel file is read to create an array of ticker sysmbols, which is named wsj_stocks. Just as an aside, I named it wsj_stocks because originally I was going to look at the thousand or so stocks that the Wall Street Journal covers. Not only was that too many stocks for me to "glance" through, I realized I care only for about 50 stocks or less. Also I do not care if the Wall Street Journal covers them or not. So I should rename the array "clif_stocks" but I just kept the original name.
# Look up the stock value of tickers as of today
today = date.today()
# Identify the file to read as an Excel file
xlsx = pd.ExcelFile('special 20200314.xlsx')
# Read the Excel file
wsj_stocks = pd.read_excel(xlsx, 'Sheet1', usecols=[0,1], header=0, skipinitialspace=True)
wsj_stocks # The list of stock tickers with their company names that will be included in the report.
For each stock ticker, the program calls the price() function and then saves the data in a data dictionary. Once in a dictionary, the ticker symbols can be sorted.
wsj = {} # dictionary to store the retrieved data
for index, row in wsj_stocks.iterrows():
ticker = row["SYM"].strip()
company = row["COMPANY"].strip()
try: # Attempt to get current price
priceTuple = prices(ticker, today) # Get the current price information of this stock
# priceTuple = (latest, yesterdays, priceIndex)
price = round(priceTuple[0],2)
yesterdays = round(priceTuple[1],2)
priceIndex = round(100.0 * priceTuple[2],2)
# Only save if the price was acquired
wsj[ticker] = {"PRICE": price,
"YESTERDAY": yesterdays,
"OFFHIGH": priceIndex,
"COMPANY": company}
except:
continue
# End for loop keys in wsj
A large string is constructed so that the information can be sent in an email or in this case just output to the screen.
# Compose the body of the email to be sent
body = "Select stocks to watch for " + str(today) + " compiled on a Raspberry Pi Zero W.\n"
body = body + "In alphabetical order by ticker symbol\n\n"
body = body + "Numbered, Ticker, Company, Closing Price, Yesterday's Close, Percentage Off High \n"
rating = 0
# Populate the body of the email message in alphabetical order
for sym in sorted(wsj.keys()):
rating += 1
thisStock = wsj[sym]
body = body + str(rating) + ": " + sym + ", " + \
str(thisStock['COMPANY']) + ", $" + \
str(thisStock['PRICE']) + ", $" + \
str(thisStock['YESTERDAY']) + ", " + \
str(thisStock['OFFHIGH']) + "% \n"
body = body + "\n\nDISCLAIMER: Code has been validated, but the potential for errors still exist!\n\n"
Print out the report¶
print(body)
The comma-delimited format of the output allows me to save it as a CSV file also and import it into R or Excel for further analysis at a later time.
- Dr. Clifton Baldwin
- April 7, 2020