mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
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:
@@ -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"
|
||||
|
||||
118
openbb_terminal/futures/databento_view.py
Normal file
118
openbb_terminal/futures/databento_view.py
Normal 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,
|
||||
)
|
||||
@@ -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]):
|
||||
|
||||
31
openbb_terminal/futures/sdk_helper.py
Normal file
31
openbb_terminal/futures/sdk_helper.py
Normal 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()
|
||||
@@ -99,7 +99,7 @@ def get_historical_futures(
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dictionary with sector weightings allocation
|
||||
Historical futures data
|
||||
"""
|
||||
|
||||
if start_date is None:
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
1099
openbb_terminal/sdk_core/trail_map.csv
vendored
1099
openbb_terminal/sdk_core/trail_map.csv
vendored
File diff suppressed because it is too large
Load Diff
@@ -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,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,
|
||||
|
||||
|
154
openbb_terminal/stocks/databento_model.py
Normal file
154
openbb_terminal/stocks/databento_model.py
Normal 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()
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
118
tests/openbb_terminal/stocks/cassettes/test_databento_model/test_stock_load.yaml
vendored
Normal file
118
tests/openbb_terminal/stocks/cassettes/test_databento_model/test_stock_load.yaml
vendored
Normal 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
|
||||
45
tests/openbb_terminal/stocks/csv/test_databento_model/test_stock_load.csv
vendored
Normal file
45
tests/openbb_terminal/stocks/csv/test_databento_model/test_stock_load.csv
vendored
Normal 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
|
||||
|
35
tests/openbb_terminal/stocks/test_databento_model.py
Normal file
35
tests/openbb_terminal/stocks/test_databento_model.py
Normal 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)
|
||||
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user