Skip to content

Commit

Permalink
Add new premium source End of Day Historical Data (#2019)
Browse files Browse the repository at this point in the history
* Add new premium source https://eodhistoricaldata.com/r/?ref=869U7F4J

* Added eod dependency to requirements.txt

* Added eod dependency to requirements.txt via poetry and fixed typo

* fixed some display bugs for stock info

* Implemented stock/load for eodhd,  use keys / eodhd demo for key.

* Commit before Pull -Implemented stock/load for eodhd,  use keys / eodhd demo for key.

* Committing files so I can merge

* Committing files so I can merge

* Committing files so I can merge

* Committing files so I can merge

* Committing files so I can merge

* Committing files so I can merge

* Committing files so I can merge

* Merge

* Fixed dependencies

* Committing files so I can merge

* Committing Stock_Helper with pylint: disable=R091

* Downgraded charset normalizer

* Fixed issues with keys

* Committing fixes to eodhd

* Committing fixes to eodhd remove eod library

Co-authored-by: Colin Delahunty <72827203+colin99d@users.noreply.github.com>
Co-authored-by: colin99d <colin99delahunty@gmail.com>
  • Loading branch information
3 people authored Aug 31, 2022
1 parent 7df711d commit 2b0a9e2
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 1,113 deletions.
3 changes: 2 additions & 1 deletion data_sources_default.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"yf",
"iex",
"av",
"polygon"
"polygon",
"eodhd"
],
"dps": {
"psi": [
Expand Down
3 changes: 3 additions & 0 deletions openbb_terminal/config_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,6 @@

# https://academy.santiment.net/products-and-plans/create-an-api-key/
API_SANTIMENT_KEY = os.getenv("OPENBB_API_SANTIMENT_KEY") or "REPLACE_ME"

# https://eodhistoricaldata.com/r/?ref=869U7F4J
API_EODHD_TOKEN = os.getenv("OPENBB_API_EODHD_KEY") or "REPLACE_ME"
53 changes: 52 additions & 1 deletion openbb_terminal/keys_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
"ethplorer",
"smartstake",
"github",
"eodhd",
"messari",
"santiment",
]
Expand Down Expand Up @@ -755,6 +756,24 @@ def check_messari_key(self, show_output: bool = False) -> None:
if show_output:
console.print(self.key_dict["MESSARI"] + "\n")

def check_eodhd_key(self, show_output: bool = False) -> None:
"""Check End of Day Historical Data key"""
self.cfg_dict["EODHD"] = "eodhd"
if cfg.API_EODHD_TOKEN == "REPLACE_ME": # nosec
logger.info("End of Day Historical Data key not defined")
self.key_dict["EODHD"] = "not defined"
else:
try:
pyEX.Client(api_token=cfg.API_EODHD_TOKEN, version="v1")
logger.info("End of Day Historical Data key defined, test passed")
self.key_dict["EODHD"] = "defined, test passed"
except PyEXception:
logger.exception("End of Day Historical Data key defined, test failed")
self.key_dict["EODHD"] = "defined, test failed"

if show_output:
console.print(self.key_dict["EODHD"] + "\n")

def check_santiment_key(self, show_output: bool = False) -> None:
"""Check Santiment key"""
self.cfg_dict["SANTIMENT"] = "santiment"
Expand Down Expand Up @@ -816,6 +835,7 @@ def check_keys_status(self) -> None:
self.check_smartstake_key()
self.check_github_key()
self.check_messari_key()
self.check_eodhd_key()
self.check_santiment_key()

def print_help(self):
Expand Down Expand Up @@ -1693,6 +1713,7 @@ def call_coinglass(self, other_args: List[str]):
other_args.insert(0, "-k")
ns_parser = parse_simple_args(parser, other_args)
if ns_parser:
print(type(ns_parser.key))
os.environ["OPENBB_API_COINGLASS_KEY"] = ns_parser.key
dotenv.set_key(self.env_file, "OPENBB_API_COINGLASS_KEY", ns_parser.key)
cfg.API_COINGLASS_KEY = ns_parser.key
Expand Down Expand Up @@ -1832,6 +1853,35 @@ def call_messari(self, other_args: List[str]):
self.check_messari_key(show_output=True)

@log_start_end(log=logger)
def call_eodhd(self, other_args: List[str]):
"""Process eodhd command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="eodhd",
description="Set End of Day Historical Data API key.",
)
parser.add_argument(
"-k",
"--key",
type=str,
dest="key",
help="key",
)
if not other_args:
console.print(
"For your API Key, visit: https://eodhistoricaldata.com/r/?ref=869U7F4J\n"
)
return
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-k")
ns_parser = parse_simple_args(parser, other_args)
if ns_parser:
os.environ["API_EODHD_TOKEN"] = ns_parser.key
dotenv.set_key(self.env_file, "API_EODHD_TOKEN", ns_parser.key)
cfg.API_EODHD_TOKEN = ns_parser.key
self.check_eodhd_key(show_output=True)

def call_santiment(self, other_args: List[str]):
"""Process santiment command"""
parser = argparse.ArgumentParser(
Expand All @@ -1849,7 +1899,8 @@ def call_santiment(self, other_args: List[str]):
)
if not other_args:
console.print(
"For your API Key, visit: https://academy.santiment.net/products-and-plans/create-an-api-key\n"
"For your API Key, visit: "
"https://academy.santiment.net/products-and-plans/create-an-api-key\n"
)
return
if other_args and "-" not in other_args[0][0]:
Expand Down
7 changes: 3 additions & 4 deletions openbb_terminal/parent_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,10 +798,7 @@ def call_load(self, other_args: List[str]):
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-t")

ns_parser = self.parse_known_args_and_warn(
parser,
other_args,
)
ns_parser = self.parse_known_args_and_warn(parser, other_args)

if ns_parser:
if ns_parser.weekly and ns_parser.monthly:
Expand Down Expand Up @@ -864,6 +861,8 @@ def call_load(self, other_args: List[str]):

if ns_parser.source == "iex":
self.start = self.stock.index[0].to_pydatetime()
elif ns_parser.source == "eodhd":
self.start = self.stock.index[0].to_pydatetime()
else:
self.start = ns_parser.start
self.interval = f"{ns_parser.interval}min"
Expand Down
88 changes: 79 additions & 9 deletions openbb_terminal/stocks/stocks_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@
logger = logging.getLogger(__name__)

# pylint: disable=no-member,too-many-branches,C0302,R0913
# pylint: disable=R0915

INTERVALS = [1, 5, 15, 30, 60]
SOURCES = ["yf", "av", "iex"]
SOURCES = ["yf", "av", "iex", "eodhd"]

market_coverage_suffix = {
"USA": ["CBT", "CME", "NYB", "CMX", "NYM", "US", ""],
Expand Down Expand Up @@ -626,14 +627,21 @@ def load(
monthly: bool = False,
):
"""
Load a symbol to perform analysis using the string above as a template. Optional arguments and their
descriptions are listed above. The default source is, yFinance (https://pypi.org/project/yfinance/).
Alternatively, one may select either AlphaVantage (https://www.alphavantage.co/documentation/)
or IEX Cloud (https://iexcloud.io/docs/api/) as the data source for the analysis.
Please note that certain analytical features are exclusive to the source.
Load a symbol to perform analysis using the string above as a template.
Optional arguments and their descriptions are listed above.
The default source is, yFinance (https://pypi.org/project/yfinance/).
Other sources:
- AlphaVantage (https://www.alphavantage.co/documentation/)
- IEX Cloud (https://iexcloud.io/docs/api/)
- Eod Historical Data (https://eodhistoricaldata.com/financial-apis/)
Please note that certain analytical features are exclusive to the specific source.
To load a symbol from an exchange outside of the NYSE/NASDAQ default, use yFinance as the source and
add the corresponding exchange to the end of the symbol. i.e. ‘BNS.TO’.
add the corresponding exchange to the end of the symbol. i.e. ‘BNS.TO’. Note this may be possible with
other paid sources check their docs.
BNS is a dual-listed stock, there are separate options chains and order books for each listing.
Opportunities for arbitrage may arise from momentary pricing discrepancies between listings
Expand Down Expand Up @@ -749,6 +757,70 @@ def load(

df_stock_candidate.index.name = "date"

# TODO: eodhd start ###########################

# End of Day Historical Data Source
elif source == "eodhd":
df_stock_candidate = pd.DataFrame()

if weekly:
int_ = "w"
int_string = "Weekly"
elif monthly:
int_ = "m"
int_string = "Monthly"
else:
int_ = "d"
int_string = "Daily"

request_url = (
f"https://eodhistoricaldata.com/api/eod/"
f"{symbol.upper()}?"
f"{start_date.strftime('%Y-%m-%d')}&"
f"to={end_date.strftime('%Y-%m-%d')}&"
f"period={int_}&"
f"api_token={cfg.API_EODHD_TOKEN}&"
f"fmt=json&"
f"order=d"
)

r = requests.get(request_url)
if r.status_code != 200:
console.print("[red]Invalid API Key for eodhistoricaldata [/red]")
console.print(
"Get your Key here: https://eodhistoricaldata.com/r/?ref=869U7F4J\n"
)
return pd.DataFrame()

r_json = r.json()

df_stock_candidate = pd.DataFrame(r_json).dropna(axis=0)

# Check that loading a stock was not successful
if df_stock_candidate.empty:
console.print("No data found from End Of Day Historical Data.\n")
return df_stock_candidate

df_stock_candidate = df_stock_candidate[
["date", "open", "high", "low", "close", "adjusted_close", "volume"]
]

df_stock_candidate = df_stock_candidate.rename(
columns={
"date": "Date",
"close": "Close",
"high": "High",
"low": "Low",
"open": "Open",
"adjusted_close": "Adj Close",
"volume": "Volume",
}
)
df_stock_candidate["Date"] = pd.to_datetime(df_stock_candidate.Date)
df_stock_candidate.set_index("Date", inplace=True)
df_stock_candidate.sort_index(ascending=True, inplace=True)
# TODO: ###########################

# IEX Cloud Source
elif source == "iex":
df_stock_candidate = pd.DataFrame()
Expand Down Expand Up @@ -1382,12 +1454,10 @@ def find_trendline(

def additional_info_about_ticker(ticker: str) -> str:
"""Information about trading the ticker such as exchange, currency, timezone and market status
Parameters
----------
ticker : str
The stock ticker to extract if stock market is open or not
Returns
-------
str
Expand Down
Loading

0 comments on commit 2b0a9e2

Please sign in to comment.