Skip to content

Commit

Permalink
Feature/yieldcurve (#1734)
Browse files Browse the repository at this point in the history
* Adds yield curves

* Adds yield curves for several countries

* Adds yield curves for several countries

* Adds yield curves for several countries

* Adds yield curves for several countries

* Adds yield curves for several countries

* ycrv plots by default

* Limits source choices and renames raw columns

* Fix test

* Fix test

* lint

Co-authored-by: Jeroen Bouma <jer.bouma@gmail.com>
Co-authored-by: jose-donato <43375532+jose-donato@users.noreply.github.com>
Co-authored-by: didierlopes.eth <dro.lopes@campus.fct.unl.pt>
Co-authored-by: James Maslek <jmaslek11@gmail.com>
  • Loading branch information
5 people authored May 17, 2022
1 parent 26781cb commit 4f692f2
Show file tree
Hide file tree
Showing 12 changed files with 291 additions and 4 deletions.
4 changes: 3 additions & 1 deletion openbb_terminal/config_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
LOGGING_FREQUENCY = os.getenv("OPENBB_LOGGING_FREQUENCY") or "H"
# stdout,stderr,noop,file
LOGGING_HANDLERS = os.getenv("OPENBB_LOGGING_HANDLERS") or "file"
LOGGING_ROLLING_CLOCK = bool(strtobool(os.getenv("OPENBB_LOGGING_ROLLING_CLOCK", "False")))
LOGGING_ROLLING_CLOCK = bool(
strtobool(os.getenv("OPENBB_LOGGING_ROLLING_CLOCK", "False"))
)
# CRITICAL = 50
# FATAL = CRITICAL
# ERROR = 40
Expand Down
68 changes: 68 additions & 0 deletions openbb_terminal/economy/economy_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
fred_model,
yfinance_model,
yfinance_view,
investingcom_model,
investingcom_view,
plot_view,
)
from openbb_terminal.helper_funcs import (
Expand Down Expand Up @@ -63,6 +65,7 @@ class EconomyController(BaseController):
"rtps",
"industry",
"bigmac",
"ycrv",
]

CHOICES_MENUS = ["pred", "qa"]
Expand Down Expand Up @@ -142,6 +145,7 @@ class EconomyController(BaseController):
"country": "Country (U.S. listed stocks only)",
"capitalization": "Capitalization",
}
ycrv_sources = ["FRED", "investpy"]
PATH = "/economy/"
FILE_PATH = os.path.join(os.path.dirname(__file__), "README.md")

Expand Down Expand Up @@ -172,6 +176,11 @@ def __init__(self, queue: List[str] = None):
c: None for c in econdb_model.COUNTRY_CODES
}

self.choices["ycrv"]["-c"] = {c: None for c in investingcom_model.COUNTRIES}
self.choices["ycrv"]["--countries"] = {
c: None for c in investingcom_model.COUNTRIES
}

self.choices["valuation"]["-s"] = {
c: None for c in self.valuation_sort_cols
}
Expand Down Expand Up @@ -226,6 +235,7 @@ def print_help(self):
index find and plot any (major) index on the market [src][Source: Yahoo Finance][/src]
treasury obtain U.S. treasury rates [src][Source: EconDB][/src]
yield show the U.S. Treasury yield curve [src][Source: FRED][/src]
ycrv show sovereign yield curves [src][Source: Investing.com/FRED][/src]
plot plot data from the above commands together
options show the available options for 'plot' or show/export the data
Expand Down Expand Up @@ -968,6 +978,64 @@ def call_yield(self, other_args: List[str]):
if ns_parser:
fred_view.display_yield_curve(ns_parser.date)

