From e5b4c1175ebd91f30f983ee3f253f0e9a79ce8ee Mon Sep 17 00:00:00 2001 From: Colin Delahunty <72827203+colin99d@users.noreply.github.com> Date: Sat, 16 Oct 2021 06:42:49 -0400 Subject: [PATCH] Parity Dividends (#812) * Refactored code, added parity * Got call price * Finalized feature * added documentation * Added changes except number limit * Added limit to number of data points * Updated duplicated variable names * Added docstrings, updated filtering * Added PV of dividends Co-authored-by: Colin Delahunty Co-authored-by: Colin Delahunty --- gamestonk_terminal/options/yfinance_model.py | 18 ++++++++++ gamestonk_terminal/options/yfinance_view.py | 37 +++++++++++++++++--- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/gamestonk_terminal/options/yfinance_model.py b/gamestonk_terminal/options/yfinance_model.py index 098325ddc05..4e64dd21b4b 100644 --- a/gamestonk_terminal/options/yfinance_model.py +++ b/gamestonk_terminal/options/yfinance_model.py @@ -47,6 +47,24 @@ def get_option_chain(ticker: str, expiration: str) -> pd.DataFrame: return chains +def get_dividend(ticker: str) -> pd.Series: + """Gets option chain from yf for given ticker and expiration + + Parameters + ---------- + ticker: str + Ticker to get options for + + Returns + ------- + chains: yf.ticker.Dividends + Dividends + """ + yf_ticker = yf.Ticker(ticker) + dividend = yf_ticker.dividends + return dividend + + def get_x_values(current_price: float, options: List[Dict[str, int]]) -> List[float]: """Generates different price values that need to be tested""" x_list = list(range(101)) diff --git a/gamestonk_terminal/options/yfinance_view.py b/gamestonk_terminal/options/yfinance_view.py index 9f507fdd943..a35e81b102e 100644 --- a/gamestonk_terminal/options/yfinance_view.py +++ b/gamestonk_terminal/options/yfinance_view.py @@ -4,7 +4,7 @@ __docformat__ = "numpy" import os from bisect import bisect_left from typing import List, Dict, Any -from datetime import datetime, date +from datetime import datetime, date, timedelta import matplotlib.pyplot as plt import numpy as np @@ -479,9 +479,32 @@ def show_parity( """ r_date = datetime.strptime(exp, "%Y-%m-%d").date() - delta = (r_date - date.today()).days / 365 - rate = ((1 + get_rf()) ** delta) - 1 + delta = (r_date - date.today()).days + rate = ((1 + get_rf()) ** (delta / 365)) - 1 stock = get_price(ticker) + + div_info = yfinance_model.get_dividend(ticker) + div_dts = div_info.index.values.tolist() + + if div_dts: + last_div = pd.to_datetime(div_dts[-1]) + + if len(div_dts) > 3: + avg_div = np.mean(div_info.to_list()[-4:]) + else: + avg_div = np.mean(div_info.to_list()) + + next_div = last_div + timedelta(days=91) + dividends = [] + while next_div < datetime.strptime(exp, "%Y-%m-%d"): + day_dif = (next_div - datetime.now()).days + dividends.append((avg_div, day_dif)) + next_div += timedelta(days=91) + div_pvs = [x[0] / ((1 + get_rf()) ** (x[1] / 365)) for x in dividends] + pv_dividend = sum(div_pvs) + else: + pv_dividend = 0 + chain = get_option_chain(ticker, exp) name = "ask" if ask else "lastPrice" o_type = "put" if put else "call" @@ -495,8 +518,12 @@ def show_parity( opts = opts.dropna() opts = opts.loc[opts["callPrice"] * opts["putPrice"] != 0] - opts["callParity"] = opts["putPrice"] + stock - (opts["strike"] / (1 + rate)) - opts["putParity"] = (opts["strike"] / (1 + rate)) + opts["callPrice"] - stock + opts["callParity"] = ( + opts["putPrice"] + stock - (opts["strike"] / (1 + rate)) - pv_dividend + ) + opts["putParity"] = ( + (opts["strike"] / (1 + rate)) + opts["callPrice"] - stock + pv_dividend + ) diff = o_type + " Difference" opts[diff] = opts[o_type + "Price"] - opts[o_type + "Parity"]