mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Parity (#806)
* 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 Co-authored-by: Colin Delahunty <colindelahunty@Colins-MacBook-Air.local> Co-authored-by: Colin Delahunty <colindelahunty@Colins-Air.indiana.edu>
This commit is contained in:
@@ -17,6 +17,7 @@ from colorama import Fore, Style
|
||||
from pandas._config.config import get_option
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
import pandas.io.formats.format
|
||||
import requests
|
||||
from screeninfo import get_monitors
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal import config_plot as cfgPlot
|
||||
@@ -711,3 +712,23 @@ def export_data(
|
||||
print("Wrong export file specified.\n")
|
||||
|
||||
print(f"Saved file: {saved_path}\n")
|
||||
|
||||
|
||||
def get_rf() -> float:
|
||||
"""
|
||||
Uses the fiscaldata.gov API to get most recent T-Bill rate
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The current US T-Bill rate
|
||||
"""
|
||||
try:
|
||||
base = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
|
||||
end = "/v2/accounting/od/avg_interest_rates"
|
||||
filters = "?filter=security_desc:eq:Treasury Bills&sort=-record_date"
|
||||
response = requests.get(base + end + filters)
|
||||
latest = response.json()["data"][0]
|
||||
return round(float(latest["avg_interest_rate_amt"]) / 100, 8)
|
||||
except Exception:
|
||||
return 0.02
|
||||
|
||||
@@ -62,6 +62,7 @@ class OptionsController:
|
||||
"unu",
|
||||
"stocks",
|
||||
"payoff",
|
||||
"parity",
|
||||
"smile",
|
||||
]
|
||||
|
||||
@@ -138,6 +139,7 @@ Current Expiry: {self.selected_date or None}
|
||||
hist plot option history [Tradier]
|
||||
grhist plot option greek history [Syncretism.io]
|
||||
smile plot the volatility smile for the expiration date [Yfinance]
|
||||
parity shows whether options are above or below expected price [Yfinance]
|
||||
> payoff shows payoff diagram for a selection of options [Yfinance]
|
||||
{Style.RESET_ALL if not colored else ''}"""
|
||||
print(help_text)
|
||||
@@ -1076,6 +1078,66 @@ Current Expiry: {self.selected_date or None}
|
||||
"""Process stocks command"""
|
||||
return stocks_controller.menu(self.ticker)
|
||||
|
||||
def call_parity(self, other_args: List[str]):
|
||||
"""Process parity command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="parity",
|
||||
description="Shows whether options are over or under valued",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--put",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="put",
|
||||
help="Shows puts instead of calls",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--ask",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="ask",
|
||||
help="Use ask price instead of lastPrice",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
"--min",
|
||||
type=float,
|
||||
default=None,
|
||||
dest="mini",
|
||||
help="Minimum strike price shown",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-M",
|
||||
"--max",
|
||||
type=float,
|
||||
default=None,
|
||||
dest="maxi",
|
||||
help="Maximum strike price shown",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if not self.ticker and not self.selected_date:
|
||||
print("Ticker and expiration required. \n")
|
||||
return
|
||||
yfinance_view.show_parity(
|
||||
self.ticker,
|
||||
self.selected_date,
|
||||
ns_parser.put,
|
||||
ns_parser.ask,
|
||||
ns_parser.mini,
|
||||
ns_parser.maxi,
|
||||
)
|
||||
print("")
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def menu(ticker: str = ""):
|
||||
"""Options Menu."""
|
||||
|
||||
@@ -4,18 +4,25 @@ __docformat__ = "numpy"
|
||||
import os
|
||||
from bisect import bisect_left
|
||||
from typing import List, Dict, Any
|
||||
from datetime import datetime, date
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import seaborn as sns
|
||||
import yfinance as yf
|
||||
from tabulate import tabulate
|
||||
|
||||
import gamestonk_terminal.config_plot as cfp
|
||||
import gamestonk_terminal.feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import export_data, plot_autoscale
|
||||
from gamestonk_terminal.options import op_helpers, yfinance_model
|
||||
from gamestonk_terminal.options.yfinance_model import generate_data
|
||||
from gamestonk_terminal.options.yfinance_model import (
|
||||
generate_data,
|
||||
get_option_chain,
|
||||
get_price,
|
||||
)
|
||||
from gamestonk_terminal.helper_funcs import get_rf
|
||||
|
||||
|
||||
def plot_oi(
|
||||
@@ -448,3 +455,79 @@ def plot_payoff(
|
||||
plt.legend()
|
||||
plt.show()
|
||||
print("")
|
||||
|
||||
|
||||
def show_parity(
|
||||
ticker: str, exp: str, put: bool, ask: bool, mini: float, maxi: float
|
||||
) -> None:
|
||||
"""Prints options and whether they are under or over priced [Source: Yahoo Finance]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
Ticker to get expirations for
|
||||
exp: str
|
||||
Expiration to use for options
|
||||
put: bool
|
||||
Whether to use puts or calls
|
||||
ask: bool
|
||||
Whether to use ask or lastPrice
|
||||
mini: float
|
||||
Minimum strike price to show
|
||||
maxi: float
|
||||
Maximum strike price to show
|
||||
|
||||
"""
|
||||
r_date = datetime.strptime(exp, "%Y-%m-%d").date()
|
||||
delta = (r_date - date.today()).days / 365
|
||||
rate = ((1 + get_rf()) ** delta) - 1
|
||||
stock = get_price(ticker)
|
||||
chain = get_option_chain(ticker, exp)
|
||||
name = "ask" if ask else "lastPrice"
|
||||
o_type = "put" if put else "call"
|
||||
|
||||
calls = chain.calls[["strike", name]].copy()
|
||||
calls = calls.rename(columns={name: "callPrice"})
|
||||
puts = chain.puts[["strike", name]].copy()
|
||||
puts = puts.rename(columns={name: "putPrice"})
|
||||
|
||||
opts = pd.merge(calls, puts, on="strike")
|
||||
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
|
||||
|
||||
diff = o_type + " Difference"
|
||||
opts[diff] = opts[o_type + "Price"] - opts[o_type + "Parity"]
|
||||
opts["distance"] = abs(stock - opts["strike"])
|
||||
filtered = opts.copy()
|
||||
|
||||
if mini is None:
|
||||
mini = filtered.strike.quantile(0.25)
|
||||
if maxi is None:
|
||||
maxi = filtered.strike.quantile(0.75)
|
||||
|
||||
filtered = filtered.loc[filtered["strike"] > mini]
|
||||
filtered = filtered.loc[filtered["strike"] < maxi]
|
||||
|
||||
show = filtered[["strike", diff]].copy()
|
||||
|
||||
print("Warning: Low volume options may be difficult to trade.\n")
|
||||
if ask:
|
||||
print("Warning: Options with no current ask price not shown.\n")
|
||||
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
show,
|
||||
headers=[x.title() for x in show.columns],
|
||||
tablefmt="fancy_grid",
|
||||
showindex=False,
|
||||
floatfmt=".2f",
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(show.to_string(index=False))
|
||||
|
||||
print("")
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import requests
|
||||
|
||||
# These are all the possible yfinance properties
|
||||
l_valid_property_infos = [
|
||||
@@ -106,16 +105,3 @@ def check_valid_property_type(aproperty: str) -> str:
|
||||
return aproperty
|
||||
|
||||
raise argparse.ArgumentTypeError(f"{aproperty} is not a valid info")
|
||||
|
||||
|
||||
def get_rf() -> float:
|
||||
"""Uses the fiscaldata.gov API to get most recent T-Bill rate"""
|
||||
try:
|
||||
base = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
|
||||
end = "/v2/accounting/od/avg_interest_rates"
|
||||
filters = "?filter=security_desc:eq:Treasury Bills&sort=-record_date"
|
||||
response = requests.get(base + end + filters)
|
||||
latest = response.json()["data"][0]
|
||||
return round(float(latest["avg_interest_rate_amt"]) / 100, 8)
|
||||
except Exception:
|
||||
return 0.02
|
||||
|
||||
@@ -16,7 +16,7 @@ from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
from gamestonk_terminal.portfolio.portfolio_optimization import optimizer_model
|
||||
from gamestonk_terminal.portfolio.portfolio_optimization.optimizer_helper import get_rf
|
||||
from gamestonk_terminal.helper_funcs import get_rf
|
||||
|
||||
d_period = {
|
||||
"1d": "[1 Day]",
|
||||
|
||||
@@ -18,7 +18,7 @@ from gamestonk_terminal.portfolio.portfolio_optimization import (
|
||||
optimizer_helper,
|
||||
)
|
||||
|
||||
from gamestonk_terminal.portfolio.portfolio_optimization.optimizer_helper import get_rf
|
||||
from gamestonk_terminal.helper_funcs import get_rf
|
||||
|
||||
period_choices = [
|
||||
"1d",
|
||||
|
||||
@@ -11,7 +11,6 @@ from openpyxl.styles import Border, Side, Font, PatternFill, Alignment
|
||||
from openpyxl import worksheet
|
||||
import yfinance as yf
|
||||
import pandas as pd
|
||||
import requests
|
||||
|
||||
|
||||
opts = Union[int, str, float]
|
||||
@@ -60,16 +59,6 @@ def set_cell(
|
||||
ws[cell].number_format = num_form
|
||||
|
||||
|
||||
def get_rf():
|
||||
"""Uses the fiscaldata.gov API to get most recent T-Bill rate"""
|
||||
base = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service"
|
||||
end = "/v2/accounting/od/avg_interest_rates"
|
||||
filters = "?filter=security_desc:eq:Treasury Bills&sort=-record_date"
|
||||
response = requests.get(base + end + filters)
|
||||
latest = response.json()["data"][0]
|
||||
return latest["avg_interest_rate_amt"]
|
||||
|
||||
|
||||
def get_fama_raw():
|
||||
"""Gets base Fama French data to calculate risk"""
|
||||
with urlopen(
|
||||
|
||||
@@ -21,6 +21,8 @@ import requests
|
||||
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import dcf_model
|
||||
|
||||
from gamestonk_terminal.helper_funcs import get_rf
|
||||
|
||||
int_or_str = Union[int, str]
|
||||
|
||||
|
||||
@@ -90,7 +92,7 @@ class CreateExcelFA:
|
||||
self.df_is: pd.DataFrame = self.get_data("IS", self.is_start, True)
|
||||
self.df_cf: pd.DataFrame = self.get_data("CF", self.cf_start, False)
|
||||
self.info: pd.DataFrame = yf.Ticker(ticker).info
|
||||
self.t_bill: float = dcf_model.get_rf()
|
||||
self.t_bill: float = get_rf()
|
||||
self.r_ff: int = dcf_model.get_fama_coe(self.ticker)
|
||||
|
||||
def create_workbook(self):
|
||||
|
||||
14
website/content/options/parity/_index.md
vendored
Normal file
14
website/content/options/parity/_index.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
```
|
||||
usage: parity [-p] [-a] [-m MINIMUM] [-M MAXIMUM] [-h]
|
||||
```
|
||||
|
||||
shows the parity for options. in theory a short plus a stock should equal a call plus a bond.
|
||||
|
||||
```
|
||||
optional arguments:
|
||||
-a, --ask uses ask price instead of lastPrice (default: False)
|
||||
-p, --put shows puts instead of calls (default: False)
|
||||
-m, --min the minimum strike price to be shown (default: None)
|
||||
-M, --max the maximum strike price to be shown (default: None)
|
||||
-h, --help show this help message (default: False)
|
||||
```
|
||||
6
website/data/menu/main.yml
vendored
6
website/data/menu/main.yml
vendored
@@ -584,8 +584,10 @@ main:
|
||||
ref: "/options/grhist"
|
||||
- name: smile
|
||||
ref: "/options/smile"
|
||||
- name: portfolio optimization
|
||||
ref: "/portfolio/portfolio_optimization"
|
||||
- name: parity
|
||||
ref: "/options/parity"
|
||||
- name: payoff
|
||||
ref: "/options/payoff"
|
||||
sub:
|
||||
- name: add
|
||||
ref: "/options/payoff/add"
|
||||
|
||||
Reference in New Issue
Block a user