@log_start_end(log=logger)
def call_ycrv(self, other_args: List[str]):
"""Process ycrv command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="ycrv",
description="Generate country yield curve. The yield curve shows the bond rates"
" at different maturities.",
)
parser.add_argument(
"-s",
"--source",
action="store",
dest="source",
choices=self.ycrv_sources,
type=str,
default="investpy",
help="Source for the data. If not supplied, the most recent entry from investpy will be used.",
)
parser.add_argument(
"-c",
"--country",
action="store",
dest="country",
nargs="+",
default="united states",
help="Display yield curve for specific country.",
)
parser.add_argument(
"-d",
"--date",
type=valid_date,
help="Date to get data from FRED. If not supplied, the most recent entry will be used.",
dest="date",
default=None,
)
ns_parser = parse_known_args_and_warn(
parser,
other_args,
export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED,
raw=True,
)
if ns_parser:
if isinstance(ns_parser.country, list):
ns_parser.country = " ".join(ns_parser.country)

investingcom_model.check_correct_country(ns_parser.country)

if ns_parser.source == "FRED":
fred_view.display_yield_curve(ns_parser.date)
elif ns_parser.source == "investpy":
investingcom_view.display_yieldcurve(
country=ns_parser.country,
raw=ns_parser.raw,
export=ns_parser.export,
)

@log_start_end(log=logger)
def call_plot(self, other_args: List[str]):
"""Process plot command"""
Expand Down
53 changes: 53 additions & 0 deletions openbb_terminal/economy/investingcom_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
""" Investing.com Model """
__docformat__ = "numpy"

import logging
import argparse

import pandas as pd
import investpy

from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import log_and_raise

logger = logging.getLogger(__name__)

COUNTRIES = investpy.bonds.get_bond_countries()


def check_correct_country(country):
"""Argparse type to check that correct country is inserted"""
if country not in investpy.bonds.get_bond_countries():
log_and_raise(
argparse.ArgumentTypeError(
f"{country} is an invalid country. Choose from {', '.join(investpy.bonds.get_bond_countries())}"
)
)
return country


@log_start_end(log=logger)
def get_yieldcurve(country) -> pd.DataFrame:
"""Get country yield curve [Source: Investing.com]
Returns
-------
pd.DataFrame
Country yield curve
"""

data = investpy.bonds.get_bonds_overview(country)
data.drop(columns=data.columns[0], axis=1, inplace=True)
data.rename(
columns={
"name": "Tenor",
"last": "Current",
"last_close": "Previous",
"high": "High",
"low": "Low",
"change": "Change",
"change_percentage": "% Change",
},
inplace=True,
)
return data
114 changes: 114 additions & 0 deletions openbb_terminal/economy/investingcom_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
""" Investing.com View """
__docformat__ = "numpy"

import logging
import os
from typing import Optional, List

import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters

from openbb_terminal.config_plot import PLOT_DPI
from openbb_terminal.config_terminal import theme
from openbb_terminal.decorators import log_start_end
from openbb_terminal.economy import investingcom_model
from openbb_terminal.helper_funcs import (
export_data,
plot_autoscale,
print_rich_table,
)
from openbb_terminal.rich_config import console

logger = logging.getLogger(__name__)

register_matplotlib_converters()

tenors_dict = {
"1M": 1 / 12,
"3M": 0.25,
"6M": 0.5,
"9M": 0.75,
"1Y": 1,
"2Y": 2,
"3Y": 3,
"4Y": 4,
"5Y": 5,
"6Y": 6,
"7Y": 7,
"8Y": 8,
"9Y": 9,
"10Y": 10,
"15Y": 15,
"20Y": 20,
"25Y": 25,
"30Y": 30,
"50Y": 50,
}


@log_start_end(log=logger)
def display_yieldcurve(
country: str,
external_axes: Optional[List[plt.Axes]] = None,
raw: bool = False,
export: str = "",
):
"""Display yield curve. [Source: Investing.com]
Parameters
----------
country: str
Country to display
export : str
Export dataframe data to csv,json,xlsx file
"""

df = investingcom_model.get_yieldcurve(country)
df = df.replace(float("NaN"), "")

if df.empty:
console.print(f"[red]Yield data not found for {country.title()}[/red].\n")
return
if external_axes is None:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

else:
if len(external_axes) != 1:
logger.error("Expected list of 3 axis items")
console.print("[red]Expected list of 3 axis items.\n[/red]")
return
(ax,) = external_axes

tenors = []
for i, row in df.iterrows():
t = row["Tenor"][-3:].strip()
df.at[i, "Tenor"] = t
if t[-1] == "M":
tenors.append(int(t[:-1]) / 12)
elif t[-1] == "Y":
tenors.append(int(t[:-1]))

ax.plot(tenors, df["Current"], "-o")
ax.set_xlabel("Maturity")
ax.set_ylabel("Rate (%)")
theme.style_primary_axis(ax)
if external_axes is None:
ax.set_title(f"Yield Curve for {country.title()} ")
theme.visualize_output()

if raw:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title=f"{country.title()} Yield Curve",
floatfmt=".3f",
)
console.print("")

export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"ycrv",
df,
)
10 changes: 10 additions & 0 deletions tests/openbb_terminal/economy/test_economy_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ def test_call_func_expect_queue(expected_queue, func, queue):
map_type="world",
),
),
(
"call_ycrv",
[
"--country=portugal",
"--export=csv",
],
"investingcom_view.display_yieldcurve",
[],
dict(country="portugal", export="csv", raw=False),
),
],
)
def test_call_func(
Expand Down
24 changes: 24 additions & 0 deletions tests/openbb_terminal/economy/test_investingcom_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# IMPORTATION STANDARD

# IMPORTATION THIRDPARTY
import pandas as pd
import pytest

# IMPORTATION INTERNAL
from openbb_terminal.economy import investingcom_model


# @pytest.mark.vcr
@pytest.mark.parametrize(
"country",
[
"united states",
"portugal",
"spain",
"germany",
],
)
def test_get_yieldcurve(country):
result_df = investingcom_model.get_yieldcurve(country)

assert isinstance(result_df, pd.DataFrame)
16 changes: 16 additions & 0 deletions tests/openbb_terminal/economy/test_investingcom_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# IMPORTATION STANDARD
# import gzip

# IMPORTATION THIRDPARTY
# import pandas as pd

# import pytest

# IMPORTATION INTERNAL
from openbb_terminal.economy import investingcom_view


# @pytest.mark.vcr
# @pytest.mark.record_stdout
def test_display_yieldcurve():
investingcom_view.display_yieldcurve(country="portugal", export="")
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
The maturity 3y is not an option for inflation. Please choose between 5y, 7y, 10y, 20y, 30y

Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
No data found for the combination nominal and 1m.
No data found for the combination nominal and 30y.

Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
The maturity 3y is not an option for inflation. Please choose between 5y, 7y, 10y, 20y, 30y

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Macro Data
index find and plot any (major) index on the market [Source: Yahoo Finance]
treasury obtain U.S. treasury rates [Source: EconDB]
yield show the U.S. Treasury yield curve [Source: FRED]
ycrv show sovereign yield curves [Source: Investing.com/FRED]
plot plot data from the above commands together
options show the available options for 'plot' or show/export the data

Expand Down
2 changes: 2 additions & 0 deletions website/data/menu/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,8 @@ main:
ref: "/terminal/economy/treasury"
- name: yield
ref: "/terminal/economy/yield"
- name: ycrv
ref: "/terminal/economy/ycrv"
- name: plot
ref: "/terminal/economy/plot"
- name: rtps
Expand Down

0 comments on commit 4f692f2

Please sign in to comment.