Skip to content

Instantly share code, notes, and snippets.

@logic
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save logic/f3062554ee5fd2ba0477 to your computer and use it in GitHub Desktop.
Save logic/f3062554ee5fd2ba0477 to your computer and use it in GitHub Desktop.
Calculate how much money you'd leave on the table, if you quit your (stock-vesting) job right now.
#!/usr/bin/env python
"""Calculate how much money you'd leave on the table if you quit right now.
Place a file named TICKER-stock.csv (where TICKER is the ticker symbol you
want to track) in the same directory as this script, formatted as:
MM/DD/YYYY,shares
Where MM is the month, DD is the date, and YYYY is the year that "shares"
number of your TICKER shares will vest.
A file named "TICKER-cache.txt" (again, where TICKER is the ticker symbol
you looked up) will be created in the same directory as the script, caching
the last price retrieved from Yahoo Finance for up to an hour so you don't
keep requesting it (handy for running this when you logging in).
Run as "remaining.py <stock>", ie. "remaining.py MSFT".
"""
from __future__ import print_function
import argparse
import csv
import datetime
import json
import os
import urllib
DATADIR = os.path.dirname(__file__)
SHARES = os.path.join(DATADIR, "%s-shares.csv")
QUOTE = ("https://query.yahooapis.com/v1/public/yql?q=select%%20*%%20from"
"%%20yahoo.finance.quote%%20where%%20symbol%%3D%%22%s%%22&"
"format=json&diagnostics=true&env=store%%3A%%2F%%2Fdatatables.org"
"%%2Falltableswithkeys&callback=")
CACHED_QUOTE = os.path.join(DATADIR, "%s-cache.txt")
def get_stock(ticker):
"""Retrieve the current stock price for a given ticker symbol."""
cached = False
result = None
cachedate = 0
# Check if there's a cache.
try:
oldquote = os.stat(CACHED_QUOTE % ticker)
cachedate = datetime.datetime.fromtimestamp(oldquote.st_mtime)
result = open(CACHED_QUOTE % ticker, "r").read().strip()
cached = True
except (OSError, IOError):
pass
# If we didn't get a result from cache, or if the date on the cache is too
# old, force a reload from network.
cachelimit = datetime.datetime.now() - datetime.timedelta(hours=1)
if result is None or cachedate < cachelimit:
try:
query = json.load(urllib.urlopen(QUOTE % ticker))
result = query["query"]["results"]["quote"]["LastTradePriceOnly"]
with open(CACHED_QUOTE % ticker, "w") as oldquote:
print(result, file=oldquote)
cached = False
except: # pylint: disable=bare-except
# If we got this far and still don't have a result, bail out.
if result is None:
raise
return float(result), cached
def import_vesting(ticker):
"""Given a ticker symbol, parse a csv of vesting dates."""
vested = 0
vesting = {}
with open(SHARES % ticker, "r") as csvfh:
for date, amount in csv.reader(csvfh):
date = datetime.datetime.strptime(date, "%m/%d/%Y")
amount = int(amount)
if date > datetime.datetime.now():
vesting[date] = amount
else:
vested += amount
return vested, vesting
def output_upcoming(vesting, total, stockval):
"""For a set of upcoming vesting events, output a summary."""
shrwidth = max(len(str(x)) for x in vesting.itervalues())
for nextvest in sorted(vesting.keys()):
nextvestamt = vesting[nextvest]
nextshares = ("%%%dd" % shrwidth) % nextvestamt
nextvestpct = (float(nextvestamt) / total) * 100
nextvestval = nextvestamt * stockval
print(" On %s, %s (%.2f%%) shares will vest, worth $%.2f." %
(nextvest.strftime("%b %d %Y"), nextshares, nextvestpct,
nextvestval))
def output_remaining(ticker, verbose=False):
"""For the given ticker, output a summary of how much is left."""
vested, vesting = import_vesting(ticker)
unvested = sum(vesting.values())
total = vested + unvested
unvestpct = (float(unvested) / total) * 100
stockval, cached = get_stock(ticker)
unvestval = unvested * stockval
stock = "%.2f%s" % (stockval, " (cached)" if cached else "")
print("%d/%d (%.2f%%) shares, worth $%.2f at $%s/share" %
(unvested, total, unvestpct, unvestval, stock))
if verbose:
output_upcoming(vesting, total, stockval)
def main():
"""__main__"""
parser = argparse.ArgumentParser()
parser.add_argument("ticker", help="Stock ticker symbol to look up")
parser.add_argument("-v", "--verbose", action="store_true",
help="Show all upcoming vesting events")
args = parser.parse_args()
output_remaining(args.ticker, args.verbose)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment