mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Add tiingo provider (#5740)
* first commit * things * Add news endpoints * CryptoHistorical * Add currency and trailing dividend yield * things working * deps * fix pre commit things * tests? * black on the tests * pratty told me to add it * integration tests * added helpers * crypto revamped * currency revamped * trailing dividend yield revamped * equity historical revamped * company news overhauled * global news overhauled * remove `tags` param from news models * crypto correct `exchanges` description * james smh * re-recorded fetcher tests * fixed integration tests * econometrics smh * james smh again --------- Co-authored-by: Pratyush Shukla <ps4534@nyu.edu>
This commit is contained in:
@@ -25,6 +25,7 @@ openbb-intrinio = { path = "./providers/intrinio", develop = true }
|
||||
openbb-oecd = { path = "./providers/oecd", develop = true }
|
||||
openbb-polygon = { path = "./providers/polygon", develop = true }
|
||||
openbb-sec = { path = "./providers/sec", develop = true }
|
||||
openbb-tiingo = { path = "./providers/tiingo", develop = true }
|
||||
openbb-tradingeconomics = { path = "./providers/tradingeconomics", develop = true }
|
||||
|
||||
openbb-crypto = { path = "./extensions/crypto", develop = true }
|
||||
|
||||
@@ -113,6 +113,26 @@ def test_crypto_search(params, headers):
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"interval": "1day",
|
||||
"exchanges": ["POLONIEX", "GDAX"],
|
||||
"symbol": "BTCUSD",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"interval": "1hour",
|
||||
"exchanges": ["POLONIEX", "GDAX"],
|
||||
"symbol": "BTCUSD",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -98,6 +98,26 @@ def test_crypto_search(params, obb):
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"interval": "1day",
|
||||
"exchanges": ["POLONIEX", "GDAX"],
|
||||
"symbol": "BTCUSD",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"interval": "1hour",
|
||||
"exchanges": ["POLONIEX", "GDAX"],
|
||||
"symbol": "BTCUSD",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -123,6 +123,24 @@ def test_currency_search(params, headers):
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"interval": "1hour",
|
||||
"provider": "tiingo",
|
||||
"symbol": "EURUSD",
|
||||
"start_date": "2023-05-21",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"interval": "1day",
|
||||
"provider": "tiingo",
|
||||
"symbol": "EURUSD",
|
||||
"start_date": "2023-05-21",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -119,6 +119,24 @@ def test_currency_search(params, obb):
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"interval": "1hour",
|
||||
"provider": "tiingo",
|
||||
"symbol": "EURUSD",
|
||||
"start_date": "2023-05-21",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"interval": "1day",
|
||||
"provider": "tiingo",
|
||||
"symbol": "EURUSD",
|
||||
"start_date": "2023-05-21",
|
||||
"end_date": "2023-06-06",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -872,6 +872,24 @@ def test_equity_options_unusual(params, headers):
|
||||
"interval": "1d",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbol": "AAPL",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
"interval": "1d",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbol": "AAPL",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
"interval": "1M",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
@@ -1334,3 +1352,18 @@ def test_equity_market_snapshots(params, headers):
|
||||
result = requests.get(url, headers=headers, timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[({"provider": "tiingo", "symbol": "AAPL"})],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_equity_fundamental_trailing_dividend_yield(params, headers):
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
query_str = get_querystring(params, [])
|
||||
url = f"http://0.0.0.0:8000/api/v1/equity/fundamental/trailing_dividend_yield?{query_str}"
|
||||
result = requests.get(url, headers=headers, timeout=10)
|
||||
assert isinstance(result, requests.Response)
|
||||
assert result.status_code == 200
|
||||
|
||||
@@ -807,6 +807,24 @@ def test_equity_options_unusual(params, obb):
|
||||
"interval": "1d",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbol": "AAPL",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
"interval": "1d",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbol": "AAPL",
|
||||
"start_date": "2023-01-01",
|
||||
"end_date": "2023-06-06",
|
||||
"interval": "1M",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
@@ -1228,3 +1246,17 @@ def test_equity_market_snapshots(params, obb):
|
||||
assert result
|
||||
assert isinstance(result, OBBject)
|
||||
assert len(result.results) > 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[({"provider": "tiingo", "symbol": "AAPL"})],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
def test_equity_fundamental_trailing_dividend_yield(params, obb):
|
||||
params = {p: v for p, v in params.items() if v}
|
||||
|
||||
result = obb.equity.fundamental.trailing_dividend_yield(**params)
|
||||
assert result
|
||||
assert isinstance(result, OBBject)
|
||||
assert len(result.results) > 0
|
||||
|
||||
@@ -255,3 +255,14 @@ def transcript(
|
||||
) -> OBBject[BaseModel]:
|
||||
"""Earnings Call Transcript. Earnings call transcript for a given company."""
|
||||
return OBBject(results=Query(**locals()).execute())
|
||||
|
||||
|
||||
@router.command(model="TrailingDividendYield")
|
||||
def trailing_dividend_yield(
|
||||
cc: CommandContext,
|
||||
provider_choices: ProviderChoices,
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> OBBject[BaseModel]:
|
||||
"""Trailing 1yr dividend yield."""
|
||||
return OBBject(results=Query(**locals()).execute())
|
||||
|
||||
@@ -56,6 +56,13 @@ def headers():
|
||||
"term": "MSFT",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"limit": 30,
|
||||
"source": "bloomberg.com",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
@@ -131,6 +138,14 @@ def test_news_world(params, headers):
|
||||
"symbols": "AAPL,MSFT",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbols": "AAPL,MSFT",
|
||||
"limit": 20,
|
||||
"source": "bloomberg.com",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -62,6 +62,13 @@ def obb(pytestconfig): # pylint: disable=inconsistent-return-statements
|
||||
"term": "MSFT",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"limit": 30,
|
||||
"source": "bloomberg.com",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
@@ -133,6 +140,14 @@ def test_news_world(params, obb):
|
||||
"symbols": "AAPL,MSFT",
|
||||
}
|
||||
),
|
||||
(
|
||||
{
|
||||
"provider": "tiingo",
|
||||
"symbols": "AAPL,MSFT",
|
||||
"limit": 20,
|
||||
"source": "bloomberg.com",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -49,7 +49,9 @@ class CurrencyHistoricalData(Data):
|
||||
high: PositiveFloat = Field(description=DATA_DESCRIPTIONS.get("high", ""))
|
||||
low: PositiveFloat = Field(description=DATA_DESCRIPTIONS.get("low", ""))
|
||||
close: PositiveFloat = Field(description=DATA_DESCRIPTIONS.get("close", ""))
|
||||
volume: float = Field(description=DATA_DESCRIPTIONS.get("volume", ""))
|
||||
volume: Optional[float] = Field(
|
||||
description=DATA_DESCRIPTIONS.get("volume", ""), default=None
|
||||
)
|
||||
vwap: Optional[PositiveFloat] = Field(
|
||||
description=DATA_DESCRIPTIONS.get("vwap", ""), default=None
|
||||
)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Trailing Dividend Yield Data Model."""
|
||||
|
||||
|
||||
from datetime import date as dateType
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from openbb_provider.abstract.data import Data
|
||||
from openbb_provider.abstract.query_params import QueryParams
|
||||
from openbb_provider.utils.descriptions import DATA_DESCRIPTIONS, QUERY_DESCRIPTIONS
|
||||
|
||||
|
||||
class TrailingDivYieldQueryParams(QueryParams):
|
||||
"""Trailing Dividend Yield Query."""
|
||||
|
||||
symbol: str = Field(default=None, description=QUERY_DESCRIPTIONS.get("symbol", ""))
|
||||
|
||||
|
||||
class TrailingDivYieldData(Data):
|
||||
"""Return Trailing Dividend Yield Data."""
|
||||
|
||||
date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", ""))
|
||||
trailing_dividend_yield: float = Field(description="Trailing dividend yield.")
|
||||
@@ -10,4 +10,5 @@ test_credentials: Dict[str, Tuple[str, str]] = {
|
||||
"nasdaq": ("x-api-token", "MOCK_API_KEY"),
|
||||
"fred": ("api_key", "MOCK_API_KEY"),
|
||||
"intrinio": ("api_key", "MOCK_API_KEY"),
|
||||
"tiingo": ("token", "MOCK_TOKEN"),
|
||||
}
|
||||
|
||||
15
openbb_platform/providers/tiingo/README.md
vendored
Normal file
15
openbb_platform/providers/tiingo/README.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# OpenBB Tiingo Provider
|
||||
|
||||
This extension integrates the [Tiingo](https://www.tiingo.com/) data provider into the OpenBB Platform.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the extension:
|
||||
|
||||
```bash
|
||||
pip install openbb-tiingo
|
||||
```
|
||||
|
||||
For development please check [Contribution Guidelines](https://github.com/OpenBB-finance/OpenBBTerminal/blob/feature/openbb-sdk-v4/openbb_platform/CONTRIBUTING.md).
|
||||
|
||||
Documentation available [here](https://docs.openbb.co/sdk).
|
||||
0
openbb_platform/providers/tiingo/__init__.py
Normal file
0
openbb_platform/providers/tiingo/__init__.py
Normal file
26
openbb_platform/providers/tiingo/openbb_tiingo/__init__.py
Normal file
26
openbb_platform/providers/tiingo/openbb_tiingo/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Tiingo provider module."""
|
||||
|
||||
from openbb_provider.abstract.provider import Provider
|
||||
from openbb_tiingo.models.company_news import TiingoCompanyNewsFetcher
|
||||
from openbb_tiingo.models.crypto_historical import TiingoCryptoHistoricalFetcher
|
||||
from openbb_tiingo.models.currency_historical import TiingoCurrencyHistoricalFetcher
|
||||
from openbb_tiingo.models.equity_historical import TiingoEquityHistoricalFetcher
|
||||
from openbb_tiingo.models.global_news import TiingoGlobalNewsFetcher
|
||||
from openbb_tiingo.models.trailing_dividend_yield import (
|
||||
TiingoTrailingDivYieldFetcher,
|
||||
)
|
||||
|
||||
tiingo_provider = Provider(
|
||||
name="tiingo",
|
||||
website="https://tiingo.com/",
|
||||
description="""""",
|
||||
required_credentials=["token"],
|
||||
fetcher_dict={
|
||||
"EquityHistorical": TiingoEquityHistoricalFetcher,
|
||||
"CompanyNews": TiingoCompanyNewsFetcher,
|
||||
"GlobalNews": TiingoGlobalNewsFetcher,
|
||||
"CryptoHistorical": TiingoCryptoHistoricalFetcher,
|
||||
"CurrencyHistorical": TiingoCurrencyHistoricalFetcher,
|
||||
"TrailingDividendYield": TiingoTrailingDivYieldFetcher,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,98 @@
|
||||
"""Tiingo Company News."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from dateutil import parser
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.company_news import (
|
||||
CompanyNewsData,
|
||||
CompanyNewsQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from openbb_tiingo.utils.helpers import get_data_many
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
|
||||
class TiingoCompanyNewsQueryParams(CompanyNewsQueryParams):
|
||||
"""tiingo Company News query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/news
|
||||
"""
|
||||
|
||||
__alias_dict__ = {"symbols": "tickers"}
|
||||
|
||||
source: Optional[str] = Field(
|
||||
default=None, description="A comma-separated list of the domains requested."
|
||||
)
|
||||
|
||||
|
||||
class TiingoCompanyNewsData(CompanyNewsData):
|
||||
"""Tiingo Company News data."""
|
||||
|
||||
__alias_dict__ = {
|
||||
"date": "publishedDate",
|
||||
"text": "description",
|
||||
}
|
||||
|
||||
symbols: str = Field(
|
||||
description="Ticker tagged in the fetched news.", alias="tickers"
|
||||
)
|
||||
article_id: int = Field(description="Unique ID of the news article.", alias="id")
|
||||
site: str = Field(description="Name of the news source.", alias="source")
|
||||
tags: str = Field(description="Tags associated with the news article.")
|
||||
crawl_date: datetime = Field(description="Date the news article was crawled.")
|
||||
|
||||
@field_validator("tags", "symbols", mode="before")
|
||||
@classmethod
|
||||
def list_to_string(cls, v):
|
||||
"""Convert list to string."""
|
||||
return ",".join(v)
|
||||
|
||||
@field_validator("crawl_date", mode="before")
|
||||
@classmethod
|
||||
def validate_date(cls, v):
|
||||
"""Validate the date."""
|
||||
return parser.parse(v)
|
||||
|
||||
@field_validator("symbols", mode="after")
|
||||
@classmethod
|
||||
def symbols_validate(cls, v: str):
|
||||
"""Convert symbols to upper case."""
|
||||
return v.upper()
|
||||
|
||||
|
||||
class TiingoCompanyNewsFetcher(
|
||||
Fetcher[
|
||||
TiingoCompanyNewsQueryParams,
|
||||
List[TiingoCompanyNewsData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoCompanyNewsQueryParams:
|
||||
"""Transform the query params."""
|
||||
return TiingoCompanyNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoCompanyNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
|
||||
base_url = "https://api.tiingo.com/tiingo/news"
|
||||
query_str = get_querystring(query.model_dump(by_alias=True), [])
|
||||
url = f"{base_url}?{query_str}&token={api_key}"
|
||||
|
||||
return get_data_many(url)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoCompanyNewsQueryParams, data: List[Dict], **kwargs: Any
|
||||
) -> List[TiingoCompanyNewsData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoCompanyNewsData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1,107 @@
|
||||
"""Tiingo Crypto end of day fetcher."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.crypto_historical import (
|
||||
CryptoHistoricalData,
|
||||
CryptoHistoricalQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from openbb_tiingo.utils.helpers import get_data_one
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class TiingoCryptoHistoricalQueryParams(CryptoHistoricalQueryParams):
|
||||
"""Tiingo Crypto end of day Query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/end-of-day
|
||||
"""
|
||||
|
||||
__alias_dict__ = {
|
||||
"symbol": "tickers",
|
||||
"start_date": "startDate",
|
||||
"end_date": "endDate",
|
||||
}
|
||||
|
||||
interval: Literal[
|
||||
"1min", "5min", "15min", "30min", "1hour", "4hour", "1day"
|
||||
] = Field(default="1day", description="Data granularity.", alias="resampleFreq")
|
||||
|
||||
exchanges: Optional[List[str]] = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"To limit the query to a subset of exchanges e.g. ['POLONIEX', 'GDAX']"
|
||||
),
|
||||
)
|
||||
# pylint: disable=protected-access
|
||||
|
||||
|
||||
class TiingoCryptoHistoricalData(CryptoHistoricalData):
|
||||
"""Tiingo Crypto end of day Data."""
|
||||
|
||||
transactions: Optional[int] = Field(
|
||||
default=None, description="Number of trades.", alias="tradesDone"
|
||||
)
|
||||
|
||||
volume_notional: Optional[float] = Field(
|
||||
default=None,
|
||||
description=(
|
||||
"The last size done for the asset on the specific date in the "
|
||||
"quote currency. The volume of the asset on the specific date in "
|
||||
"the quote currency."
|
||||
),
|
||||
alias="volumeNotional",
|
||||
)
|
||||
|
||||
|
||||
class TiingoCryptoHistoricalFetcher(
|
||||
Fetcher[
|
||||
TiingoCryptoHistoricalQueryParams,
|
||||
List[TiingoCryptoHistoricalData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the Tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoCryptoHistoricalQueryParams:
|
||||
"""Transform the query params."""
|
||||
transformed_params = params
|
||||
|
||||
now = datetime.now().date()
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - relativedelta(years=1)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
|
||||
return TiingoCryptoHistoricalQueryParams(**transformed_params)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoCryptoHistoricalQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Optional[Any],
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the Tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
|
||||
base_url = "https://api.tiingo.com/tiingo/crypto/prices"
|
||||
query_str = get_querystring(query.model_dump(by_alias=True), [])
|
||||
url = f"{base_url}?{query_str}&token={api_key}"
|
||||
data = get_data_one(url).get("priceData", [])
|
||||
|
||||
return data
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoCryptoHistoricalQueryParams,
|
||||
data: List[Dict],
|
||||
**kwargs: Any,
|
||||
) -> List[TiingoCryptoHistoricalData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoCryptoHistoricalData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1,85 @@
|
||||
"""Tiingo Currency end of day fetcher."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.currency_historical import (
|
||||
CurrencyHistoricalData,
|
||||
CurrencyHistoricalQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from openbb_tiingo.utils.helpers import get_data_many
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class TiingoCurrencyHistoricalQueryParams(CurrencyHistoricalQueryParams):
|
||||
"""Tiingo Currency end of day Query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/end-of-day
|
||||
"""
|
||||
|
||||
__alias_dict__ = {
|
||||
"symbol": "tickers",
|
||||
"start_date": "startDate",
|
||||
"end_date": "endDate",
|
||||
}
|
||||
|
||||
interval: Literal[
|
||||
"1min", "5min", "15min", "30min", "1hour", "4hour", "1day"
|
||||
] = Field(default="1day", description="Data granularity.", alias="resampleFreq")
|
||||
|
||||
|
||||
class TiingoCurrencyHistoricalData(CurrencyHistoricalData):
|
||||
"""Tiingo Currency end of day Data."""
|
||||
|
||||
|
||||
class TiingoCurrencyHistoricalFetcher(
|
||||
Fetcher[
|
||||
TiingoCurrencyHistoricalQueryParams,
|
||||
List[TiingoCurrencyHistoricalData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the Tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoCurrencyHistoricalQueryParams:
|
||||
"""Transform the query params."""
|
||||
transformed_params = params
|
||||
|
||||
now = datetime.now().date()
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - relativedelta(years=1)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
|
||||
return TiingoCurrencyHistoricalQueryParams(**transformed_params)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoCurrencyHistoricalQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the Tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
|
||||
base_url = "https://api.tiingo.com/tiingo/fx/prices"
|
||||
query_str = get_querystring(query.model_dump(by_alias=True), [])
|
||||
url = f"{base_url}?{query_str}&token={api_key}"
|
||||
data = get_data_many(url)
|
||||
|
||||
return data
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoCurrencyHistoricalQueryParams,
|
||||
data: List[Dict],
|
||||
**kwargs: Any,
|
||||
) -> List[TiingoCurrencyHistoricalData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoCurrencyHistoricalData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1,142 @@
|
||||
"""Tiingo Equity end of day fetcher."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.equity_historical import (
|
||||
EquityHistoricalData,
|
||||
EquityHistoricalQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from openbb_tiingo.utils.helpers import get_data_many
|
||||
from pydantic import Field, PrivateAttr, model_validator
|
||||
|
||||
|
||||
class TiingoEquityHistoricalQueryParams(EquityHistoricalQueryParams):
|
||||
"""Tiingo Equity end of day Query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/end-of-day
|
||||
"""
|
||||
|
||||
__alias_dict__ = {
|
||||
"start_date": "startDate",
|
||||
"end_date": "endDate",
|
||||
}
|
||||
|
||||
interval: Literal["1d", "1W", "1M", "1Y"] = Field(
|
||||
default="1d", description=QUERY_DESCRIPTIONS.get("interval", "")
|
||||
)
|
||||
_frequency: Literal[
|
||||
"daily", "weekly", "monthly", "quarterly", "yearly"
|
||||
] = PrivateAttr(default=None)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@model_validator(mode="after") # type: ignore[arg-type]
|
||||
@classmethod
|
||||
def set_time_params(cls, values: "TiingoEquityHistoricalQueryParams"):
|
||||
"""Set the default start & end date and time params for Tiingo API."""
|
||||
frequency_dict = {
|
||||
"1d": "daily",
|
||||
"1W": "weekly",
|
||||
"1M": "monthly",
|
||||
"1Q": "quarterly",
|
||||
"1Y": "yearly",
|
||||
}
|
||||
|
||||
values._frequency = frequency_dict[values.interval] # type: ignore[assignment]
|
||||
|
||||
return values
|
||||
|
||||
|
||||
class TiingoEquityHistoricalData(EquityHistoricalData):
|
||||
"""Tiingo Equity end of day Data."""
|
||||
|
||||
adj_open: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Adjusted open price during the period.",
|
||||
alias="adjOpen",
|
||||
)
|
||||
adj_high: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Adjusted high price during the period.",
|
||||
alias="adjHigh",
|
||||
)
|
||||
adj_low: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Adjusted low price during the period.",
|
||||
alias="adjLow",
|
||||
)
|
||||
adj_close: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Adjusted closing price during the period.",
|
||||
alias="adjClose",
|
||||
)
|
||||
adj_volume: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Adjusted volume during the period.",
|
||||
alias="adjVolume",
|
||||
)
|
||||
split_ratio: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Ratio of the equity split, if a equity split occurred.",
|
||||
alias="splitFactor",
|
||||
)
|
||||
dividend: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Dividend amount, if a dividend was paid.",
|
||||
alias="divCash",
|
||||
)
|
||||
|
||||
|
||||
class TiingoEquityHistoricalFetcher(
|
||||
Fetcher[
|
||||
TiingoEquityHistoricalQueryParams,
|
||||
List[TiingoEquityHistoricalData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the Tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoEquityHistoricalQueryParams:
|
||||
"""Transform the query params."""
|
||||
transformed_params = params
|
||||
|
||||
now = datetime.now().date()
|
||||
if params.get("start_date") is None:
|
||||
transformed_params["start_date"] = now - relativedelta(years=1)
|
||||
|
||||
if params.get("end_date") is None:
|
||||
transformed_params["end_date"] = now
|
||||
|
||||
return TiingoEquityHistoricalQueryParams(**transformed_params)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoEquityHistoricalQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the Tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
|
||||
base_url = "https://api.tiingo.com/tiingo/daily"
|
||||
query_str = get_querystring(
|
||||
query.model_dump(by_alias=True), ["symbol", "interval"]
|
||||
)
|
||||
url = f"{base_url}/{query.symbol}/prices?{query_str}&resampleFreq={query._frequency}&token={api_key}"
|
||||
|
||||
return get_data_many(url)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoEquityHistoricalQueryParams,
|
||||
data: List[Dict],
|
||||
**kwargs: Any,
|
||||
) -> List[TiingoEquityHistoricalData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoEquityHistoricalData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1,96 @@
|
||||
"""Tiingo Global News."""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from dateutil import parser
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.global_news import (
|
||||
GlobalNewsData,
|
||||
GlobalNewsQueryParams,
|
||||
)
|
||||
from openbb_provider.utils.helpers import get_querystring
|
||||
from openbb_tiingo.utils.helpers import get_data_many
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
|
||||
class TiingoGlobalNewsQueryParams(GlobalNewsQueryParams):
|
||||
"""Tiingo Global News query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/news
|
||||
"""
|
||||
|
||||
source: Optional[str] = Field(
|
||||
default=None, description="A comma-separated list of the domains requested."
|
||||
)
|
||||
|
||||
|
||||
class TiingoGlobalNewsData(GlobalNewsData):
|
||||
"""Tiingo Global News data."""
|
||||
|
||||
__alias_dict__ = {
|
||||
"date": "publishedDate",
|
||||
"text": "description",
|
||||
}
|
||||
|
||||
symbols: str = Field(
|
||||
description="Ticker tagged in the fetched news.", alias="tickers"
|
||||
)
|
||||
article_id: int = Field(description="Unique ID of the news article.", alias="id")
|
||||
site: str = Field(description="Name of the news source.", alias="source")
|
||||
tags: str = Field(description="Tags associated with the news article.")
|
||||
crawl_date: datetime = Field(description="Date the news article was crawled.")
|
||||
|
||||
@field_validator("tags", "symbols", mode="before")
|
||||
@classmethod
|
||||
def list_to_string(cls, v):
|
||||
"""Convert list to string."""
|
||||
return ",".join(v)
|
||||
|
||||
@field_validator("crawl_date", mode="before")
|
||||
@classmethod
|
||||
def validate_date(cls, v):
|
||||
"""Validate the date."""
|
||||
return parser.parse(v)
|
||||
|
||||
@field_validator("symbols", mode="after")
|
||||
@classmethod
|
||||
def symbols_validate(cls, v: str):
|
||||
"""Convert symbols to upper case."""
|
||||
return v.upper()
|
||||
|
||||
|
||||
class TiingoGlobalNewsFetcher(
|
||||
Fetcher[
|
||||
TiingoGlobalNewsQueryParams,
|
||||
List[TiingoGlobalNewsData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoGlobalNewsQueryParams:
|
||||
"""Transform the query params."""
|
||||
return TiingoGlobalNewsQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoGlobalNewsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
|
||||
base_url = "https://api.tiingo.com/tiingo/news"
|
||||
query_str = get_querystring(query.model_dump(by_alias=True), [])
|
||||
url = f"{base_url}?{query_str}&token={api_key}"
|
||||
|
||||
return get_data_many(url)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoGlobalNewsQueryParams, data: List[Dict], **kwargs: Any
|
||||
) -> List[TiingoGlobalNewsData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoGlobalNewsData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1,63 @@
|
||||
"""Tiingo Trailing Dividend Yield fetcher."""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from openbb_provider.abstract.fetcher import Fetcher
|
||||
from openbb_provider.standard_models.trailing_dividend_yield import (
|
||||
TrailingDivYieldData,
|
||||
TrailingDivYieldQueryParams,
|
||||
)
|
||||
from openbb_tiingo.utils.helpers import get_data_many
|
||||
|
||||
|
||||
class TiingoTrailingDivYieldQueryParams(TrailingDivYieldQueryParams):
|
||||
"""Tiingo Trailing Dividend Yield Query.
|
||||
|
||||
Source: https://www.tiingo.com/documentation/end-of-day
|
||||
"""
|
||||
|
||||
|
||||
class TiingoTrailingDivYieldData(TrailingDivYieldData):
|
||||
"""Tiingo Trailing Dividend Yield Data."""
|
||||
|
||||
__alias_dict__ = {"trailing_dividend_yield": "trailingDiv1Y"}
|
||||
|
||||
|
||||
class TiingoTrailingDivYieldFetcher(
|
||||
Fetcher[
|
||||
TiingoTrailingDivYieldQueryParams,
|
||||
List[TiingoTrailingDivYieldData],
|
||||
]
|
||||
):
|
||||
"""Transform the query, extract and transform the data from the Tiingo endpoints."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(params: Dict[str, Any]) -> TiingoTrailingDivYieldQueryParams:
|
||||
"""Transform the query params."""
|
||||
transformed_params = params
|
||||
return TiingoTrailingDivYieldQueryParams(**transformed_params)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@staticmethod
|
||||
def extract_data(
|
||||
query: TiingoTrailingDivYieldQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the Tiingo endpoint."""
|
||||
api_key = credentials.get("tiingo_token") if credentials else ""
|
||||
url = (
|
||||
f"https://api.tiingo.com/tiingo/corporate-actions/{query.symbol}/distribution-yield?"
|
||||
f"token={api_key}"
|
||||
)
|
||||
return get_data_many(url)
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: TiingoTrailingDivYieldQueryParams,
|
||||
data: List[Dict],
|
||||
**kwargs: Any,
|
||||
) -> List[TiingoTrailingDivYieldData]:
|
||||
"""Return the transformed data."""
|
||||
return [TiingoTrailingDivYieldData.model_validate(d) for d in data]
|
||||
@@ -0,0 +1 @@
|
||||
"""Tiingo helpers."""
|
||||
108
openbb_platform/providers/tiingo/openbb_tiingo/utils/helpers.py
Normal file
108
openbb_platform/providers/tiingo/openbb_tiingo/utils/helpers.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""Tiingo Helpers Module."""
|
||||
|
||||
import json
|
||||
from io import StringIO
|
||||
from typing import Any, List, Optional, TypeVar, Union
|
||||
|
||||
import requests
|
||||
from openbb_provider import helpers
|
||||
from openbb_provider.utils.errors import EmptyDataError
|
||||
from pydantic import BaseModel
|
||||
from requests.exceptions import SSLError
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
|
||||
|
||||
class BasicResponse:
|
||||
"""Basic Response class."""
|
||||
|
||||
def __init__(self, response: StringIO):
|
||||
"""Initialize the BasicResponse class."""
|
||||
# Find a way to get the status code
|
||||
self.status_code = 200
|
||||
response.seek(0)
|
||||
self.text = response.read()
|
||||
|
||||
def json(self) -> dict:
|
||||
"""Return the response as a dictionary."""
|
||||
return json.loads(self.text)
|
||||
|
||||
|
||||
def request(url: str) -> BasicResponse:
|
||||
"""
|
||||
Request function for PyScript. Pass in Method and make sure to await.
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
url: str
|
||||
URL to make request to
|
||||
|
||||
Return:
|
||||
-------
|
||||
response: BasicRequest
|
||||
BasicRequest object with status_code and text attributes
|
||||
"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from pyodide.http import open_url # type: ignore
|
||||
|
||||
response = open_url(url)
|
||||
return BasicResponse(response)
|
||||
|
||||
|
||||
def get_data(url: str, **kwargs: Any) -> Union[list, dict]:
|
||||
"""Get data from Tiingo endpoint."""
|
||||
try:
|
||||
r: Union[requests.Response, BasicResponse] = helpers.make_request(url, **kwargs)
|
||||
except SSLError:
|
||||
r = request(url)
|
||||
if r.status_code == 404:
|
||||
raise RuntimeError("Tiingo endpoint doesn't exist")
|
||||
|
||||
data = r.json()
|
||||
if r.status_code != 200:
|
||||
error = data.get("detail")
|
||||
raise RuntimeError(f"Error in Tiingo request -> {error}")
|
||||
|
||||
if len(data) == 0:
|
||||
raise EmptyDataError()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_data_many(
|
||||
url: str, sub_dict: Optional[str] = None, **kwargs: Any
|
||||
) -> List[dict]:
|
||||
"""Get data from Tiingo endpoint and convert to list of schemas.
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
url: str
|
||||
The URL to get the data from.
|
||||
sub_dict: Optional[str]
|
||||
The sub-dictionary to use.
|
||||
|
||||
Returns:
|
||||
--------
|
||||
List[dict]
|
||||
Dictionary of data.
|
||||
"""
|
||||
data = get_data(url, **kwargs)
|
||||
if sub_dict and isinstance(data, dict):
|
||||
data = data.get(sub_dict, [])
|
||||
if isinstance(data, dict):
|
||||
raise ValueError("Expected list of dicts, got dict")
|
||||
return data
|
||||
|
||||
|
||||
def get_data_one(url: str, **kwargs: Any) -> dict:
|
||||
"""Get data from Tiingo endpoint and convert to schema."""
|
||||
data = get_data(url, **kwargs)
|
||||
if isinstance(data, list):
|
||||
if len(data) == 0:
|
||||
raise ValueError("Expected dict, got empty list")
|
||||
try:
|
||||
data = {i: data[i] for i in range(len(data))} if len(data) > 1 else data[0]
|
||||
except TypeError as e:
|
||||
raise ValueError("Expected dict, got list of dicts") from e
|
||||
|
||||
return data
|
||||
1400
openbb_platform/providers/tiingo/poetry.lock
generated
vendored
Normal file
1400
openbb_platform/providers/tiingo/poetry.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
openbb_platform/providers/tiingo/pyproject.toml
vendored
Normal file
18
openbb_platform/providers/tiingo/pyproject.toml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
[tool.poetry]
|
||||
name = "openbb-tiingo"
|
||||
version = "1.0.0b0"
|
||||
description = "Tiingo extension for OpenBB"
|
||||
authors = ["OpenBB Team <hello@openbb.co>"]
|
||||
readme = "README.md"
|
||||
packages = [{ include = "openbb_tiingo" }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
openbb-core = "^1.0.0b0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."openbb_provider_extension"]
|
||||
tiingo = "openbb_tiingo:tiingo_provider"
|
||||
@@ -0,0 +1,152 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate, br
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.tiingo.com/tiingo/news?limit=20&tickers=AAPL%2CMSFT&token=MOCK_TOKEN
|
||||
response:
|
||||
body:
|
||||
string: "[{\"id\":59591345,\"publishedDate\":\"2023-11-16T08:31:31Z\",\"title\":\"I
|
||||
walked 5,500 steps with the Google Pixel Watch 2 and Fitbit Charge 6 \u2014
|
||||
here\u2019s which was more accurate\",\"url\":\"https://www.tomsguide.com/features/i-walked-5500-steps-with-the-google-pixel-watch-2-and-fitbit-charge-6-heres-which-was-more-accurate\",\"description\":\"Here\u2019s
|
||||
which came out on top\",\"source\":\"tomsguide.com\",\"tags\":[\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T08:34:32.287630Z\",\"tickers\":[\"aapl\",\"goog\",\"googl\"]},{\"id\":59591139,\"publishedDate\":\"2023-11-16T08:22:28.911292Z\",\"title\":\"Sprinklr
|
||||
and infinit.cx Partner to Deliver AI-Powered Contact Center and Customer Experience
|
||||
Solutions\",\"url\":\"http://www.businesswire.com/news/home/20231116087060/en/Sprinklr-and-infinit.cx-Partner-to-Deliver-AI-Powered-Contact-Center-and-Customer-Experience-Solutions\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), the unified customer experience management (Unified-CXM) platform
|
||||
for modern enterprises, today announced a partnership with Con\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:22:47.067660Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59591138,\"publishedDate\":\"2023-11-16T08:22:28.901883Z\",\"title\":\"Sprinklr
|
||||
und infinit.cx kooperieren bei KI-gesttztem Contact Center und Customer Experience-Lsungen\",\"url\":\"http://www.businesswire.com/news/home/20231116060376/de/\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), die Plattform f\xFCr einheitliches Customer Experience Management
|
||||
(Unified-CXM) f\xFCr moderne Unternehmen, gab heute eine Partnerscha\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:22:45.583804Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59591365,\"publishedDate\":\"2023-11-16T08:19:00Z\",\"title\":\"Data
|
||||
Center Networking Market Report Published: A Comprehensive Report on Market
|
||||
Size, Growth Drivers, and Key Players\",\"url\":\"https://finance.yahoo.com/news/data-center-networking-market-report-081900779.html\",\"description\":\"The
|
||||
global data center networking market is expected to touch US$ 48.3 billion
|
||||
by 2030, with an annual growth rate of more than 11.5%Wilmington, Delaware,
|
||||
Nov. 16, 2023 (GLOBE NEWSWIRE) -- Global Data Center Networking Market is
|
||||
valued at US$ 22.6 billion in 2023 and is expected to grow at a significant
|
||||
CAGR of over 11.5% over the forecast period of 2023-2030, according to the
|
||||
published market report by RationalStat Market Definition, Market Scope, and
|
||||
Report Overview The advent of digital techn\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Cagr\",\"Communication
|
||||
Services\",\"Data Center\",\"Forecast Period\",\"Market Intelligence\",\"Market
|
||||
Share\",\"Market Sizing\",\"Networking Market\",\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:36:32.393928Z\",\"tickers\":[\"anet\",\"cagr\",\"csco\",\"dell\",\"dvmt\",\"fjtsy\",\"intc\",\"iqnt\",\"jnpr\",\"msft\",\"orcl\",\"vmw\"]},{\"id\":59590759,\"publishedDate\":\"2023-11-16T08:04:55Z\",\"title\":\"J
|
||||
Arnold Wealth Management Co Bolsters Portfolio with First Trust Consumer Staples
|
||||
AlphaDEX ...\",\"url\":\"https://www.gurufocus.com/search?s=j-arnold-wealth-management-co-bolsters-portfolio-with-first-trust-consumer-staples-alphadex-fund-fxg-shares\",\"description\":\"Search
|
||||
for Stocks, ETFs, Indices, Insiders, Investing Gurus and Futures on Gurufocus.com.\",\"source\":\"gurufocus.com\",\"tags\":[\"ETF\",\"Healthcare\",\"Investing
|
||||
Guru Lookup\",\"Stock\",\"Stock Insider Lookup\",\"Stock Symbol Lookup\",\"Symbol
|
||||
Lookup\",\"Technology\",\"Ticker Lookup\",\"Unknown Sector\"],\"crawlDate\":\"2023-11-16T08:05:24.260582Z\",\"tickers\":[\"aapl\",\"fxg\",\"fxg\",\"ihi\",\"isrg\",\"voo\"]},{\"id\":59591215,\"publishedDate\":\"2023-11-16T08:04:55Z\",\"title\":\"J
|
||||
Arnold Wealth Management Co Bolsters Portfolio with First Trust Consumer Staples
|
||||
AlphaDEX ...\",\"url\":\"https://finance.yahoo.com/news/j-arnold-wealth-management-co-080455684.html\",\"description\":\"J
|
||||
Arnold Wealth Management Co (Trades, Portfolio), a recognized investment firm,
|
||||
has recently expanded its portfolio with a significant addition of shares
|
||||
in the First Trust Consumer Staples AlphaDEX Fund (FXG). On October 31, 2023,
|
||||
the firm acquired 101,9722 shares of FXG, marking a notable trade action that
|
||||
reflects a strategic investment move. The transaction, which had a trade
|
||||
impact of 0.22% on the firm's portfolio, was executed at a trade price of
|
||||
$58.12.\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Consumer Staples\",\"Healthcare\",\"Portfolio\",\"Stock\",\"Strategic
|
||||
Investment\",\"Technology\",\"Trade Impact\",\"Trade Price\",\"Wealth Management\"],\"crawlDate\":\"2023-11-16T08:25:50.754245Z\",\"tickers\":[\"aapl\",\"isrg\"]},{\"id\":59590789,\"publishedDate\":\"2023-11-16T08:01:49Z\",\"title\":\"Black
|
||||
Friday Apple deals \u2014 7 best sales to shop right now\",\"url\":\"https://www.tomsguide.com/deals/black-friday-apple-deals-7-best-sales-to-shop-right-now\",\"description\":\"Save
|
||||
on iPhone 15, iPads, MacBooks and more\",\"source\":\"tomsguide.com\",\"tags\":[\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T08:06:23.382809Z\",\"tickers\":[\"aapl\"]},{\"id\":59590788,\"publishedDate\":\"2023-11-16T08:01:24Z\",\"title\":\"How
|
||||
to change keyboard shortcuts in Windows 11\",\"url\":\"https://www.tomsguide.com/how-to/how-to-change-keyboard-shortcuts-in-windows-11\",\"description\":\"Change
|
||||
keyboard shortcuts in Windows if the default ones don't work for you\",\"source\":\"tomsguide.com\",\"tags\":[\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T08:06:22.603414Z\",\"tickers\":[\"msft\"]},{\"id\":59590685,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Sprinklr
|
||||
and infinit.cx Partner to Deliver AI-Powered Contact Center and Customer Experience
|
||||
Solutions\",\"url\":\"https://www.businesswire.com/news/home/20231116087060/en/Sprinklr-and-infinit.cx-Partner-to-Deliver-AI-Powered-Contact-Center-and-Customer-Experience-Solutions/?feedref=JjAwJuNHiystnCoBq_hl-d0q77hRjGWvCunvqSsMC5PkKuEqWGdtYcKRejd3o8qMqnKfqP6Z7nZVMLG-WqUNUuIFBOuQU34x9_qUrqnb9IFt3G9xeKEyIFKgj2nxZILuWb2_mZzaa2HVGkrPJ34F1Q%3D%3D\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), the unified customer experience management (Unified-CXM) platform
|
||||
for modern enterprises, today announced a partnership with Con\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:03:15.847532Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59590686,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Sprinklr
|
||||
und infinit.cx kooperieren bei KI-gesttztem Contact Center und Customer Experience-Lsungen\",\"url\":\"https://www.businesswire.com/news/home/20231116060376/de/?feedref=JjAwJuNHiystnCoBq_hl-d0q77hRjGWvCunvqSsMC5PkKuEqWGdtYcKRejd3o8qMqnKfqP6Z7nZVMLG-WqUNUuIFBOuQU34x9_qUrqnb9IFt3G9xeKEyIFKgj2nxZILuWb2_mZzaa2HVGkrPJ34F1Q%3D%3D\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), die Plattform f\xFCr einheitliches Customer Experience Management
|
||||
(Unified-CXM) f\xFCr moderne Unternehmen, gab heute eine Partnerscha\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:03:19.469883Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59590811,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Uberall
|
||||
Announces Enhanced Integration Experience with Apple Business Connect\",\"url\":\"http://www.hawaiinewsnow.com/prnewswire/2023/11/16/uberall-announces-enhanced-integration-experience-with-apple-business-connect/\",\"description\":\"Uberall
|
||||
Announces Enhanced Integration Experience with Apple Business Connect\\nPublished:
|
||||
Nov. 15, 2023 at 10:00 PM HST\\n|\\nUpdated: 7 minutes ago\\nNew capability
|
||||
will empower multi-location businesses to manage their presence in the Apple
|
||||
ecosystem dire\",\"source\":\"hawaiinewsnow.com\",\"tags\":[\"CryptoCurrency\",\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T08:08:30.008038Z\",\"tickers\":[\"aapl\"]},{\"id\":59590969,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Virtual
|
||||
Reality Headsets Market projected to surpass USD 61.6 Billion by 2030, growing
|
||||
at a CAGR of 29.6% during the forecast period of 2023-2030 - professed by
|
||||
MarketDigits in its recent study.\",\"url\":\"https://finance.yahoo.com/news/virtual-reality-headsets-market-projected-080000399.html\",\"description\":\"The
|
||||
Global Virtual Reality Headsets Market was valued USD 7.8 Billion in 2022
|
||||
and projected to reach USD 61.6 Billion by 2030, growing at a CAGR of 29.6%
|
||||
during the forecast period of 2023-2030.Richmond, Nov. 16, 2023 (GLOBE NEWSWIRE)
|
||||
-- According to a research report \\\"Virtual Reality Headsets Market, by
|
||||
End-device (Low-end Device, Mid-range Device, High-end Device), Product Type
|
||||
(Standalone, Smartphone-enabled, Standalone PC-connected), Application (Gaming,
|
||||
Healthcare, Media & Entertainment, Ma\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Application\",\"Asia
|
||||
Pacific\",\"Entertainment\",\"Media & Entertainment\",\"North America\",\"Stock\",\"Technology\",\"Virtual
|
||||
Reality\",\"Virtual Reality Headsets\"],\"crawlDate\":\"2023-11-16T08:14:30.202071Z\",\"tickers\":[\"msft\"]},{\"id\":59590984,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"interop.io
|
||||
and comitFS Form Strategic Partnership to Revolutionize Trader-Client Conversations\",\"url\":\"https://finance.yahoo.com/news/interop-io-comitfs-form-strategic-080000985.html\",\"description\":\"interop.io,
|
||||
the leading interoperability provider for the finance industry, and comitFS,
|
||||
the market leader in optimizing high touch voice conversations, today announced
|
||||
their strategic partnership, marking a significant leap in the automation
|
||||
of voice communication within capital markets.\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Stock\",\"Strategic
|
||||
Partnership\",\"Technology\",\"Voice Conversations\",\"Workflow Automation\"],\"crawlDate\":\"2023-11-16T08:14:52.193412Z\",\"tickers\":[\"csco\",\"msft\"]},{\"id\":59590994,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"interop.io
|
||||
and comitFS Form Strategic Partnership to Revolutionize Trader-Client Conversations\",\"url\":\"https://finance.yahoo.com/news/interop-io-comitfs-form-strategic-080000483.html\",\"description\":\"interop.io,
|
||||
the leading interoperability provider for the finance industry, and comitFS,
|
||||
the market leader in optimizing high touch voice conversations, today announced
|
||||
their strategic partnership, marking a significant leap in the automation
|
||||
of voice communication within capital markets.\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Stock\",\"Strategic
|
||||
Partnership\",\"Technology\",\"Voice Conversations\",\"Workflow Automation\"],\"crawlDate\":\"2023-11-16T08:15:08.220216Z\",\"tickers\":[\"csco\",\"msft\"]},{\"id\":59590995,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Sprinklr
|
||||
und infinit.cx kooperieren bei KI-gesttztem Contact Center und Customer Experience-Lsungen\",\"url\":\"https://www.businesswire.com/news/home/20231116060376/de/?feedref=JjAwJuNHiystnCoBq_hl-fqXyBvmekC3Xq1G1wQ7hjMFbZM1ntlKeK-8bUzJqFSVSfe41V1BKA-b6v2ZVrSSNs-dUYKiDvY7XniNSqv88QcY1Ge_vf9QIMZ4alzIf_0HlyE0C4hZhHVlTvKnn0d0vQ%3D%3D\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), die Plattform f\xFCr einheitliches Customer Experience Management
|
||||
(Unified-CXM) f\xFCr moderne Unternehmen, gab heute eine Partnerscha\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:15:24.206362Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59590997,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Sprinklr
|
||||
and infinit.cx Partner to Deliver AI-Powered Contact Center and Customer Experience
|
||||
Solutions\",\"url\":\"https://www.businesswire.com/news/home/20231116087060/en/Sprinklr-and-infinit.cx-Partner-to-Deliver-AI-Powered-Contact-Center-and-Customer-Experience-Solutions/?feedref=JjAwJuNHiystnCoBq_hl-fqXyBvmekC3Xq1G1wQ7hjMFbZM1ntlKeK-8bUzJqFSVSfe41V1BKA-b6v2ZVrSSNs-dUYKiDvY7XniNSqv88QcY1Ge_vf9QIMZ4alzIf_0HlyE0C4hZhHVlTvKnn0d0vQ%3D%3D\",\"description\":\"Sprinklr
|
||||
(NYSE: CXM), the unified customer experience management (Unified-CXM) platform
|
||||
for modern enterprises, today announced a partnership with Con\",\"source\":\"businesswire.com\",\"tags\":[\"Stock\",\"Technology\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:15:25.737765Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59591209,\"publishedDate\":\"2023-11-16T08:00:00Z\",\"title\":\"Sprinklr
|
||||
and infinit.cx Partner to Deliver AI-Powered Contact Center and Customer Experience
|
||||
Solutions\",\"url\":\"https://finance.yahoo.com/news/sprinklr-infinit-cx-partner-deliver-080000313.html\",\"description\":\"NEW
|
||||
YORK, November 16, 2023--Sprinklr (NYSE: CXM), the unified customer experience
|
||||
management (Unified-CXM) platform for modern enterprises, today announced
|
||||
a partnership with Contact Center as a Service (CCaaS) and customer experience
|
||||
specialists infinit.cx to help enterprises optimize Sprinklr Service and facilitate
|
||||
a seamless, transformational migration to cloud-based customer service across
|
||||
30+ digital channels. Through this partnership, enterprises can future-proof
|
||||
their customer service, m\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Customer
|
||||
Experience Management\",\"Customer Service\",\"Sprinklr\",\"Stock\",\"Technology\",\"Technology
|
||||
Enterprises\",\"Unknown Sector\"],\"crawlDate\":\"2023-11-16T08:25:40.107409Z\",\"tickers\":[\"cxm\",\"dtegy\",\"msft\"]},{\"id\":59590684,\"publishedDate\":\"2023-11-16T07:59:36Z\",\"title\":\"iPhone
|
||||
15 Wireless Charging Is Now Broken In GM Cars After Issues With BMW\",\"url\":\"https://www.benzinga.com/news/23/11/35820909/iphone-15-wireless-charging-is-now-broken-in-gm-cars-after-issues-with-bmw\",\"description\":\"After
|
||||
BMW, now GM car owners are reporting iPhone 15 wireless charging issues, while
|
||||
some users have been told by Apple that it's a GM issue.\",\"source\":\"benzinga.com\",\"tags\":[\"Aapl\",\"Apple\",\"Appleverse\",\"Benzinga\",\"Bmwyy\",\"Consumer
|
||||
Cyclical\",\"Consumer Tech\",\"General Motors\",\"Gm\",\"Iphone\",\"Iphone
|
||||
15\",\"Mobility\",\"News\",\"Stock\",\"Tech\",\"Technology\",\"Tiingo Top\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:02:55.629506Z\",\"tickers\":[\"aapl\",\"bmwyy\",\"gm\",\"ne-ws\"]},{\"id\":59590693,\"publishedDate\":\"2023-11-16T07:47:00Z\",\"title\":\"Diginius
|
||||
is thrilled to announce the official launch of the Shopify app, Diginius Shopping,
|
||||
engineered to streamline Microsoft Shopping campaigns for Shopify store users\",\"url\":\"https://finance.yahoo.com/news/diginius-thrilled-announce-official-launch-074700630.html\",\"description\":\"Diginius
|
||||
is thrilled to announce the official launch of the Shopify app, Diginius Shopping.
|
||||
This innovative app aims to streamline Microsoft Shopping management for Shopify
|
||||
store owners advertising on Bing.\",\"source\":\"finance.yahoo.com\",\"tags\":[\"Diginius
|
||||
Shopping\",\"Microsoft\",\"Microsoft Advertising\",\"Shopify\",\"Shopping
|
||||
App\",\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T08:03:26.584670Z\",\"tickers\":[\"msft\"]},{\"id\":59589990,\"publishedDate\":\"2023-11-16T07:34:05.673695Z\",\"title\":\"TikTok
|
||||
joins Meta in appealing against EU gatekeeper status\",\"url\":\"http://www.streetinsider.com/Reuters/TikTok+joins+Meta+in+appealing+against+EU+gatekeeper+status/22421627.html\",\"description\":\"\\nBy
|
||||
Supantha Mukherjee\\n STOCKHOLM (Reuters) - TikTok on Thursday
|
||||
joined Meta in appealing against the \\\"gatekeeper\\\" status under the Digital
|
||||
Markets Act (DMA), an EU law that brings in tougher rules for tech...\\n\",\"source\":\"streetinsider.com\",\"tags\":[\"Stock\",\"Technology\"],\"crawlDate\":\"2023-11-16T07:34:06.714809Z\",\"tickers\":[\"goog\",\"googl\",\"msft\"]}]"
|
||||
headers:
|
||||
allow:
|
||||
- GET, HEAD, OPTIONS
|
||||
content-length:
|
||||
- '14859'
|
||||
content-type:
|
||||
- application/json
|
||||
date:
|
||||
- Thu, 16 Nov 2023 08:39:36 GMT
|
||||
server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
vary:
|
||||
- Cookie, Origin
|
||||
x-frame-options:
|
||||
- SAMEORIGIN
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,138 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate, br
|
||||
Connection:
|
||||
- keep-alive
|
||||
method: GET
|
||||
uri: https://api.tiingo.com/tiingo/news?limit=20&token=MOCK_TOKEN
|
||||
response:
|
||||
body:
|
||||
string: "[{\"id\":59591461,\"publishedDate\":\"2023-11-16T08:38:56Z\",\"title\":\"How
|
||||
to navigate higher education finances for a transformative journey? MintGenie
|
||||
explains\",\"url\":\"https://www.livemint.com/money/personal-finance/how-to-navigate-higher-education-finances-for-a-transformative-journey-mintgenie-explains-11699517017204.html\",\"description\":\"Navigating
|
||||
higher education finances requires careful planning and a personal approach.
|
||||
Prioritize, stay informed, budget effectively, seek scholarships, explore
|
||||
investments, and manage loans wisely to establish a robust foundation for
|
||||
a successful educational journey.\",\"source\":\"livemint.com\",\"tags\":[\"Budgeting\",\"Cost
|
||||
Of Education\",\"Educational Goals\",\"Expert Speak\",\"Financial Goals\",\"Financial
|
||||
Planning\",\"Financial Resources\",\"Higher Education\",\"Inflation\",\"Investing\",\"Loans\",\"Mutual
|
||||
Funds\",\"Personal Finance\",\"Scholarships\",\"Stocks\",\"Tax Benefits\"],\"crawlDate\":\"2023-11-16T08:39:15.354554Z\",\"tickers\":[]},{\"id\":59591464,\"publishedDate\":\"2023-11-16T08:38:22Z\",\"title\":\"Broome
|
||||
financial counsellor Sen Amaratunga recognised for service to community\",\"url\":\"https://thewest.com.au/news/broome-advertiser/broome-financial-counsellor-sen-amaratunga-recognised-for-service-to-community--c-12574080\",\"description\":\"A
|
||||
Broome financial counsellor has been honoured with an award for his dedication
|
||||
to servicing the community.\_\",\"source\":\"thewest.com.au\",\"tags\":[\"Broome-Advertiser\",\"Kimberley\"],\"crawlDate\":\"2023-11-16T08:39:32.545512Z\",\"tickers\":[]},{\"id\":59591466,\"publishedDate\":\"2023-11-16T08:38:00Z\",\"title\":\"NetEase
|
||||
Announces Third Quarter 2023 Unaudited Financial Results\",\"url\":\"https://www.prnewswire.com/news-releases/netease-announces-third-quarter-2023-unaudited-financial-results-301990338.html\",\"description\":\"/PRNewswire/
|
||||
-- NetEase, Inc. (NASDAQ: NTES and HKEX: 9999, \\\"NetEase\\\" or the \\\"Company\\\"),
|
||||
a leading internet and game services provider, today announced its...\",\"source\":\"prnewswire.com\",\"tags\":[\"Banking
|
||||
& Financial Services\",\"Computer & Electronics\",\"Computer Software\",\"Earnings\",\"Earnings
|
||||
Forecasts & Projections\",\"Electronic Gaming\",\"Entertainment\",\"Internet
|
||||
Technology\",\"Mobile Entertainment\",\"Multimedia & Internet\",\"Telecommunications
|
||||
Industry\",\"Web Site\"],\"crawlDate\":\"2023-11-16T08:39:47.836668Z\",\"tickers\":[]},{\"id\":59591465,\"publishedDate\":\"2023-11-16T08:37:46Z\",\"title\":\"UK's
|
||||
Cameron makes first official visit to Ukraine\",\"url\":\"https://thewest.com.au/news/conflict/uks-cameron-makes-first-official-visit-to-ukraine-c-12578128\",\"description\":\"David
|
||||
Cameron has met President Volodymyr Zelenskiy to underscore Britain's support
|
||||
for Ukraine on his first official trip as foreign secretary.\",\"source\":\"thewest.com.au\",\"tags\":[\"Conflict\",\"Ukraine\"],\"crawlDate\":\"2023-11-16T08:39:33.544746Z\",\"tickers\":[]},{\"id\":59591382,\"publishedDate\":\"2023-11-16T08:37:25.324087Z\",\"title\":\"Retail,
|
||||
institutional investors to be subject to same rules for short selling for
|
||||
fairness\",\"url\":\"https://koreatimes.co.kr/www/nation/2023/11/488_363360.html?utm_source=fl\",\"description\":\"The
|
||||
ruling People Power Party and financial authorities have announced plans to
|
||||
apply the same conditions for the local short selling system for both retail
|
||||
and institutional investors. \",\"source\":\"koreatimes.co.kr\",\"tags\":[\"Fsc\",\"Fss\",\"Korea\",\"Korea
|
||||
Times\",\"Korean In English\",\"Koreatimes\",\"Short Selling\",\"South Korea\",\"The
|
||||
Korea Times\",\"Tiingo Top\"],\"crawlDate\":\"2023-11-16T08:37:26.483241Z\",\"tickers\":[]},{\"id\":59591420,\"publishedDate\":\"2023-11-16T08:37:24Z\",\"title\":\"Bill
|
||||
Director buys stock worth $1M (NYSE:BILL)\",\"url\":\"https://seekingalpha.com/news/4037421-bill-director-buys-stock-worth-1m\",\"description\":\"Bill
|
||||
Holdings director David Hornik purchased $1M worth of shares at $56.49 each.
|
||||
The stock price is up 1.9% to $60.75 pre-market.\",\"source\":\"seekingalpha.com\",\"tags\":[\"Stock\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:38:21.175265Z\",\"tickers\":[\"bill\"]},{\"id\":59591429,\"publishedDate\":\"2023-11-16T08:37:11.873000Z\",\"title\":\"New
|
||||
Delhi smog grows more intense as farm fires rage\",\"url\":\"https://www.reuters.com/world/india/new-delhi-smog-grows-more-intense-farm-fires-rage-2023-11-16/\",\"description\":\"Toxic
|
||||
smog gripping New Delhi grew more intense on Thursday as farm fires raged
|
||||
in nearby fields despite a court-ordered ban, making India's capital the world's
|
||||
most polluted city again.\",\"source\":\"reuters.com\",\"tags\":[\"2023:Ml_Kbn32B0Iw\",\"2023:Ml_Kbn32B0Iw:1\",\"2023:Ml_L1N3Ch0Kv\",\"2023:Ml_L1N3Ch0Kv:1327319944\",\"2023:Ml_M1L1N3Ch0Kv\",\"2023:Ml_M1L1N3Ch0Kv:1327319944\",\"Guid:Tag:Reuters.Com\",\"India\",\"Usn:Kbn32B0Iw\",\"Usn:L1N3Ch0Kv\",\"Usn:M1L1N3Ch0Kv\",\"Vguid:Tag:Reuters.Com\"],\"crawlDate\":\"2023-11-16T08:38:28.349029Z\",\"tickers\":[]},{\"id\":59591435,\"publishedDate\":\"2023-11-16T08:37:09Z\",\"title\":\"Fans
|
||||
to miss Coldplay after flight cancellation\",\"url\":\"https://www.smh.com.au/national/fans-to-miss-coldplay-after-flight-cancellation-20231116-p5eko8.html?ref=rss&utm_medium=rss&utm_source=rss_feed\",\"description\":\"Coldplay
|
||||
and Robbie Williams fans are devastated to miss their concerts after flights
|
||||
were cancelled from Adelaide Airport.\",\"source\":\"smh.com.au\",\"tags\":[\"National\"],\"crawlDate\":\"2023-11-16T08:38:31.298558Z\",\"tickers\":[]},{\"id\":59591380,\"publishedDate\":\"2023-11-16T08:37:05Z\",\"title\":\"Bitcoin\u2019s
|
||||
Price is Pumping in the Past 24 Hours: Here\u2019s Why\",\"url\":\"https://cryptopotato.com/bitcoins-price-is-pumping-in-the-past-24-hours-heres-why/\",\"description\":\"BTC
|
||||
rose to almost $38K following the SEC's latest delay on crypto ETF applications.\",\"source\":\"cryptopotato.com\",\"tags\":[\"Bitcoin\",\"Bitcoin
|
||||
(Btc) Price\",\"Crypto Bits\",\"Crypto News\",\"CryptoCurrency\",\"ETF\",\"Financial
|
||||
Services\",\"Real Estate\",\"Stock\",\"Unknown Sector\"],\"crawlDate\":\"2023-11-16T08:37:20.616538Z\",\"tickers\":[\"bcf\",\"bgio\",\"blk\",\"ihit\",\"ivr\",\"ivz\"]},{\"id\":59591430,\"publishedDate\":\"2023-11-16T08:37:00Z\",\"title\":\"ATP
|
||||
Finals LIVE: Novak Djokovic given stark warning as Nick Kyrgios makes X-rated
|
||||
error\",\"url\":\"https://www.express.co.uk/sport/tennis/1835605/ATP-Finals-LIVE-Novak-Djokovic-Nick-Kyrgios-tennis-scores-results-highlights\",\"description\":\"Express
|
||||
Sport is on hand to provide the latest news from the ATP Finals.\",\"source\":\"express.co.uk\",\"tags\":[\"Andrey
|
||||
Rublev\",\"Atp Finals\",\"Atp Finals Highlights\",\"Atp Finals Results\",\"Atp
|
||||
Finals Scores\",\"Nick Kyrgios\",\"Novak Djokovic\",\"Rafael Nadal\",\"Tennis\",\"Tennis
|
||||
Scores\"],\"crawlDate\":\"2023-11-16T08:38:28.605087Z\",\"tickers\":[]},{\"id\":59591426,\"publishedDate\":\"2023-11-16T08:36:48Z\",\"title\":\"Royal
|
||||
Mail blames strikes and slump in letter sending as losses deepen\",\"url\":\"https://www.telegraph.co.uk/business/2023/11/16/royal-mail-blames-strikes-slump-letter-sending-losses/\",\"description\":\"Postal
|
||||
company suffers \xA3319m hit as boss reiterates calls to scrap Saturday letter
|
||||
deliveries\",\"source\":\"telegraph.co.uk\",\"tags\":[\"Business\",\"Ofcom\",\"Royal
|
||||
Mail\",\"Royal Mail Strikes\",\"Standard\",\"Stock\",\"Tiingo Top\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:38:27.571781Z\",\"tickers\":[\"roymf\"]},{\"id\":59591434,\"publishedDate\":\"2023-11-16T08:36:05Z\",\"title\":\"Car
|
||||
rams barricade near Israel embassy in Tokyo, driver detained\",\"url\":\"https://nypost.com/2023/11/16/news/car-rams-barricade-near-israel-embassy-in-tokyo-man-detained/\",\"description\":\"A
|
||||
man crashed a car into a barricade near the entrance of the Israeli embassy
|
||||
in Tokyo on Thursday, injuring a police officer.\",\"source\":\"nypost.com\",\"tags\":[\"Hamas\",\"Israel\",\"Israel
|
||||
War 2023\",\"Tokyo\"],\"crawlDate\":\"2023-11-16T08:38:31.314583Z\",\"tickers\":[]},{\"id\":59591371,\"publishedDate\":\"2023-11-16T08:36:03Z\",\"title\":\"Monet
|
||||
in Paris: The French Impressionists Alive multi-sensory experience arrives
|
||||
at Crown Perth\",\"url\":\"https://thewest.com.au/genwest/arts/monet-in-paris-the-french-impressionists-alive-multi-sensory-experience-arrives-at-crown-perth-c-12566259\",\"description\":\"All
|
||||
the charm of Parisian neighbourhood Montmartre has been transported to Perth
|
||||
with multi-sensory experience, Monet in Paris \u2013 The French Impressionists
|
||||
Alive.\",\"source\":\"thewest.com.au\",\"tags\":[\"Arts\"],\"crawlDate\":\"2023-11-16T08:36:41.491701Z\",\"tickers\":[]},{\"id\":59591356,\"publishedDate\":\"2023-11-16T08:35:54Z\",\"title\":\"Synagogue
|
||||
in Armenia set alight in latest attack on Jewish diaspora\",\"url\":\"https://www.jpost.com/diaspora/antisemitism/article-773485\",\"description\":\"A
|
||||
similar attack occurred in October by ASALA, which targeted the World Jewish
|
||||
Center in Yerevan.\",\"source\":\"jpost.com\",\"tags\":[\"Antisemitism\",\"Armenia\",\"Attack\",\"Azerbaijan\",\"Diaspora
|
||||
Jews\"],\"crawlDate\":\"2023-11-16T08:36:14.626883Z\",\"tickers\":[]},{\"id\":59591377,\"publishedDate\":\"2023-11-16T08:35:54Z\",\"title\":\"Nationwide
|
||||
protests add to Panama woes\",\"url\":\"https://splash247.com/nationwide-protests-add-to-panama-woes/\",\"description\":\"It\u2019s
|
||||
not just drought in Panama that is giving supply chain planners pause for
|
||||
reflection, the Central American nation is also reeling from the largest protests
|
||||
in the western hemisphere, action that has affected rail, roads and ports
|
||||
over the past month. Protests that began over a mining contract with a Canadian
|
||||
company have rocked \u2026\",\"source\":\"splash247.com\",\"tags\":[\"Central
|
||||
America\",\"Panama\"],\"crawlDate\":\"2023-11-16T08:37:15.350030Z\",\"tickers\":[]},{\"id\":59591358,\"publishedDate\":\"2023-11-16T08:35:03Z\",\"title\":\"Police
|
||||
investigate after woman\u2019s body found\",\"url\":\"https://www.smh.com.au/national/police-investigate-after-woman-s-body-found-20231116-p5eko7.html?ref=rss&utm_medium=rss&utm_source=rss_feed\",\"description\":\"Detectives
|
||||
are investigating after a woman's body was found in a block of units in Adelaide\u2019s
|
||||
east.\",\"source\":\"smh.com.au\",\"tags\":[\"National\"],\"crawlDate\":\"2023-11-16T08:36:19.777723Z\",\"tickers\":[]},{\"id\":59591440,\"publishedDate\":\"2023-11-16T08:35:02.359000Z\",\"title\":\"Macquarie
|
||||
invests $190 mln in green aviation fuel supplier SkyNRG\",\"url\":\"https://www.reuters.com/sustainability/climate-energy/macquarie-invests-190-mln-green-aviation-fuel-supplier-skynrg-2023-11-16/\",\"description\":\"Australia's
|
||||
Macquarie Group Ltd said on Thursday its asset management arm will make an
|
||||
initial investment of up to 175 million euros (about $190 million) in Netherlands-based
|
||||
sustainable aviation fuel (SAF) supplier SkyNRG.\",\"source\":\"reuters.com\",\"tags\":[\"2023:Ml_Kbn32B0In\",\"2023:Ml_Kbn32B0In:1\",\"2023:Ml_Kbn32B0Io\",\"2023:Ml_Kbn32B0Io:1\",\"2023:Ml_L4N3Ch1Um\",\"2023:Ml_L4N3Ch1Va\",\"2023:Ml_L4N3Ch1Va:722089037\",\"Australia\",\"Guid:Tag:Reuters.Com\",\"Netherlands\",\"Netherlands
|
||||
Antilles\",\"Stock\",\"Unknown Sector\",\"Usn:Kbn32B0In\",\"Usn:Kbn32B0Io\",\"Usn:L4N3Ch1Um\",\"Usn:L4N3Ch1Va\",\"Vguid:Tag:Reuters.Com\"],\"crawlDate\":\"2023-11-16T08:38:39.691757Z\",\"tickers\":[\"mqg\"]},{\"id\":59591353,\"publishedDate\":\"2023-11-16T08:35:00Z\",\"title\":\"US-Cannabis
|
||||
Market is to grow by USD 46.90 billion between 2022 - 2027 | Aurora Cannabis
|
||||
Inc., Canopy Growth Corp., Charlottes Web Holdings Inc. and more among the
|
||||
key companies\",\"url\":\"https://www.prnewswire.com/news-releases/us-cannabis-market-is-to-grow-by-usd-46-90-billion-between-2022---2027--aurora-cannabis-inc-canopy-growth-corp-charlottes-web-holdings-inc-and-more-among-the-key-companies-301989972.html\",\"description\":\"/PRNewswire/
|
||||
-- The US-Cannabis Market is projected to witness a surge at a Compound Annual
|
||||
Growth Rate (CAGR) of 24.03% with USD 46.90 b illion from 2022 to...\",\"source\":\"prnewswire.com\",\"tags\":[\"Cannabis\",\"CryptoCurrency\",\"ETF\",\"FX\",\"Health
|
||||
Care & Hospitals\",\"Healthcare\",\"Market Research Reports\",\"Stock\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:35:37.725202Z\",\"tickers\":[\"acb\",\"twmjf\",\"usd\"]},{\"id\":59591354,\"publishedDate\":\"2023-11-16T08:35:00Z\",\"title\":\"North
|
||||
America - The Maintenance, Repair, and Overhaul (MRO) Distribution Market
|
||||
size to grow at a CAGR of 2.43% from 2022 to 2027| A.R. Thomson Group, Applied
|
||||
Industrial Technologies Inc., AWC Inc. and more among the key companies in
|
||||
the market -Technavio\",\"url\":\"https://www.prnewswire.com/news-releases/north-america---the-maintenance-repair-and-overhaul-mro-distribution-market-size-to-grow-at-a-cagr-of-2-43-from-2022-to-2027-ar-thomson-group-applied-industrial-technologies-inc-awc-inc-and-more-among-the-key-companies-301989958.html\",\"description\":\"/PRNewswire/
|
||||
-- The MRO distribution market in North America is estimated to grow at a
|
||||
CAGR of 2.43% between 2022 and 2027 and the size of the market is...\",\"source\":\"prnewswire.com\",\"tags\":[\"Energy\",\"Industrials\",\"Market
|
||||
Research Reports\",\"North America\",\"Oil & Energy\",\"Stock\",\"Unknown
|
||||
Sector\"],\"crawlDate\":\"2023-11-16T08:35:38.520380Z\",\"tickers\":[\"ait\",\"awc\",\"cagr\",\"mro\"]},{\"id\":59591355,\"publishedDate\":\"2023-11-16T08:35:00Z\",\"title\":\"Smartphone
|
||||
Screen Protector Market is driven by the growing awareness of the importance
|
||||
of device protection - Technavio\",\"url\":\"https://www.prnewswire.com/news-releases/smartphone-screen-protector-market-is-driven-by-the-growing-awareness-of-the-importance-of-device-protection---technavio-301990019.html\",\"description\":\"/PRNewswire/
|
||||
-- In a recent analysis conducted by Technavio, titled \\\"Smartphone Screen
|
||||
Protector Market Analysis - APAC, North America, Europe, South America,...\",\"source\":\"prnewswire.com\",\"tags\":[\"Computer
|
||||
& Electronics\",\"Consumer Electronics\",\"Market Research Reports\",\"Mobile
|
||||
Entertainment\",\"North America\",\"South America\"],\"crawlDate\":\"2023-11-16T08:35:39.717934Z\",\"tickers\":[]}]"
|
||||
headers:
|
||||
allow:
|
||||
- GET, HEAD, OPTIONS
|
||||
content-length:
|
||||
- '13244'
|
||||
content-type:
|
||||
- application/json
|
||||
date:
|
||||
- Thu, 16 Nov 2023 08:40:09 GMT
|
||||
server:
|
||||
- nginx/1.18.0 (Ubuntu)
|
||||
vary:
|
||||
- Cookie, Origin
|
||||
x-frame-options:
|
||||
- SAMEORIGIN
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,90 @@
|
||||
from datetime import date
|
||||
|
||||
import pytest
|
||||
from openbb_core.app.service.user_service import UserService
|
||||
from openbb_tiingo.models.company_news import TiingoCompanyNewsFetcher
|
||||
from openbb_tiingo.models.crypto_historical import TiingoCryptoHistoricalFetcher
|
||||
from openbb_tiingo.models.currency_historical import TiingoCurrencyHistoricalFetcher
|
||||
from openbb_tiingo.models.equity_historical import TiingoEquityHistoricalFetcher
|
||||
from openbb_tiingo.models.global_news import TiingoGlobalNewsFetcher
|
||||
from openbb_tiingo.models.trailing_dividend_yield import TiingoTrailingDivYieldFetcher
|
||||
|
||||
test_credentials = UserService().default_user_settings.credentials.model_dump(
|
||||
mode="json"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def vcr_config():
|
||||
return {
|
||||
"filter_headers": [("User-Agent", None)],
|
||||
"filter_query_parameters": [
|
||||
("token", "MOCK_TOKEN"),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_equity_historical_fetcher(credentials=test_credentials):
|
||||
params = {
|
||||
"symbol": "AAPL",
|
||||
"start_date": date(2023, 1, 1),
|
||||
"end_date": date(2023, 6, 6),
|
||||
}
|
||||
|
||||
fetcher = TiingoEquityHistoricalFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_company_news_fetcher(credentials=test_credentials):
|
||||
params = {"symbols": "AAPL,MSFT"}
|
||||
|
||||
fetcher = TiingoCompanyNewsFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_global_news_fetcher(credentials=test_credentials):
|
||||
params = {}
|
||||
|
||||
fetcher = TiingoGlobalNewsFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_crypto_historical_fetcher(credentials=test_credentials):
|
||||
params = {
|
||||
"symbol": "BTCUSD",
|
||||
"start_date": date(2023, 1, 1),
|
||||
"end_date": date(2023, 6, 6),
|
||||
}
|
||||
|
||||
fetcher = TiingoCryptoHistoricalFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_currency_historical_fetcher(credentials=test_credentials):
|
||||
params = {
|
||||
"symbol": "EURUSD",
|
||||
"start_date": date(2023, 1, 1),
|
||||
"end_date": date(2023, 6, 6),
|
||||
}
|
||||
|
||||
fetcher = TiingoCurrencyHistoricalFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.record_http
|
||||
def test_tiingo_trailing_div_yield_fetcher(credentials=test_credentials):
|
||||
params = {"symbol": "SCHD"}
|
||||
|
||||
fetcher = TiingoTrailingDivYieldFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
2
openbb_platform/pyproject.toml
vendored
2
openbb_platform/pyproject.toml
vendored
@@ -17,6 +17,7 @@ openbb-intrinio = "^1.0.0b0"
|
||||
openbb-oecd = "^1.0.0b0"
|
||||
openbb-polygon = "^1.0.0b0"
|
||||
openbb-sec = "^1.0.0b0"
|
||||
openbb-tiingo = "^1.0.0b0"
|
||||
openbb-tradingeconomics = "^1.0.0b0"
|
||||
|
||||
openbb-crypto = "^1.0.0b0"
|
||||
@@ -80,6 +81,7 @@ all = [
|
||||
"openbb-technical",
|
||||
"openbb-wsj",
|
||||
"openbb-yfinance",
|
||||
"openbb-tiingo"
|
||||
]
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
|
||||
Reference in New Issue
Block a user