Adding databento as a source (#4293)

* First commit

* Baby steps

* Keys and sdk

* Fix import for api key

* Add SDK endpoints

* Test + api checks

* tests

* roque print of api key

* Changes

* minor

* custom timeout

* improve timeouts

---------

Co-authored-by: hjoaquim <h.joaquim@campus.fct.unl.pt>
This commit is contained in:
James Maslek
2023-02-24 10:33:45 -05:00
committed by GitHub
parent f1a824a179
commit eea170bdda
25 changed files with 1266 additions and 642 deletions

View File

@@ -200,3 +200,6 @@ OPENBB_PERSONAL_ACCESS_TOKEN = (
# https://intrinio.com/starter-plan
API_INTRINIO_KEY = os.getenv("OPENBB_API_INTRINIO_KEY") or "REPLACE_ME"
# https://databento.com/
API_DATABENTO_KEY = os.getenv("OPENBB_API_DATABENTO_KEY") or "REPLACE_ME"

View File

@@ -0,0 +1,118 @@
"""DataBento view"""
__docformat__ = "numpy"
import os
from typing import List, Optional
import mplfinance as mpf
from matplotlib import pyplot as plt
from openbb_terminal.config_terminal import theme
from openbb_terminal.helper_funcs import (
export_data,
is_valid_axes_count,
lambda_long_number_format_y_axis,
plot_autoscale,
print_rich_table,
)
from openbb_terminal.rich_config import console
from openbb_terminal.stocks import databento_model
def display_historical(
symbol: str,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
raw: bool = False,
export: str = "",
sheet_name: Optional[str] = None,
external_axes: Optional[List[plt.Axes]] = None,
):
"""Display historical futures [Source: DataBento]
Parameters
----------
symbol: List[str]
Symbol to display
start_date: Optional[str]
Start date of the historical data with format YYYY-MM-DD
end_date: Optional[str]
End date of the historical data with format YYYY-MM-DD
raw: bool
Display futures timeseries in raw format
sheet_name: str
Optionally specify the name of the sheet the data is exported to.
export: str
Type of format to export data
external_axes : Optional[List[plt.Axes]], optional
External axes (1 axis is expected in the list), by default None
"""
data = databento_model.get_historical_futures(
symbol.upper(), start_date=start_date, end_date=end_date
)
if data.empty:
console.print(f"No data found for {symbol}.")
return
# We check if there's Volume data to avoid errors and empty subplots
has_volume = False
if "Volume" in data.columns:
has_volume = bool(data["Volume"].sum() > 0)
candle_chart_kwargs = {
"type": "candle",
"style": theme.mpf_style,
"volume": has_volume,
"addplot": [],
"xrotation": theme.xticks_rotation,
"scale_padding": {"left": 0.3, "right": 1, "top": 0.8, "bottom": 0.8},
"update_width_config": {
"candle_linewidth": 0.6,
"candle_width": 0.8,
"volume_linewidth": 0.8,
"volume_width": 0.8,
},
"warn_too_much_data": 10000,
}
if external_axes is None:
candle_chart_kwargs["returnfig"] = True
candle_chart_kwargs["figratio"] = (10, 7)
candle_chart_kwargs["figscale"] = 1.10
candle_chart_kwargs["figsize"] = plot_autoscale()
candle_chart_kwargs["warn_too_much_data"] = 100_000
fig, ax = mpf.plot(data, **candle_chart_kwargs)
if has_volume:
lambda_long_number_format_y_axis(data, "Volume", ax)
fig.suptitle(
f"{symbol}",
x=0.055,
y=0.965,
horizontalalignment="left",
)
theme.visualize_output(force_tight_layout=False)
elif (has_volume and is_valid_axes_count(external_axes, 2)) or (
not has_volume and is_valid_axes_count(external_axes, 1)
):
candle_chart_kwargs["ax"] = external_axes[0]
if has_volume:
candle_chart_kwargs["volume"] = external_axes[1]
mpf.plot(data, **candle_chart_kwargs)
if raw:
print_rich_table(
data,
headers=list(data.columns),
show_index=True,
title="Futures timeseries",
)
console.print()
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"historical_db",
data,
sheet_name,
)

View File

@@ -11,7 +11,7 @@ from typing import List, Optional
from openbb_terminal import feature_flags as obbff
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
from openbb_terminal.decorators import log_start_end
from openbb_terminal.futures import yfinance_model, yfinance_view
from openbb_terminal.futures import databento_view, yfinance_model, yfinance_view
from openbb_terminal.helper_funcs import (
EXPORT_BOTH_RAW_DATA_AND_FIGURES,
EXPORT_ONLY_RAW_DATA_ALLOWED,
@@ -165,8 +165,8 @@ class FuturesController(BaseController):
"--start",
dest="start",
type=valid_date,
help="Initial date. Default: 3 years ago",
default=(datetime.now() - timedelta(days=3 * 365)),
help="Initial date. Default: 2 years ago",
default=(datetime.now() - timedelta(days=2 * 365)),
)
parser.add_argument(
"-e",
@@ -193,17 +193,29 @@ class FuturesController(BaseController):
raw=True,
)
if ns_parser:
yfinance_view.display_historical(
symbols=ns_parser.ticker.upper().split(","),
expiry=ns_parser.expiry,
start_date=ns_parser.start.strftime("%Y-%m-%d"),
end_date=ns_parser.end.strftime("%Y-%m-%d"),
raw=ns_parser.raw,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
if ns_parser.source == "YahooFinance":
yfinance_view.display_historical(
symbols=ns_parser.ticker.upper().split(","),
expiry=ns_parser.expiry,
start_date=ns_parser.start.strftime("%Y-%m-%d"),
end_date=ns_parser.end.strftime("%Y-%m-%d"),
raw=ns_parser.raw,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
if ns_parser.source == "DataBento":
databento_view.display_historical(
symbol=ns_parser.ticker,
start_date=ns_parser.start.strftime("%Y-%m-%d"),
end_date=ns_parser.end.strftime("%Y-%m-%d"),
raw=ns_parser.raw,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
def call_curve(self, other_args: List[str]):

View File

@@ -0,0 +1,31 @@
"""SDK Helper Functions"""
__docformat__ = "numpy"
from typing import List, Optional, Union
import pandas as pd
from openbb_terminal.futures import yfinance_model
from openbb_terminal.stocks import databento_model
def get_historical(
symbols: Union[str, List[str]],
start_date: str,
end_date: str,
source: Optional[str] = "YahooFinance",
expiry: Optional[str] = "",
) -> pd.DataFrame:
"""Get historical futures data"""
if source == "YahooFinance":
if isinstance(symbols, str):
symbols = [symbols]
return yfinance_model.get_historical_futures(
symbols, expiry, start_date, end_date
)
if source == "DataBento":
if isinstance(symbols, list):
print("DataBento only supports one symbol at a time. Using first symbol.")
symbols = symbols[0]
return databento_model.get_historical_futures(symbols, start_date, end_date)
return pd.DataFrame()

View File

@@ -99,7 +99,7 @@ def get_historical_futures(
Returns
-------
pd.DataFrame
Dictionary with sector weightings allocation
Historical futures data
"""
if start_date is None:

View File

@@ -44,10 +44,7 @@ from openbb_terminal import (
config_terminal as cfg,
feature_flags as obbff,
)
from openbb_terminal.core.config.paths import (
HOME_DIRECTORY,
USER_EXPORTS_DIRECTORY,
)
from openbb_terminal.core.config.paths import HOME_DIRECTORY, USER_EXPORTS_DIRECTORY
from openbb_terminal.rich_config import console
try:
@@ -1967,7 +1964,9 @@ def check_start_less_than_end(start_date: str, end_date: str) -> bool:
# Write an abstract helper to make requests from a url with potential headers and params
def request(url: str, method="GET", **kwargs) -> requests.Response:
def request(
url: str, method: str = "GET", timeout: int = 0, **kwargs
) -> requests.Response:
"""Abstract helper to make requests from a url with potential headers and params.
Parameters
@@ -1990,15 +1989,15 @@ def request(url: str, method="GET", **kwargs) -> requests.Response:
# We want to add a user agent to the request, so check if there are any headers
# If there are headers, check if there is a user agent, if not add one.
# Some requests seem to work only with a specific user agent, so we want to be able to override it.
headers = kwargs.pop("headers") if "headers" in kwargs else {}
headers = kwargs.pop("headers", {})
timeout = timeout or cfg.REQUEST_TIMEOUT
if "User-Agent" not in headers:
headers["User-Agent"] = get_user_agent()
if method.upper() == "GET":
return requests.get(url, headers=headers, timeout=cfg.REQUEST_TIMEOUT, **kwargs)
return requests.get(url, headers=headers, timeout=timeout, **kwargs)
if method.upper() == "POST":
return requests.post(
url, headers=headers, timeout=cfg.REQUEST_TIMEOUT, **kwargs
)
return requests.post(url, headers=headers, timeout=timeout, **kwargs)
raise ValueError("Method must be GET or POST")

View File

@@ -1140,6 +1140,34 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
key=ns_parser.key, persist=True, show_output=True
)
@log_start_end(log=logger)
def call_databento(self, other_args: List[str]):
"""Process databento command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="databento",
description="Set DataBento API key.",
)
parser.add_argument(
"-k",
"--key",
type=str,
dest="key",
help="key",
)
if not other_args:
console.print("For your API Key, https://databento.com")
return
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-k")
ns_parser = self.parse_simple_args(parser, other_args)
if ns_parser:
self.status_dict["databento"] = keys_model.set_databento_key(
key=ns_parser.key, persist=True, show_output=True
)
@log_start_end(log=logger)
def call_openbb(self, other_args: List[str]):
"""Process openbb command"""

View File

@@ -58,6 +58,7 @@ API_DICT: Dict = {
"quandl": "QUANDL",
"polygon": "POLYGON",
"intrinio": "INTRINIO",
"databento": "DATABENTO",
"fred": "FRED",
"news": "NEWSAPI",
"tradier": "TRADIER",
@@ -2592,7 +2593,7 @@ def set_intrinio_key(key: str, persist: bool = False, show_output: bool = False)
def check_intrinio_key(show_output: bool = False) -> str:
"""Check Polygon key
"""Check Intrinio key
Parameters
----------
@@ -2626,3 +2627,72 @@ def check_intrinio_key(show_output: bool = False) -> str:
console.print(status.colorize())
return str(status)
def set_databento_key(
key: str, persist: bool = False, show_output: bool = False
) -> str:
"""Set DataBento key
Parameters
----------
key: str
API key
persist: bool, optional
If False, api key change will be contained to where it was changed. For example, a Jupyter notebook session.
If True, api key change will be global, i.e. it will affect terminal environment variables.
By default, False.
show_output: bool, optional
Display status string or not. By default, False.
Returns
-------
str
Status of key set
Examples
--------
>>> from openbb_terminal.sdk import openbb
>>> openbb.keys.databento(key="example_key")
"""
set_key("OPENBB_API_DATABENTO_KEY", key, persist)
return check_databento_key(show_output)
def check_databento_key(show_output: bool = False) -> str:
"""Check DataBento key
Parameters
----------
show_output: bool
Display status string or not. By default, False.
Returns
-------
str
Status of key set
"""
if cfg.API_DATABENTO_KEY == "REPLACE_ME":
logger.info("DataBento key not defined")
status = KeyStatus.NOT_DEFINED
else:
r = request(
"https://hist.databento.com/v0/metadata.list_datasets",
auth=(f"{cfg.API_DATABENTO_KEY}", ""),
)
if r.status_code in [403, 401, 429]:
logger.warning("DataBento key defined, test failed")
status = KeyStatus.DEFINED_TEST_FAILED
elif r.status_code == 200:
logger.info("DataBento key defined, test passed")
status = KeyStatus.DEFINED_TEST_PASSED
else:
logger.warning("DataBento key defined, test inconclusive")
status = KeyStatus.DEFINED_TEST_INCONCLUSIVE
if show_output:
console.print(status.colorize())
return str(status)

View File

@@ -6,7 +6,7 @@
"candle": [],
"codes": ["Polygon"],
"news": ["Feedparser", "NewsApi"],
"load": ["YahooFinance", "AlphaVantage", "Polygon", "EODHD", "Intrinio"],
"load": ["YahooFinance", "AlphaVantage", "Polygon", "EODHD", "Intrinio", "DataBento"],
"th": {
"symbol": ["FinanceDatabase"],
"open": ["Bursa"],
@@ -489,7 +489,7 @@
},
"futures": {
"search": ["YahooFinance"],
"historical": ["YahooFinance"],
"historical": ["YahooFinance", "DataBento"],
"curve": ["YahooFinance"]
},
"portfolio": {

View File

@@ -297,7 +297,7 @@ class OpenBBSDK:
Attributes:
`curve`: Get curve futures [Source: Yahoo Finance]\n
`curve_chart`: Display curve futures [Source: Yahoo Finance]\n
`historical`: Get historical futures [Source: Yahoo Finance]\n
`historical`: Get historical futures data\n
`historical_chart`: Display historical futures [Source: Yahoo Finance]\n
`search`: Get search futures [Source: Yahoo Finance]\n
"""
@@ -316,6 +316,7 @@ class OpenBBSDK:
`coinbase`: Set Coinbase key\n
`coinglass`: Set Coinglass key.\n
`cpanic`: Set Cpanic key.\n
`databento`: Set DataBento key\n
`degiro`: Set Degiro key\n
`eodhd`: Set Eodhd key.\n
`ethplorer`: Set Ethplorer key.\n

View File

@@ -77,7 +77,6 @@ class ForecastRoot(Category):
if not lib.FORECASTING_TOOLKIT_ENABLED:
# pylint: disable=C0415
from openbb_terminal.rich_config import console
console.print(lib.FORECASTING_TOOLKIT_WARNING)

View File

@@ -10,7 +10,7 @@ class FuturesRoot(Category):
Attributes:
`curve`: Get curve futures [Source: Yahoo Finance]\n
`curve_chart`: Display curve futures [Source: Yahoo Finance]\n
`historical`: Get historical futures [Source: Yahoo Finance]\n
`historical`: Get historical futures data\n
`historical_chart`: Display historical futures [Source: Yahoo Finance]\n
`search`: Get search futures [Source: Yahoo Finance]\n
"""
@@ -21,6 +21,6 @@ class FuturesRoot(Category):
super().__init__()
self.curve = lib.futures_yfinance_model.get_curve_futures
self.curve_chart = lib.futures_yfinance_view.display_curve
self.historical = lib.futures_yfinance_model.get_historical_futures
self.historical = lib.futures_sdk_model.get_historical
self.historical_chart = lib.futures_yfinance_view.display_historical
self.search = lib.futures_yfinance_model.get_search_futures

View File

@@ -15,6 +15,7 @@ class KeysRoot(Category):
`coinbase`: Set Coinbase key\n
`coinglass`: Set Coinglass key.\n
`cpanic`: Set Cpanic key.\n
`databento`: Set DataBento key\n
`degiro`: Set Degiro key\n
`eodhd`: Set Eodhd key.\n
`ethplorer`: Set Ethplorer key.\n
@@ -55,6 +56,7 @@ class KeysRoot(Category):
self.coinbase = lib.keys_model.set_coinbase_key
self.coinglass = lib.keys_model.set_coinglass_key
self.cpanic = lib.keys_model.set_cpanic_key
self.databento = lib.keys_model.set_databento_key
self.degiro = lib.keys_model.set_degiro_key
self.eodhd = lib.keys_model.set_eodhd_key
self.ethplorer = lib.keys_model.set_ethplorer_key

View File

@@ -177,7 +177,6 @@ class PortfolioPortfolioOptimization(Category):
if not lib.OPTIMIZATION_TOOLKIT_ENABLED:
# pylint: disable=C0415
from openbb_terminal.rich_config import console
console.print(lib.OPTIMIZATION_TOOLKIT_WARNING)

View File

@@ -252,6 +252,7 @@ from openbb_terminal.forex import (
from openbb_terminal.futures import (
yfinance_model as futures_yfinance_model,
yfinance_view as futures_yfinance_view,
sdk_helper as futures_sdk_model,
)
# Stocks Helpers

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +1,39 @@
trail,model,view
forecast.anom,forecast_anom_model.get_anomaly_detection_data,forecast_anom_view.display_anomaly_detection
forecast.atr,forecast_model.add_atr,
forecast.autoarima,forecast_autoarima_model.get_autoarima_data,forecast_autoarima_view.display_autoarima_forecast
forecast.autoces,forecast_autoces_model.get_autoces_data,forecast_autoces_view.display_autoces_forecast
forecast.autoets,forecast_autoets_model.get_autoets_data,forecast_autoets_view.display_autoets_forecast
forecast.autoselect,forecast_autoselect_model.get_autoselect_data,forecast_autoselect_view.display_autoselect_forecast
forecast.brnn,forecast_brnn_model.get_brnn_data,forecast_brnn_view.display_brnn_forecast
forecast.clean,forecast_model.clean,
forecast.combine,forecast_model.combine_dfs,
forecast.corr,forecast_model.corr_df,forecast_view.display_corr
forecast.delete,forecast_model.delete_column,
forecast.delta,forecast_model.add_delta,
forecast.desc,forecast_model.describe_df,forecast_view.describe_df
forecast.ema,forecast_model.add_ema,
forecast.expo,forecast_expo_model.get_expo_data,forecast_expo_view.display_expo_forecast
forecast.export,forecast_view.export_df,
forecast.linregr,forecast_linregr_model.get_linear_regression_data,forecast_linregr_view.display_linear_regression
forecast.load,common_model.load,
forecast.mom,forecast_model.add_momentum,
forecast.mstl,forecast_mstl_model.get_mstl_data,forecast_mstl_view.display_mstl_forecast
forecast.nbeats,forecast_nbeats_model.get_NBEATS_data,forecast_nbeats_view.display_nbeats_forecast
forecast.nhits,forecast_nhits_model.get_nhits_data,forecast_nhits_view.display_nhits_forecast
forecast.plot,forecast_view.display_plot,forecast_view.display_plot
forecast.regr,forecast_regr_model.get_regression_data,forecast_regr_view.display_regression
forecast.rename,forecast_model.rename_column,
forecast.rnn,forecast_rnn_model.get_rnn_data,forecast_rnn_view.display_rnn_forecast
forecast.roc,forecast_model.add_roc,
forecast.rsi,forecast_model.add_rsi,
forecast.rwd,forecast_rwd_model.get_rwd_data,forecast_rwd_view.display_rwd_forecast
forecast.season,,forecast_view.display_seasonality
forecast.seasonalnaive,forecast_seasonalnaive_model.get_seasonalnaive_data,forecast_seasonalnaive_view.display_seasonalnaive_forecast
forecast.show,forecast_view.show_df,
forecast.signal,forecast_model.add_signal,
forecast.sto,forecast_model.add_sto,
forecast.tcn,forecast_tcn_model.get_tcn_data,forecast_tcn_view.display_tcn_forecast
forecast.tft,forecast_tft_model.get_tft_data,forecast_tft_view.display_tft_forecast
forecast.theta,forecast_theta_model.get_theta_data,forecast_theta_view.display_theta_forecast
forecast.trans,forecast_trans_model.get_trans_data,forecast_trans_view.display_trans_forecast
trail,model,view
forecast.anom,forecast_anom_model.get_anomaly_detection_data,forecast_anom_view.display_anomaly_detection
forecast.atr,forecast_model.add_atr,
forecast.autoarima,forecast_autoarima_model.get_autoarima_data,forecast_autoarima_view.display_autoarima_forecast
forecast.autoces,forecast_autoces_model.get_autoces_data,forecast_autoces_view.display_autoces_forecast
forecast.autoets,forecast_autoets_model.get_autoets_data,forecast_autoets_view.display_autoets_forecast
forecast.autoselect,forecast_autoselect_model.get_autoselect_data,forecast_autoselect_view.display_autoselect_forecast
forecast.brnn,forecast_brnn_model.get_brnn_data,forecast_brnn_view.display_brnn_forecast
forecast.clean,forecast_model.clean,
forecast.combine,forecast_model.combine_dfs,
forecast.corr,forecast_model.corr_df,forecast_view.display_corr
forecast.delete,forecast_model.delete_column,
forecast.delta,forecast_model.add_delta,
forecast.desc,forecast_model.describe_df,forecast_view.describe_df
forecast.ema,forecast_model.add_ema,
forecast.expo,forecast_expo_model.get_expo_data,forecast_expo_view.display_expo_forecast
forecast.export,forecast_view.export_df,
forecast.linregr,forecast_linregr_model.get_linear_regression_data,forecast_linregr_view.display_linear_regression
forecast.load,common_model.load,
forecast.mom,forecast_model.add_momentum,
forecast.mstl,forecast_mstl_model.get_mstl_data,forecast_mstl_view.display_mstl_forecast
forecast.nbeats,forecast_nbeats_model.get_NBEATS_data,forecast_nbeats_view.display_nbeats_forecast
forecast.nhits,forecast_nhits_model.get_nhits_data,forecast_nhits_view.display_nhits_forecast
forecast.plot,forecast_view.display_plot,forecast_view.display_plot
forecast.regr,forecast_regr_model.get_regression_data,forecast_regr_view.display_regression
forecast.rename,forecast_model.rename_column,
forecast.rnn,forecast_rnn_model.get_rnn_data,forecast_rnn_view.display_rnn_forecast
forecast.roc,forecast_model.add_roc,
forecast.rsi,forecast_model.add_rsi,
forecast.rwd,forecast_rwd_model.get_rwd_data,forecast_rwd_view.display_rwd_forecast
forecast.season,,forecast_view.display_seasonality
forecast.seasonalnaive,forecast_seasonalnaive_model.get_seasonalnaive_data,forecast_seasonalnaive_view.display_seasonalnaive_forecast
forecast.show,forecast_view.show_df,
forecast.signal,forecast_model.add_signal,
forecast.sto,forecast_model.add_sto,
forecast.tcn,forecast_tcn_model.get_tcn_data,forecast_tcn_view.display_tcn_forecast
forecast.tft,forecast_tft_model.get_tft_data,forecast_tft_view.display_tft_forecast
forecast.theta,forecast_theta_model.get_theta_data,forecast_theta_view.display_theta_forecast
forecast.trans,forecast_trans_model.get_trans_data,forecast_trans_view.display_trans_forecast
1 trail model view
2 forecast.anom forecast_anom_model.get_anomaly_detection_data forecast_anom_view.display_anomaly_detection
3 forecast.atr forecast_model.add_atr
4 forecast.autoarima forecast_autoarima_model.get_autoarima_data forecast_autoarima_view.display_autoarima_forecast
5 forecast.autoces forecast_autoces_model.get_autoces_data forecast_autoces_view.display_autoces_forecast
6 forecast.autoets forecast_autoets_model.get_autoets_data forecast_autoets_view.display_autoets_forecast
7 forecast.autoselect forecast_autoselect_model.get_autoselect_data forecast_autoselect_view.display_autoselect_forecast
8 forecast.brnn forecast_brnn_model.get_brnn_data forecast_brnn_view.display_brnn_forecast
9 forecast.clean forecast_model.clean
10 forecast.combine forecast_model.combine_dfs
11 forecast.corr forecast_model.corr_df forecast_view.display_corr
12 forecast.delete forecast_model.delete_column
13 forecast.delta forecast_model.add_delta
14 forecast.desc forecast_model.describe_df forecast_view.describe_df
15 forecast.ema forecast_model.add_ema
16 forecast.expo forecast_expo_model.get_expo_data forecast_expo_view.display_expo_forecast
17 forecast.export forecast_view.export_df
18 forecast.linregr forecast_linregr_model.get_linear_regression_data forecast_linregr_view.display_linear_regression
19 forecast.load common_model.load
20 forecast.mom forecast_model.add_momentum
21 forecast.mstl forecast_mstl_model.get_mstl_data forecast_mstl_view.display_mstl_forecast
22 forecast.nbeats forecast_nbeats_model.get_NBEATS_data forecast_nbeats_view.display_nbeats_forecast
23 forecast.nhits forecast_nhits_model.get_nhits_data forecast_nhits_view.display_nhits_forecast
24 forecast.plot forecast_view.display_plot forecast_view.display_plot
25 forecast.regr forecast_regr_model.get_regression_data forecast_regr_view.display_regression
26 forecast.rename forecast_model.rename_column
27 forecast.rnn forecast_rnn_model.get_rnn_data forecast_rnn_view.display_rnn_forecast
28 forecast.roc forecast_model.add_roc
29 forecast.rsi forecast_model.add_rsi
30 forecast.rwd forecast_rwd_model.get_rwd_data forecast_rwd_view.display_rwd_forecast
31 forecast.season forecast_view.display_seasonality
32 forecast.seasonalnaive forecast_seasonalnaive_model.get_seasonalnaive_data forecast_seasonalnaive_view.display_seasonalnaive_forecast
33 forecast.show forecast_view.show_df
34 forecast.signal forecast_model.add_signal
35 forecast.sto forecast_model.add_sto
36 forecast.tcn forecast_tcn_model.get_tcn_data forecast_tcn_view.display_tcn_forecast
37 forecast.tft forecast_tft_model.get_tft_data forecast_tft_view.display_tft_forecast
38 forecast.theta forecast_theta_model.get_theta_data forecast_theta_view.display_theta_forecast
39 forecast.trans forecast_trans_model.get_trans_data forecast_trans_view.display_trans_forecast

View File

@@ -1,19 +1,19 @@
trail,model,view
portfolio.po.blacklitterman,portfolio_optimization_po_model.get_blacklitterman,
portfolio.po.ef,portfolio_optimization_po_model.get_ef,portfolio_optimization_po_view.display_ef
portfolio.po.file,portfolio_optimization_po_model.load_parameters_file,
portfolio.po.herc,portfolio_optimization_po_model.get_herc,
portfolio.po.hrp,portfolio_optimization_po_model.get_hrp,
portfolio.po.load,portfolio_optimization_po_model.generate_portfolio,
portfolio.po.load_bl_views,portfolio_optimization_excel_model.load_bl_views,
portfolio.po.maxdecorr,portfolio_optimization_po_model.get_maxdecorr,
portfolio.po.maxdiv,portfolio_optimization_po_model.get_maxdiv,
portfolio.po.maxret,portfolio_optimization_po_model.get_maxret,
portfolio.po.maxsharpe,portfolio_optimization_po_model.get_maxsharpe,
portfolio.po.maxutil,portfolio_optimization_po_model.get_maxutil,
portfolio.po.minrisk,portfolio_optimization_po_model.get_minrisk,
portfolio.po.nco,portfolio_optimization_po_model.get_nco,
portfolio.po.plot,portfolio_optimization_po_view.display_plot,portfolio_optimization_po_view.display_plot
portfolio.po.relriskparity,portfolio_optimization_po_model.get_relriskparity,
portfolio.po.riskparity,portfolio_optimization_po_model.get_riskparity,
portfolio.po.show,portfolio_optimization_po_model.show,
trail,model,view
portfolio.po.blacklitterman,portfolio_optimization_po_model.get_blacklitterman,
portfolio.po.ef,portfolio_optimization_po_model.get_ef,portfolio_optimization_po_view.display_ef
portfolio.po.file,portfolio_optimization_po_model.load_parameters_file,
portfolio.po.herc,portfolio_optimization_po_model.get_herc,
portfolio.po.hrp,portfolio_optimization_po_model.get_hrp,
portfolio.po.load,portfolio_optimization_po_model.generate_portfolio,
portfolio.po.load_bl_views,portfolio_optimization_excel_model.load_bl_views,
portfolio.po.maxdecorr,portfolio_optimization_po_model.get_maxdecorr,
portfolio.po.maxdiv,portfolio_optimization_po_model.get_maxdiv,
portfolio.po.maxret,portfolio_optimization_po_model.get_maxret,
portfolio.po.maxsharpe,portfolio_optimization_po_model.get_maxsharpe,
portfolio.po.maxutil,portfolio_optimization_po_model.get_maxutil,
portfolio.po.minrisk,portfolio_optimization_po_model.get_minrisk,
portfolio.po.nco,portfolio_optimization_po_model.get_nco,
portfolio.po.plot,portfolio_optimization_po_view.display_plot,portfolio_optimization_po_view.display_plot
portfolio.po.relriskparity,portfolio_optimization_po_model.get_relriskparity,
portfolio.po.riskparity,portfolio_optimization_po_model.get_riskparity,
portfolio.po.show,portfolio_optimization_po_model.show,
1 trail model view
2 portfolio.po.blacklitterman portfolio_optimization_po_model.get_blacklitterman
3 portfolio.po.ef portfolio_optimization_po_model.get_ef portfolio_optimization_po_view.display_ef
4 portfolio.po.file portfolio_optimization_po_model.load_parameters_file
5 portfolio.po.herc portfolio_optimization_po_model.get_herc
6 portfolio.po.hrp portfolio_optimization_po_model.get_hrp
7 portfolio.po.load portfolio_optimization_po_model.generate_portfolio
8 portfolio.po.load_bl_views portfolio_optimization_excel_model.load_bl_views
9 portfolio.po.maxdecorr portfolio_optimization_po_model.get_maxdecorr
10 portfolio.po.maxdiv portfolio_optimization_po_model.get_maxdiv
11 portfolio.po.maxret portfolio_optimization_po_model.get_maxret
12 portfolio.po.maxsharpe portfolio_optimization_po_model.get_maxsharpe
13 portfolio.po.maxutil portfolio_optimization_po_model.get_maxutil
14 portfolio.po.minrisk portfolio_optimization_po_model.get_minrisk
15 portfolio.po.nco portfolio_optimization_po_model.get_nco
16 portfolio.po.plot portfolio_optimization_po_view.display_plot portfolio_optimization_po_view.display_plot
17 portfolio.po.relriskparity portfolio_optimization_po_model.get_relriskparity
18 portfolio.po.riskparity portfolio_optimization_po_model.get_riskparity
19 portfolio.po.show portfolio_optimization_po_model.show

View File

@@ -0,0 +1,154 @@
__docformat__ = "numpy"
import logging
from datetime import datetime, timedelta
from io import StringIO
import pandas as pd
import requests
from pydantic import BaseModel
from openbb_terminal import config_terminal as cfg
from openbb_terminal.decorators import check_api_key, log_start_end
from openbb_terminal.helper_funcs import request
from openbb_terminal.rich_config import console
logger = logging.getLogger(__name__)
# pylint:disable=too-few-public-methods
class DataBento(BaseModel):
symbol: str
exchange: str = "XNAS.ITCH"
stype: str = "native"
start: str = (datetime.now() - timedelta(days=365)).strftime("%Y-%m-%d")
end: str = datetime.now().strftime("%Y-%m-%d")
class Config:
arbitrary_types_allowed = True
def get_historical_stock(self):
"""Gets historical EOD stock data from DataBento. Currnetly, just NASDAQ is supported.
Note that only nonadjusted data is available."""
self.exchange = "XNAS.ITCH"
self.stype = "native"
if not self.validate_symbol():
return pd.DataFrame()
return self.get_historical()
def validate_symbol(self):
"""Validates the symbol is supported by DataBento. There is no API for this, so we will use their
Symbology endpoint to see if something exists. Doing a long time range can make this request on the order of
one minute, so try to keep smaller requests."""
base_url = "https://hist.databento.com/v0/symbology.resolve"
params = {
"dataset": self.exchange,
"symbols": self.symbol,
"start_date": self.start,
"end_date": self.end,
"stype_in": "smart",
"stype_out": "product_id",
}
auth = requests.auth.HTTPBasicAuth(cfg.API_DATABENTO_KEY, "")
# This seems to only work for futures? Assume the user is entering correct stock ticker
if self.exchange == "XNAS.ITCH":
return True
result = request(base_url, params=params, auth=auth, timeout=30)
if "message" not in result.json():
console.print(
"Issue validating symbol in the date range. Please check with DataBento for symbology."
)
return False
return result.json()["message"] != "Not found"
def get_historical_futures(self):
"""Gets historical EODfutures data from DataBento. Currently, just CME is supported.
Note this gets the highest volume contract each day"""
self.exchange = "GLBX.MDP3"
self.stype = "smart"
if not self.validate_symbol():
return pd.DataFrame()
return self.get_historical()
@log_start_end(log=logger)
@check_api_key(["API_DATABENTO_KEY"])
def get_historical(self) -> pd.DataFrame:
"""Prepares the request to be made. I am using their https interface instead of their python client.
Their next update will change symbol.V.0 to symbol.C.0"""
base_url = "https://hist.databento.com/v0/timeseries.stream"
symbol = self.symbol + ".V.0" if self.exchange == "GLBX.MDP3" else self.symbol
params = {
"dataset": self.exchange,
"symbols": symbol,
"schema": "ohlcv-1d",
"start": self.start,
"end": self.end,
"stype_in": self.stype,
"encoding": "csv",
}
auth = requests.auth.HTTPBasicAuth(cfg.API_DATABENTO_KEY, "")
data = self.process_request(base_url, params, auth)
if data.empty:
console.print(f"No data found for symbol `{self.symbol}`.")
return data
def process_request(self, base_url, params, auth) -> pd.DataFrame:
"""Takes the request and returns the adjusted dataframe"""
r = request(base_url, params=params, auth=auth)
if r.status_code != 200:
raise Exception(f"Error: Status Code {r.status_code}")
df = pd.read_csv(StringIO(r.text))
df["time"] = pd.to_datetime(df.ts_event, unit="ns")
df[["open", "high", "low", "close"]] /= 1_000_000_000
df = df.drop(columns=["ts_event", "publisher_id", "product_id"]).set_index(
"time"
)
df = df.rename(
columns={
"open": "Open",
"high": "High",
"low": "Low",
"close": "Close",
"volume": "Volume",
}
)
return df
@log_start_end(log=logger)
@check_api_key(["API_DATABENTO_KEY"])
def get_historical_stock(symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
"""Gets historical EOD data from DataBento. Currently, just NASDAQ is supported.
Parameters
----------
symbol : str
Symbol to get data for
start_date : str
Start date of data
end_date : str
End date to get data for
"""
db = DataBento(symbol=symbol, start=start_date, end=end_date)
return db.get_historical_stock()
@log_start_end(log=logger)
@check_api_key(["API_DATABENTO_KEY"])
def get_historical_futures(symbol: str, start_date: str, end_date: str) -> pd.DataFrame:
"""Gets historical EODfutures data from DataBento. Currently, just CME is supported.
Parameters
----------
symbol : str
Symbol to get data for
start_date : str
Start date of data
end_date : str
End date to get data for
"""
db = DataBento(symbol=symbol, start=start_date, end=end_date)
return db.get_historical_futures()

View File

@@ -56,6 +56,8 @@ from openbb_terminal.stocks.stocks_model import (
load_stock_yf,
)
from . import databento_model
logger = logging.getLogger(__name__)
@@ -335,6 +337,12 @@ def load(
elif source == "Intrinio":
df_stock_candidate = load_stock_intrinio(symbol, start_date, end_date)
elif source == "DataBento":
df_stock_candidate = databento_model.get_historical_stock(
symbol, start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d")
)
else:
console.print("[red]Invalid source for stock[/red]\n")
return

View File

@@ -1,5 +1,5 @@
search search for a future based on category or exchange [YahooFinance]
historical get historical timeseries [YahooFinance]
historical get historical timeseries [YahooFinance, DataBento]
curve get futures curves [YahooFinance]

View File

@@ -0,0 +1,118 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- MOCK_AUTHORIZATION
Connection:
- keep-alive
method: GET
uri: https://hist.databento.com/v0/timeseries.stream?dataset=XNAS.ITCH&symbols=AAPL&schema=ohlcv-1d&start=2022-08-01&end=2022-12-01&stype_in=native&encoding=csv
response:
body:
string: 'ts_event,publisher_id,product_id,open,high,low,close,volume
1659312000000000000,2,27,162200000000,163590000000,160830000000,161400000000,10045637
1659398400000000000,2,27,160730000000,162410000000,159550000000,160010000000,10065910
1659484800000000000,2,27,160060000000,166595000000,159850000000,165840000000,13326012
1659571200000000000,2,27,165830000000,167190000000,164430000000,165850000000,9578445
1659657600000000000,2,27,166000000000,166230000000,162790000000,164920000000,9683719
1659916800000000000,2,27,166080000000,167800000000,164200000000,165150000000,9135766
1660003200000000000,2,29,164990000000,165810000000,163460000000,164970000000,9230005
1660089600000000000,2,29,165010000000,169310000000,164560000000,169130000000,11638513
1660176000000000000,2,29,169240000000,170990000000,168190000000,168800000000,9732568
1660262400000000000,2,29,169180000000,172170000000,168650000000,171850000000,11916663
1660521600000000000,2,29,171140000000,173390000000,170740000000,173150000000,8485815
1660608000000000000,2,29,172830000000,174080000000,171670000000,173700000000,9979182
1660694400000000000,2,29,172670000000,176150000000,172140000000,173320000000,13581411
1660780800000000000,2,29,173200000000,174890000000,173130000000,174090000000,11175367
1660867200000000000,2,29,173600000000,173730000000,170700000000,170790000000,11296793
1661126400000000000,2,29,169400000000,169860000000,167135000000,167950000000,13070702
1661212800000000000,2,29,167610000000,168700000000,166650000000,167130000000,10629743
1661299200000000000,2,29,166930000000,168410000000,166245000000,167910000000,9482192
1661385600000000000,2,29,169270000000,170340000000,168230000000,170200000000,9874644
1661472000000000000,2,29,169900000000,171130000000,162300000000,162450000000,14062181
1661731200000000000,2,29,161790000000,162910000000,159830000000,161780000000,12363097
1661817600000000000,2,29,162600000000,163340000000,157730000000,158960000000,11853126
1661904000000000000,2,29,159650000000,160570000000,155770000000,156000000000,13343001
1661990400000000000,2,29,155890000000,158690000000,154675000000,158620000000,13016463
1662076800000000000,2,29,157710000000,160360000000,154965000000,155650000000,12975036
1662422400000000000,2,29,156790000000,157390000000,153730000000,154490000000,14840703
1662508800000000000,2,29,154800000000,156660000000,153610000000,155960000000,13205605
1662595200000000000,2,29,155950000000,156430000000,152680000000,154620000000,14072194
1662681600000000000,2,29,155260000000,157805000000,154760000000,157520000000,10213517
1662940800000000000,2,29,158000000000,164260000000,158000000000,164100000000,15959461
1663027200000000000,2,29,164150000000,164900000000,153385000000,154250000000,19181953
1663113600000000000,2,29,154470000000,157100000000,153250000000,156000000000,15250245
1663200000000000000,2,29,155960000000,156040000000,151100000000,151270000000,13929824
1663286400000000000,2,29,151350000000,151510000000,148360000000,151290000000,19608708
1663545600000000000,2,29,149820000000,155000000000,148700000000,155000000000,13024172
1663632000000000000,2,29,154270000000,158080000000,153090000000,156480000000,16126729
1663718400000000000,2,29,156580000000,158740000000,152240000000,152400000000,16938650
1663804800000000000,2,29,153530000000,154960000000,150920000000,153090000000,14902502
1663891200000000000,2,29,152250000000,152550000000,148560000000,150570000000,16074945
1664150400000000000,2,29,150420000000,153770000000,149140000000,151100000000,14918149
1664236800000000000,2,29,152840000000,154690000000,149950000000,151870000000,14873042
1664323200000000000,2,29,148500000000,150640000000,144840000000,149370000000,24532649
1664409600000000000,2,29,148000000000,148180000000,140680000000,142410000000,21075773
1664496000000000000,2,29,143160000000,143580000000,137220000000,137540000000,20801834
'
headers:
date:
- Tue, 21 Feb 2023 14:37:29 GMT
server:
- uvicorn
transfer-encoding:
- chunked
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,45 @@
time,Open,High,Low,Close,Volume
2022-08-01,162.2,163.59,160.83,161.4,10045637
2022-08-02,160.73,162.41,159.55,160.01,10065910
2022-08-03,160.06,166.595,159.85,165.84,13326012
2022-08-04,165.83,167.19,164.43,165.85,9578445
2022-08-05,166.0,166.23,162.79,164.92,9683719
2022-08-08,166.08,167.8,164.2,165.15,9135766
2022-08-09,164.99,165.81,163.46,164.97,9230005
2022-08-10,165.01,169.31,164.56,169.13,11638513
2022-08-11,169.24,170.99,168.19,168.8,9732568
2022-08-12,169.18,172.17,168.65,171.85,11916663
2022-08-15,171.14,173.39,170.74,173.15,8485815
2022-08-16,172.83,174.08,171.67,173.7,9979182
2022-08-17,172.67,176.15,172.14,173.32,13581411
2022-08-18,173.2,174.89,173.13,174.09,11175367
2022-08-19,173.6,173.73,170.7,170.79,11296793
2022-08-22,169.4,169.86,167.135,167.95,13070702
2022-08-23,167.61,168.7,166.65,167.13,10629743
2022-08-24,166.93,168.41,166.245,167.91,9482192
2022-08-25,169.27,170.34,168.23,170.2,9874644
2022-08-26,169.9,171.13,162.3,162.45,14062181
2022-08-29,161.79,162.91,159.83,161.78,12363097
2022-08-30,162.6,163.34,157.73,158.96,11853126
2022-08-31,159.65,160.57,155.77,156.0,13343001
2022-09-01,155.89,158.69,154.675,158.62,13016463
2022-09-02,157.71,160.36,154.965,155.65,12975036
2022-09-06,156.79,157.39,153.73,154.49,14840703
2022-09-07,154.8,156.66,153.61,155.96,13205605
2022-09-08,155.95,156.43,152.68,154.62,14072194
2022-09-09,155.26,157.805,154.76,157.52,10213517
2022-09-12,158.0,164.26,158.0,164.1,15959461
2022-09-13,164.15,164.9,153.385,154.25,19181953
2022-09-14,154.47,157.1,153.25,156.0,15250245
2022-09-15,155.96,156.04,151.1,151.27,13929824
2022-09-16,151.35,151.51,148.36,151.29,19608708
2022-09-19,149.82,155.0,148.7,155.0,13024172
2022-09-20,154.27,158.08,153.09,156.48,16126729
2022-09-21,156.58,158.74,152.24,152.4,16938650
2022-09-22,153.53,154.96,150.92,153.09,14902502
2022-09-23,152.25,152.55,148.56,150.57,16074945
2022-09-26,150.42,153.77,149.14,151.1,14918149
2022-09-27,152.84,154.69,149.95,151.87,14873042
2022-09-28,148.5,150.64,144.84,149.37,24532649
2022-09-29,148.0,148.18,140.68,142.41,21075773
2022-09-30,143.16,143.58,137.22,137.54,20801834
1 time Open High Low Close Volume
2 2022-08-01 162.2 163.59 160.83 161.4 10045637
3 2022-08-02 160.73 162.41 159.55 160.01 10065910
4 2022-08-03 160.06 166.595 159.85 165.84 13326012
5 2022-08-04 165.83 167.19 164.43 165.85 9578445
6 2022-08-05 166.0 166.23 162.79 164.92 9683719
7 2022-08-08 166.08 167.8 164.2 165.15 9135766
8 2022-08-09 164.99 165.81 163.46 164.97 9230005
9 2022-08-10 165.01 169.31 164.56 169.13 11638513
10 2022-08-11 169.24 170.99 168.19 168.8 9732568
11 2022-08-12 169.18 172.17 168.65 171.85 11916663
12 2022-08-15 171.14 173.39 170.74 173.15 8485815
13 2022-08-16 172.83 174.08 171.67 173.7 9979182
14 2022-08-17 172.67 176.15 172.14 173.32 13581411
15 2022-08-18 173.2 174.89 173.13 174.09 11175367
16 2022-08-19 173.6 173.73 170.7 170.79 11296793
17 2022-08-22 169.4 169.86 167.135 167.95 13070702
18 2022-08-23 167.61 168.7 166.65 167.13 10629743
19 2022-08-24 166.93 168.41 166.245 167.91 9482192
20 2022-08-25 169.27 170.34 168.23 170.2 9874644
21 2022-08-26 169.9 171.13 162.3 162.45 14062181
22 2022-08-29 161.79 162.91 159.83 161.78 12363097
23 2022-08-30 162.6 163.34 157.73 158.96 11853126
24 2022-08-31 159.65 160.57 155.77 156.0 13343001
25 2022-09-01 155.89 158.69 154.675 158.62 13016463
26 2022-09-02 157.71 160.36 154.965 155.65 12975036
27 2022-09-06 156.79 157.39 153.73 154.49 14840703
28 2022-09-07 154.8 156.66 153.61 155.96 13205605
29 2022-09-08 155.95 156.43 152.68 154.62 14072194
30 2022-09-09 155.26 157.805 154.76 157.52 10213517
31 2022-09-12 158.0 164.26 158.0 164.1 15959461
32 2022-09-13 164.15 164.9 153.385 154.25 19181953
33 2022-09-14 154.47 157.1 153.25 156.0 15250245
34 2022-09-15 155.96 156.04 151.1 151.27 13929824
35 2022-09-16 151.35 151.51 148.36 151.29 19608708
36 2022-09-19 149.82 155.0 148.7 155.0 13024172
37 2022-09-20 154.27 158.08 153.09 156.48 16126729
38 2022-09-21 156.58 158.74 152.24 152.4 16938650
39 2022-09-22 153.53 154.96 150.92 153.09 14902502
40 2022-09-23 152.25 152.55 148.56 150.57 16074945
41 2022-09-26 150.42 153.77 149.14 151.1 14918149
42 2022-09-27 152.84 154.69 149.95 151.87 14873042
43 2022-09-28 148.5 150.64 144.84 149.37 24532649
44 2022-09-29 148.0 148.18 140.68 142.41 21075773
45 2022-09-30 143.16 143.58 137.22 137.54 20801834

View File

@@ -0,0 +1,35 @@
import pytest
from openbb_terminal.stocks import databento_model
@pytest.fixture(scope="module")
def vcr_config():
return {
"filter_headers": [
("User-Agent", None),
("Authorization", "MOCK_AUTHORIZATION"),
],
}
def test_databento_model():
"""Tests the DataBento model."""
model = databento_model.DataBento(
symbol="AAPL", start="2021-08-10", end="2021-08-11"
)
assert model.symbol == "AAPL"
assert model.exchange == "XNAS.ITCH"
assert model.stype == "native"
assert model.start == "2021-08-10"
assert model.end == "2021-08-11"
@pytest.mark.vcr
def test_stock_load(recorder):
"""Tests the stock load function."""
result = databento_model.get_historical_stock(
symbol="AAPL", start_date="2022-08-01", end_date="2022-12-01"
)
assert result.empty is False
recorder.capture(result)

View File

@@ -1,5 +1,5 @@
search search a specific stock ticker for analysis [FinanceDatabase]
load load a specific stock ticker and additional info for analysis [YahooFinance, AlphaVantage, Polygon, EODHD, Intrinio]
load load a specific stock ticker and additional info for analysis [YahooFinance, AlphaVantage, Polygon, EODHD, Intrinio, DataBento]
Stock: