From d80a5ed3920a6bd4504d20585139d4386b360c9d Mon Sep 17 00:00:00 2001 From: Danglewood <85772166+deeleeramone@users.noreply.github.com> Date: Thu, 30 May 2024 02:02:42 -0700 Subject: [PATCH] [Feature] More OECD - House Price Index, Immediate Interest Rate (#6473) * add house price index * static files * unemployment cleanup * EA20 * test params * add immediate interest rates --- .../standard_models/house_price_index.py | 55 ++ .../immediate_interest_rate.py | 45 ++ .../provider/standard_models/unemployment.py | 20 +- .../economy/integration/test_economy_api.py | 54 +- .../integration/test_economy_python.py | 52 +- .../economy/openbb_economy/economy_router.py | 50 +- openbb_platform/openbb/assets/reference.json | 491 +++++++++++++++++- openbb_platform/openbb/package/economy.py | 240 ++++++++- openbb_platform/openbb/package/economy_gdp.py | 2 +- .../providers/oecd/openbb_oecd/__init__.py | 8 +- .../openbb_oecd/models/house_price_index.py | 158 ++++++ .../models/immediate_interest_rate.py | 153 ++++++ .../openbb_oecd/models/share_price_index.py | 4 +- .../oecd/openbb_oecd/models/unemployment.py | 181 ++++--- .../oecd/openbb_oecd/utils/constants.py | 10 +- .../test_oecd_house_price_index_fetcher.yaml | 54 ++ ..._oecd_immediate_interest_rate_fetcher.yaml | 57 ++ .../test_oecd_unemployment_fetcher.yaml | 305 +---------- .../oecd/tests/test_oecd_fetchers.py | 31 ++ 19 files changed, 1548 insertions(+), 422 deletions(-) create mode 100644 openbb_platform/core/openbb_core/provider/standard_models/house_price_index.py create mode 100644 openbb_platform/core/openbb_core/provider/standard_models/immediate_interest_rate.py create mode 100644 openbb_platform/providers/oecd/openbb_oecd/models/house_price_index.py create mode 100644 openbb_platform/providers/oecd/openbb_oecd/models/immediate_interest_rate.py create mode 100644 openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_house_price_index_fetcher.yaml create mode 100644 openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_immediate_interest_rate_fetcher.yaml diff --git a/openbb_platform/core/openbb_core/provider/standard_models/house_price_index.py b/openbb_platform/core/openbb_core/provider/standard_models/house_price_index.py new file mode 100644 index 000000000000..7e92b210b805 --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/standard_models/house_price_index.py @@ -0,0 +1,55 @@ +"""House Price Index Standard Model.""" + +from datetime import date as dateType +from typing import Literal, Optional + +from pydantic import Field + +from openbb_core.provider.abstract.data import Data +from openbb_core.provider.abstract.query_params import QueryParams +from openbb_core.provider.utils.descriptions import ( + DATA_DESCRIPTIONS, + QUERY_DESCRIPTIONS, +) + + +class HousePriceIndexQueryParams(QueryParams): + """House Price Index Query.""" + + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + ) + frequency: Literal["monthly", "quarter", "annual"] = Field( + description=QUERY_DESCRIPTIONS.get("frequency", ""), + default="quarter", + json_schema_extra={"choices": ["monthly", "quarter", "annual"]}, + ) + transform: Literal["index", "yoy", "period"] = Field( + description="Transformation of the CPI data. Period represents the change since previous." + + " Defaults to change from one year ago (yoy).", + default="index", + json_schema_extra={"choices": ["index", "yoy", "period"]}, + ) + start_date: Optional[dateType] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("start_date") + ) + end_date: Optional[dateType] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("end_date") + ) + + +class HousePriceIndexData(Data): + """House Price Index Data.""" + + date: Optional[dateType] = Field( + default=None, description=DATA_DESCRIPTIONS.get("date") + ) + country: Optional[str] = Field( + default=None, + description=DATA_DESCRIPTIONS.get("country", ""), + ) + value: Optional[float] = Field( + default=None, + description="Share price index value.", + ) diff --git a/openbb_platform/core/openbb_core/provider/standard_models/immediate_interest_rate.py b/openbb_platform/core/openbb_core/provider/standard_models/immediate_interest_rate.py new file mode 100644 index 000000000000..2143fc519bc1 --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/standard_models/immediate_interest_rate.py @@ -0,0 +1,45 @@ +"""Immediate Interest Rates Standard Model.""" + +from datetime import date as dateType +from typing import Optional + +from pydantic import Field + +from openbb_core.provider.abstract.data import Data +from openbb_core.provider.abstract.query_params import QueryParams +from openbb_core.provider.utils.descriptions import ( + DATA_DESCRIPTIONS, + QUERY_DESCRIPTIONS, +) + + +class ImmediateInterestRateQueryParams(QueryParams): + """Immediate (Call money, interbank rate) Rate Query.""" + + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + ) + start_date: Optional[dateType] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("start_date") + ) + end_date: Optional[dateType] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("end_date") + ) + + +class ImmediateInterestRateData(Data): + """Immediate Interest Rates Data.""" + + date: Optional[dateType] = Field( + default=None, description=DATA_DESCRIPTIONS.get("date") + ) + country: Optional[str] = Field( + default=None, + description="Country for which interest rate is given", + ) + value: Optional[float] = Field( + default=None, + description="Immediate interest rates, call money, interbank rate.", + json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100}, + ) diff --git a/openbb_platform/core/openbb_core/provider/standard_models/unemployment.py b/openbb_platform/core/openbb_core/provider/standard_models/unemployment.py index 2091aff51c47..4380719fd77d 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/unemployment.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/unemployment.py @@ -1,7 +1,7 @@ """Unemployment Standard Model.""" from datetime import date as dateType -from typing import Optional +from typing import Literal, Optional from pydantic import Field @@ -16,6 +16,15 @@ class UnemploymentQueryParams(QueryParams): """Unemployment Query.""" + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + ) + frequency: Literal["monthly", "quarter", "annual"] = Field( + description=QUERY_DESCRIPTIONS.get("frequency", ""), + default="monthly", + json_schema_extra={"choices": ["monthly", "quarter", "annual"]}, + ) start_date: Optional[dateType] = Field( default=None, description=QUERY_DESCRIPTIONS.get("start_date") ) @@ -30,11 +39,12 @@ class UnemploymentData(Data): date: Optional[dateType] = Field( default=None, description=DATA_DESCRIPTIONS.get("date") ) - value: Optional[float] = Field( - default=None, - description="Unemployment rate (given as a whole number, i.e 10=10%)", - ) country: Optional[str] = Field( default=None, description="Country for which unemployment rate is given", ) + value: Optional[float] = Field( + default=None, + description="Unemployment rate, as a normalized percent.", + json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100}, + ) diff --git a/openbb_platform/extensions/economy/integration/test_economy_api.py b/openbb_platform/extensions/economy/integration/test_economy_api.py index 556094a492ba..db2ada070bb2 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_api.py +++ b/openbb_platform/extensions/economy/integration/test_economy_api.py @@ -431,7 +431,6 @@ def test_economy_money_measures(params, headers): @parametrize( "params", [ - ({"start_date": "2023-01-01", "end_date": "2023-06-06", "provider": "oecd"}), ( { "country": "united_states", @@ -734,3 +733,56 @@ def test_economy_share_price_index(params, headers): result = requests.get(url, headers=headers, timeout=10) assert isinstance(result, requests.Response) assert result.status_code == 200 + + +@parametrize( + "params", + [ + ( + { + "country": "united_states,united_kingdom", + "frequency": "quarter", + "provider": "oecd", + "start_date": "2022-01-01", + "end_date": "2024-04-01", + "transform": "index", + } + ), + ], +) +@pytest.mark.integration +def test_economy_house_price_index(params, headers): + """Test the economy house price index.""" + 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/economy/house_price_index?{query_str}" + result = requests.get(url, headers=headers, timeout=10) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + +@parametrize( + "params", + [ + ( + { + "country": "united_states,united_kingdom", + "frequency": "monthly", + "provider": "oecd", + "start_date": "2022-01-01", + "end_date": "2024-04-01", + } + ), + ], +) +@pytest.mark.integration +def test_economy_immediate_interest_rate(params, headers): + """Test the economy immediate_interest_rate.""" + 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/economy/immediate_interest_rate?{query_str}" + result = requests.get(url, headers=headers, timeout=10) + assert isinstance(result, requests.Response) + assert result.status_code == 200 diff --git a/openbb_platform/extensions/economy/integration/test_economy_python.py b/openbb_platform/extensions/economy/integration/test_economy_python.py index 9899b9b34c28..f31297561c33 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_python.py +++ b/openbb_platform/extensions/economy/integration/test_economy_python.py @@ -400,7 +400,6 @@ def test_economy_money_measures(params, obb): @parametrize( "params", [ - ({"start_date": "2023-01-01", "end_date": "2023-06-06"}), ( { "country": "united_states", @@ -693,3 +692,54 @@ def test_economy_share_price_index(params, obb): assert result assert isinstance(result, OBBject) assert len(result.results) > 0 + + +@parametrize( + "params", + [ + ( + { + "country": "united_states,united_kingdom", + "frequency": "quarter", + "provider": "oecd", + "start_date": "2022-01-01", + "end_date": "2024-04-01", + "transform": "index", + } + ), + ], +) +@pytest.mark.integration +def test_economy_house_price_index(params, obb): + """Test economy house price index.""" + params = {p: v for p, v in params.items() if v} + + result = obb.economy.house_price_index(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + + +@parametrize( + "params", + [ + ( + { + "country": "united_states,united_kingdom", + "frequency": "monthly", + "provider": "oecd", + "start_date": "2022-01-01", + "end_date": "2024-04-01", + } + ), + ], +) +@pytest.mark.integration +def test_economy_immediate_interest_rate(params, obb): + """Test economy immediate interest rate.""" + params = {p: v for p, v in params.items() if v} + + result = obb.economy.immediate_interest_rate(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 diff --git a/openbb_platform/extensions/economy/openbb_economy/economy_router.py b/openbb_platform/extensions/economy/openbb_economy/economy_router.py index ade0833bd01b..43f869104919 100644 --- a/openbb_platform/extensions/economy/openbb_economy/economy_router.py +++ b/openbb_platform/extensions/economy/openbb_economy/economy_router.py @@ -421,7 +421,7 @@ async def central_bank_holdings( description="Multiple countries can be passed in as a list.", parameters={ "country": "united_kingdom,germany", - "frequency": "quarterly", + "frequency": "quarter", "provider": "oecd", }, ), @@ -435,3 +435,51 @@ async def share_price_index( ) -> OBBject: """Get the Share Price Index by country from the OECD Short-Term Economics Statistics.""" return await OBBject.from_query(Query(**locals())) + + +@router.command( + model="HousePriceIndex", + examples=[ + APIEx(parameters={"provider": "oecd"}), + APIEx( + description="Multiple countries can be passed in as a list.", + parameters={ + "country": "united_kingdom,germany", + "frequency": "quarter", + "provider": "oecd", + }, + ), + ], +) +async def house_price_index( + cc: CommandContext, + provider_choices: ProviderChoices, + standard_params: StandardParams, + extra_params: ExtraParams, +) -> OBBject: + """Get the House Price Index by country from the OECD Short-Term Economics Statistics.""" + return await OBBject.from_query(Query(**locals())) + + +@router.command( + model="ImmediateInterestRate", + examples=[ + APIEx(parameters={"provider": "oecd"}), + APIEx( + description="Multiple countries can be passed in as a list.", + parameters={ + "country": "united_kingdom,germany", + "frequency": "monthly", + "provider": "oecd", + }, + ), + ], +) +async def immediate_interest_rate( + cc: CommandContext, + provider_choices: ProviderChoices, + standard_params: StandardParams, + extra_params: ExtraParams, +) -> OBBject: + """Get immediate interest rates by country.""" + return await OBBject.from_query(Query(**locals())) diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index 664b855d3938..5f7900d09010 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -2340,7 +2340,7 @@ "oecd": [ { "name": "country", - "type": "Literal['G20', 'G7', 'argentina', 'australia', 'austria', 'belgium', 'brazil', 'bulgaria', 'canada', 'chile', 'china', 'colombia', 'costa_rica', 'croatia', 'czech_republic', 'denmark', 'estonia', 'euro_area_19', 'europe', 'european_union_27', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'india', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'oecd_total', 'poland', 'portugal', 'romania', 'russia', 'saudi_arabia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all']", + "type": "Literal['G20', 'G7', 'argentina', 'australia', 'austria', 'belgium', 'brazil', 'bulgaria', 'canada', 'chile', 'china', 'colombia', 'costa_rica', 'croatia', 'czech_republic', 'denmark', 'estonia', 'euro_area_20', 'euro_area_19', 'europe', 'european_union_27', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'india', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'oecd_total', 'poland', 'portugal', 'romania', 'russia', 'saudi_arabia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all']", "description": "Country to get GDP for.", "default": "united_states", "optional": true, @@ -4176,9 +4176,29 @@ "message": null }, "description": "Get global unemployment data.", - "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.unemployment(provider='oecd')\nobb.economy.unemployment(country=all, frequency=quarterly, provider='oecd')\n# Demographics for the statistics are selected with the `age` parameter.\nobb.economy.unemployment(country=all, frequency=quarterly, age=25-54, provider='oecd')\n```\n\n", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.unemployment(provider='oecd')\nobb.economy.unemployment(country='all', frequency='quarterly', provider='oecd')\n# Demographics for the statistics are selected with the `age` parameter.\nobb.economy.unemployment(country='all', frequency='quarterly', age=25-54, provider='oecd')\n```\n\n", "parameters": { "standard": [ + { + "name": "country", + "type": "Union[str, List[str]]", + "description": "The country to get data. Multiple items allowed for provider(s): oecd.", + "default": "united_states", + "optional": true, + "choices": null + }, + { + "name": "frequency", + "type": "Literal['monthly', 'quarter', 'annual']", + "description": "The frequency of the data.", + "default": "monthly", + "optional": true, + "choices": [ + "monthly", + "quarter", + "annual" + ] + }, { "name": "start_date", "type": "Union[date, str]", @@ -4206,11 +4226,57 @@ "oecd": [ { "name": "country", - "type": "Literal['colombia', 'new_zealand', 'united_kingdom', 'italy', 'luxembourg', 'euro_area19', 'sweden', 'oecd', 'south_africa', 'denmark', 'canada', 'switzerland', 'slovakia', 'hungary', 'portugal', 'spain', 'france', 'czech_republic', 'costa_rica', 'japan', 'slovenia', 'russia', 'austria', 'latvia', 'netherlands', 'israel', 'iceland', 'united_states', 'ireland', 'mexico', 'germany', 'greece', 'turkey', 'australia', 'poland', 'south_korea', 'chile', 'finland', 'european_union27_2020', 'norway', 'lithuania', 'euro_area20', 'estonia', 'belgium', 'brazil', 'indonesia', 'all']", - "description": "Country to get GDP for.", + "type": "str", + "description": "The country to get data.", "default": "united_states", "optional": true, - "choices": null + "choices": [ + "all", + "australia", + "austria", + "belgium", + "canada", + "chile", + "colombia", + "costa_rica", + "czech_republic", + "denmark", + "estonia", + "euro_area20", + "european_union27_2020", + "finland", + "france", + "g7", + "germany", + "greece", + "hungary", + "iceland", + "ireland", + "israel", + "italy", + "japan", + "korea", + "latvia", + "lithuania", + "luxembourg", + "mexico", + "netherlands", + "new_zealand", + "norway", + "oecd", + "poland", + "portugal", + "russia", + "slovakia", + "slovenia", + "south_africa", + "spain", + "sweden", + "switzerland", + "turkey", + "united_kingdom", + "united_states" + ] }, { "name": "sex", @@ -4218,23 +4284,26 @@ "description": "Sex to get unemployment for.", "default": "total", "optional": true, - "choices": null - }, - { - "name": "frequency", - "type": "Literal['monthly', 'quarterly', 'annual']", - "description": "Frequency to get unemployment for.", - "default": "monthly", - "optional": true, - "choices": null + "choices": [ + "total", + "male", + "female" + ] }, { "name": "age", - "type": "Literal['total', '15-24', '15-64', '25-54', '55-64']", + "type": "Literal['total', '15-24', '25-54', '55-64', '15-64', '15-74']", "description": "Age group to get unemployment for. Total indicates 15 years or over", "default": "total", "optional": true, - "choices": null + "choices": [ + "total", + "15-24", + "25-54", + "55-64", + "15-64", + "15-74" + ] }, { "name": "seasonal_adjustment", @@ -4286,17 +4355,17 @@ "choices": null }, { - "name": "value", - "type": "float", - "description": "Unemployment rate (given as a whole number, i.e 10=10%)", + "name": "country", + "type": "str", + "description": "Country for which unemployment rate is given", "default": null, "optional": true, "choices": null }, { - "name": "country", - "type": "str", - "description": "Country for which unemployment rate is given", + "name": "value", + "type": "float", + "description": "Unemployment rate, as a normalized percent.", "default": null, "optional": true, "choices": null @@ -4446,7 +4515,7 @@ "oecd": [ { "name": "country", - "type": "Literal['belgium', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all']", + "type": "Literal['belgium', 'bulgaria', 'brazil', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'romania', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all']", "description": "Country to get interest rate for.", "default": "united_states", "optional": true, @@ -4558,7 +4627,7 @@ "oecd": [ { "name": "country", - "type": "Literal['belgium', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all']", + "type": "Literal['belgium', 'bulgaria', 'brazil', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'romania', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all']", "description": "Country to get interest rate for.", "default": "united_states", "optional": true, @@ -5661,7 +5730,7 @@ "message": null }, "description": "Get the Share Price Index by country from the OECD Short-Term Economics Statistics.", - "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.share_price_index(provider='oecd')\n# Multiple countries can be passed in as a list.\nobb.economy.share_price_index(country='united_kingdom,germany', frequency='quarterly', provider='oecd')\n```\n\n", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.share_price_index(provider='oecd')\n# Multiple countries can be passed in as a list.\nobb.economy.share_price_index(country='united_kingdom,germany', frequency='quarter', provider='oecd')\n```\n\n", "parameters": { "standard": [ { @@ -5718,19 +5787,23 @@ "choices": [ "G20", "G7", + "all", "argentina", "australia", "austria", "belgium", "brazil", + "bulgaria", "canada", "chile", "china", "colombia", "costa_rica", + "croatia", "czech_republic", "denmark", "estonia", + "euro_area_19", "euro_area_20", "europe", "european_union_27", @@ -5757,6 +5830,7 @@ "oecd_total", "poland", "portugal", + "romania", "russia", "saudi_arabia", "slovak_republic", @@ -5767,8 +5841,7 @@ "switzerland", "turkey", "united_kingdom", - "united_states", - "all" + "united_states" ] } ] @@ -5833,6 +5906,370 @@ }, "model": "SharePriceIndex" }, + "/economy/house_price_index": { + "deprecated": { + "flag": null, + "message": null + }, + "description": "Get the House Price Index by country from the OECD Short-Term Economics Statistics.", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.house_price_index(provider='oecd')\n# Multiple countries can be passed in as a list.\nobb.economy.house_price_index(country='united_kingdom,germany', frequency='quarter', provider='oecd')\n```\n\n", + "parameters": { + "standard": [ + { + "name": "country", + "type": "Union[str, List[str]]", + "description": "The country to get data. Multiple items allowed for provider(s): oecd.", + "default": "united_states", + "optional": true, + "choices": null + }, + { + "name": "frequency", + "type": "Literal['monthly', 'quarter', 'annual']", + "description": "The frequency of the data.", + "default": "quarter", + "optional": true, + "choices": [ + "monthly", + "quarter", + "annual" + ] + }, + { + "name": "transform", + "type": "Literal['index', 'yoy', 'period']", + "description": "Transformation of the CPI data. Period represents the change since previous. Defaults to change from one year ago (yoy).", + "default": "index", + "optional": true, + "choices": [ + "index", + "yoy", + "period" + ] + }, + { + "name": "start_date", + "type": "Union[date, str]", + "description": "Start date of the data, in YYYY-MM-DD format.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "end_date", + "type": "Union[date, str]", + "description": "End date of the data, in YYYY-MM-DD format.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "provider", + "type": "Literal['oecd']", + "description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: o, e, c, d.", + "default": null, + "optional": true + } + ], + "oecd": [ + { + "name": "country", + "type": "str", + "description": "The country to get data.", + "default": "united_states", + "optional": true, + "choices": [ + "G20", + "G7", + "argentina", + "australia", + "austria", + "belgium", + "brazil", + "bulgaria", + "canada", + "chile", + "china", + "colombia", + "costa_rica", + "croatia", + "czech_republic", + "denmark", + "estonia", + "euro_area_20", + "euro_area_19", + "europe", + "european_union_27", + "finland", + "france", + "germany", + "greece", + "hungary", + "iceland", + "india", + "indonesia", + "ireland", + "israel", + "italy", + "japan", + "korea", + "latvia", + "lithuania", + "luxembourg", + "mexico", + "netherlands", + "new_zealand", + "norway", + "oecd_total", + "poland", + "portugal", + "romania", + "russia", + "saudi_arabia", + "slovak_republic", + "slovenia", + "south_africa", + "spain", + "sweden", + "switzerland", + "turkey", + "united_kingdom", + "united_states", + "all" + ] + } + ] + }, + "returns": { + "OBBject": [ + { + "name": "results", + "type": "List[HousePriceIndex]", + "description": "Serializable results." + }, + { + "name": "provider", + "type": "Optional[Literal['oecd']]", + "description": "Provider name." + }, + { + "name": "warnings", + "type": "Optional[List[Warning_]]", + "description": "List of warnings." + }, + { + "name": "chart", + "type": "Optional[Chart]", + "description": "Chart object." + }, + { + "name": "extra", + "type": "Dict[str, Any]", + "description": "Extra info." + } + ] + }, + "data": { + "standard": [ + { + "name": "date", + "type": "date", + "description": "The date of the data.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "country", + "type": "str", + "description": "", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "value", + "type": "float", + "description": "Share price index value.", + "default": null, + "optional": true, + "choices": null + } + ], + "oecd": [] + }, + "model": "HousePriceIndex" + }, + "/economy/immediate_interest_rate": { + "deprecated": { + "flag": null, + "message": null + }, + "description": "Get immediate interest rates by country.", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.economy.immediate_interest_rate(provider='oecd')\n# Multiple countries can be passed in as a list.\nobb.economy.immediate_interest_rate(country='united_kingdom,germany', frequency=monthly, provider='oecd')\n```\n\n", + "parameters": { + "standard": [ + { + "name": "country", + "type": "Union[str, List[str]]", + "description": "The country to get data. Multiple items allowed for provider(s): oecd.", + "default": "united_states", + "optional": true, + "choices": null + }, + { + "name": "start_date", + "type": "Union[date, str]", + "description": "Start date of the data, in YYYY-MM-DD format.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "end_date", + "type": "Union[date, str]", + "description": "End date of the data, in YYYY-MM-DD format.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "provider", + "type": "Literal['oecd']", + "description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: o, e, c, d.", + "default": null, + "optional": true + } + ], + "oecd": [ + { + "name": "country", + "type": "str", + "description": "The country to get data.", + "default": "united_states", + "optional": true, + "choices": [ + "belgium", + "bulgaria", + "brazil", + "ireland", + "mexico", + "indonesia", + "new_zealand", + "japan", + "united_kingdom", + "france", + "chile", + "canada", + "netherlands", + "united_states", + "south_korea", + "norway", + "austria", + "south_africa", + "denmark", + "switzerland", + "hungary", + "luxembourg", + "australia", + "germany", + "sweden", + "iceland", + "turkey", + "greece", + "israel", + "czech_republic", + "latvia", + "slovenia", + "poland", + "estonia", + "lithuania", + "portugal", + "costa_rica", + "slovakia", + "finland", + "spain", + "romania", + "russia", + "euro_area19", + "colombia", + "italy", + "india", + "china", + "croatia", + "all" + ] + }, + { + "name": "frequency", + "type": "Literal['monthly', 'quarter', 'annual']", + "description": "The frequency of the data.", + "default": "monthly", + "optional": true, + "choices": null + } + ] + }, + "returns": { + "OBBject": [ + { + "name": "results", + "type": "List[ImmediateInterestRate]", + "description": "Serializable results." + }, + { + "name": "provider", + "type": "Optional[Literal['oecd']]", + "description": "Provider name." + }, + { + "name": "warnings", + "type": "Optional[List[Warning_]]", + "description": "List of warnings." + }, + { + "name": "chart", + "type": "Optional[Chart]", + "description": "Chart object." + }, + { + "name": "extra", + "type": "Dict[str, Any]", + "description": "Extra info." + } + ] + }, + "data": { + "standard": [ + { + "name": "date", + "type": "date", + "description": "The date of the data.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "country", + "type": "str", + "description": "Country for which interest rate is given", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "value", + "type": "float", + "description": "Immediate interest rates, call money, interbank rate.", + "default": null, + "optional": true, + "choices": null + } + ], + "oecd": [] + }, + "model": "ImmediateInterestRate" + }, "/equity/calendar/ipo": { "deprecated": { "flag": null, diff --git a/openbb_platform/openbb/package/economy.py b/openbb_platform/openbb/package/economy.py index 64e219f7377a..ec82f700614d 100644 --- a/openbb_platform/openbb/package/economy.py +++ b/openbb_platform/openbb/package/economy.py @@ -24,6 +24,8 @@ class ROUTER_economy(Container): fred_search fred_series /gdp + house_price_index + immediate_interest_rate indicators long_term_interest_rate money_measures @@ -1238,6 +1240,208 @@ def gdp(self): return economy_gdp.ROUTER_economy_gdp(command_runner=self._command_runner) + @exception_handler + @validate + def house_price_index( + self, + country: Annotated[ + Union[str, List[str]], + OpenBBField( + description="The country to get data. Multiple comma separated items allowed for provider(s): oecd." + ), + ] = "united_states", + frequency: Annotated[ + Literal["monthly", "quarter", "annual"], + OpenBBField( + description="The frequency of the data.", + choices=["monthly", "quarter", "annual"], + ), + ] = "quarter", + transform: Annotated[ + Literal["index", "yoy", "period"], + OpenBBField( + description="Transformation of the CPI data. Period represents the change since previous. Defaults to change from one year ago (yoy).", + choices=["index", "yoy", "period"], + ), + ] = "index", + start_date: Annotated[ + Union[datetime.date, None, str], + OpenBBField(description="Start date of the data, in YYYY-MM-DD format."), + ] = None, + end_date: Annotated[ + Union[datetime.date, None, str], + OpenBBField(description="End date of the data, in YYYY-MM-DD format."), + ] = None, + provider: Annotated[ + Optional[Literal["oecd"]], + OpenBBField( + description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd." + ), + ] = None, + **kwargs + ) -> OBBject: + """Get the House Price Index by country from the OECD Short-Term Economics Statistics. + + Parameters + ---------- + country : Union[str, List[str]] + The country to get data. Multiple comma separated items allowed for provider(s): oecd. + frequency : Literal['monthly', 'quarter', 'annual'] + The frequency of the data. + transform : Literal['index', 'yoy', 'period'] + Transformation of the CPI data. Period represents the change since previous. Defaults to change from one year ago (yoy). + start_date : Union[datetime.date, None, str] + Start date of the data, in YYYY-MM-DD format. + end_date : Union[datetime.date, None, str] + End date of the data, in YYYY-MM-DD format. + provider : Optional[Literal['oecd']] + The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. + + Returns + ------- + OBBject + results : List[HousePriceIndex] + Serializable results. + provider : Optional[Literal['oecd']] + Provider name. + warnings : Optional[List[Warning_]] + List of warnings. + chart : Optional[Chart] + Chart object. + extra : Dict[str, Any] + Extra info. + + HousePriceIndex + --------------- + date : Optional[date] + The date of the data. + country : Optional[str] + + value : Optional[float] + Share price index value. + + Examples + -------- + >>> from openbb import obb + >>> obb.economy.house_price_index(provider='oecd') + >>> # Multiple countries can be passed in as a list. + >>> obb.economy.house_price_index(country='united_kingdom,germany', frequency='quarter', provider='oecd') + """ # noqa: E501 + + return self._run( + "/economy/house_price_index", + **filter_inputs( + provider_choices={ + "provider": self._get_provider( + provider, + "economy.house_price_index", + ("oecd",), + ) + }, + standard_params={ + "country": country, + "frequency": frequency, + "transform": transform, + "start_date": start_date, + "end_date": end_date, + }, + extra_params=kwargs, + info={"country": {"oecd": ["multiple_items_allowed"]}}, + ) + ) + + @exception_handler + @validate + def immediate_interest_rate( + self, + country: Annotated[ + Union[str, List[str]], + OpenBBField( + description="The country to get data. Multiple comma separated items allowed for provider(s): oecd." + ), + ] = "united_states", + start_date: Annotated[ + Union[datetime.date, None, str], + OpenBBField(description="Start date of the data, in YYYY-MM-DD format."), + ] = None, + end_date: Annotated[ + Union[datetime.date, None, str], + OpenBBField(description="End date of the data, in YYYY-MM-DD format."), + ] = None, + provider: Annotated[ + Optional[Literal["oecd"]], + OpenBBField( + description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd." + ), + ] = None, + **kwargs + ) -> OBBject: + """Get immediate interest rates by country. + + Parameters + ---------- + country : Union[str, List[str]] + The country to get data. Multiple comma separated items allowed for provider(s): oecd. + start_date : Union[datetime.date, None, str] + Start date of the data, in YYYY-MM-DD format. + end_date : Union[datetime.date, None, str] + End date of the data, in YYYY-MM-DD format. + provider : Optional[Literal['oecd']] + The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. + frequency : Literal['monthly', 'quarter', 'annual'] + The frequency of the data. (provider: oecd) + + Returns + ------- + OBBject + results : List[ImmediateInterestRate] + Serializable results. + provider : Optional[Literal['oecd']] + Provider name. + warnings : Optional[List[Warning_]] + List of warnings. + chart : Optional[Chart] + Chart object. + extra : Dict[str, Any] + Extra info. + + ImmediateInterestRate + --------------------- + date : Optional[date] + The date of the data. + country : Optional[str] + Country for which interest rate is given + value : Optional[float] + Immediate interest rates, call money, interbank rate. + + Examples + -------- + >>> from openbb import obb + >>> obb.economy.immediate_interest_rate(provider='oecd') + >>> # Multiple countries can be passed in as a list. + >>> obb.economy.immediate_interest_rate(country='united_kingdom,germany', frequency='monthly', provider='oecd') + """ # noqa: E501 + + return self._run( + "/economy/immediate_interest_rate", + **filter_inputs( + provider_choices={ + "provider": self._get_provider( + provider, + "economy.immediate_interest_rate", + ("oecd",), + ) + }, + standard_params={ + "country": country, + "start_date": start_date, + "end_date": end_date, + }, + extra_params=kwargs, + info={"country": {"oecd": ["multiple_items_allowed"]}}, + ) + ) + @exception_handler @validate def indicators( @@ -1401,7 +1605,7 @@ def long_term_interest_rate( End date of the data, in YYYY-MM-DD format. provider : Optional[Literal['oecd']] The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. - country : Literal['belgium', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all'] + country : Literal['belgium', 'bulgaria', 'brazil', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'romania', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all'] Country to get interest rate for. (provider: oecd) frequency : Literal['monthly', 'quarterly', 'annual'] Frequency to get interest rate for for. (provider: oecd) @@ -1694,7 +1898,7 @@ def share_price_index( >>> from openbb import obb >>> obb.economy.share_price_index(provider='oecd') >>> # Multiple countries can be passed in as a list. - >>> obb.economy.share_price_index(country='united_kingdom,germany', frequency='quarterly', provider='oecd') + >>> obb.economy.share_price_index(country='united_kingdom,germany', frequency='quarter', provider='oecd') """ # noqa: E501 return self._run( @@ -1756,7 +1960,7 @@ def short_term_interest_rate( End date of the data, in YYYY-MM-DD format. provider : Optional[Literal['oecd']] The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. - country : Literal['belgium', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all'] + country : Literal['belgium', 'bulgaria', 'brazil', 'ireland', 'mexico', 'indonesia', 'new_zealand', 'japan', 'united_kingdom', 'france', 'chile', 'canada', 'netherlands', 'united_states', 'south_korea', 'norway', 'austria', 'south_africa', 'denmark', 'switzerland', 'hungary', 'luxembourg', 'australia', 'germany', 'sweden', 'iceland', 'turkey', 'greece', 'israel', 'czech_republic', 'latvia', 'slovenia', 'poland', 'estonia', 'lithuania', 'portugal', 'costa_rica', 'slovakia', 'finland', 'spain', 'romania', 'russia', 'euro_area19', 'colombia', 'italy', 'india', 'china', 'croatia', 'all'] Country to get interest rate for. (provider: oecd) frequency : Literal['monthly', 'quarterly', 'annual'] Frequency to get interest rate for for. (provider: oecd) @@ -1813,6 +2017,19 @@ def short_term_interest_rate( @validate def unemployment( self, + country: Annotated[ + Union[str, List[str]], + OpenBBField( + description="The country to get data. Multiple comma separated items allowed for provider(s): oecd." + ), + ] = "united_states", + frequency: Annotated[ + Literal["monthly", "quarter", "annual"], + OpenBBField( + description="The frequency of the data.", + choices=["monthly", "quarter", "annual"], + ), + ] = "monthly", start_date: Annotated[ Union[datetime.date, None, str], OpenBBField(description="Start date of the data, in YYYY-MM-DD format."), @@ -1833,19 +2050,19 @@ def unemployment( Parameters ---------- + country : Union[str, List[str]] + The country to get data. Multiple comma separated items allowed for provider(s): oecd. + frequency : Literal['monthly', 'quarter', 'annual'] + The frequency of the data. start_date : Union[datetime.date, None, str] Start date of the data, in YYYY-MM-DD format. end_date : Union[datetime.date, None, str] End date of the data, in YYYY-MM-DD format. provider : Optional[Literal['oecd']] The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. - country : Literal['colombia', 'new_zealand', 'united_kingdom', 'italy', 'luxembourg', 'euro_area19', 'sweden', 'oecd', 'south_africa', 'denmark', 'canada', 'switzerland', 'slovakia', 'hungary', 'portugal', 'spain', 'france', 'czech_republic', 'costa_rica', 'japan', 'slovenia', 'russia', 'austria', 'latvia', 'netherlands', 'israel', 'iceland', 'united_states', 'ireland', 'mexico', 'germany', 'greece', 'turkey', 'australia', 'poland', 'south_korea', 'chile', 'finland', 'european_union27_2020', 'norway', 'lithuania', 'euro_area20', 'estonia', 'belgium', 'brazil', 'indonesia', 'all'] - Country to get GDP for. (provider: oecd) sex : Literal['total', 'male', 'female'] Sex to get unemployment for. (provider: oecd) - frequency : Literal['monthly', 'quarterly', 'annual'] - Frequency to get unemployment for. (provider: oecd) - age : Literal['total', '15-24', '15-64', '25-54', '55-64'] + age : Literal['total', '15-24', '25-54', '55-64', '15-64', '15-74'] Age group to get unemployment for. Total indicates 15 years or over (provider: oecd) seasonal_adjustment : bool Whether to get seasonally adjusted unemployment. Defaults to False. (provider: oecd) @@ -1868,10 +2085,10 @@ def unemployment( ------------ date : Optional[date] The date of the data. - value : Optional[float] - Unemployment rate (given as a whole number, i.e 10=10%) country : Optional[str] Country for which unemployment rate is given + value : Optional[float] + Unemployment rate, as a normalized percent. Examples -------- @@ -1893,9 +2110,12 @@ def unemployment( ) }, standard_params={ + "country": country, + "frequency": frequency, "start_date": start_date, "end_date": end_date, }, extra_params=kwargs, + info={"country": {"oecd": ["multiple_items_allowed"]}}, ) ) diff --git a/openbb_platform/openbb/package/economy_gdp.py b/openbb_platform/openbb/package/economy_gdp.py index adcbabd1f77c..1a08cca3b241 100644 --- a/openbb_platform/openbb/package/economy_gdp.py +++ b/openbb_platform/openbb/package/economy_gdp.py @@ -244,7 +244,7 @@ def real( End date of the data, in YYYY-MM-DD format. provider : Optional[Literal['oecd']] The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: oecd. - country : Literal['G20', 'G7', 'argentina', 'australia', 'austria', 'belgium', 'brazil', 'bulgaria', 'canada', 'chile', 'china', 'colombia', 'costa_rica', 'croatia', 'czech_republic', 'denmark', 'estonia', 'euro_area_19', 'europe', 'european_union_27', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'india', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'oecd_total', 'poland', 'portugal', 'romania', 'russia', 'saudi_arabia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all'] + country : Literal['G20', 'G7', 'argentina', 'australia', 'austria', 'belgium', 'brazil', 'bulgaria', 'canada', 'chile', 'china', 'colombia', 'costa_rica', 'croatia', 'czech_republic', 'denmark', 'estonia', 'euro_area_20', 'euro_area_19', 'europe', 'european_union_27', 'finland', 'france', 'germany', 'greece', 'hungary', 'iceland', 'india', 'indonesia', 'ireland', 'israel', 'italy', 'japan', 'korea', 'latvia', 'lithuania', 'luxembourg', 'mexico', 'netherlands', 'new_zealand', 'norway', 'oecd_total', 'poland', 'portugal', 'romania', 'russia', 'saudi_arabia', 'slovak_republic', 'slovenia', 'south_africa', 'spain', 'sweden', 'switzerland', 'turkey', 'united_kingdom', 'united_states', 'all'] Country to get GDP for. (provider: oecd) Returns diff --git a/openbb_platform/providers/oecd/openbb_oecd/__init__.py b/openbb_platform/providers/oecd/openbb_oecd/__init__.py index 366875f4f0af..f7fa7d3d37a8 100644 --- a/openbb_platform/providers/oecd/openbb_oecd/__init__.py +++ b/openbb_platform/providers/oecd/openbb_oecd/__init__.py @@ -6,6 +6,8 @@ from openbb_oecd.models.gdp_forecast import OECDGdpForecastFetcher from openbb_oecd.models.gdp_nominal import OECDGdpNominalFetcher from openbb_oecd.models.gdp_real import OECDGdpRealFetcher +from openbb_oecd.models.house_price_index import OECDHousePriceIndexFetcher +from openbb_oecd.models.immediate_interest_rate import OECDImmediateInterestRateFetcher from openbb_oecd.models.long_term_interest_rate import OECDLTIRFetcher from openbb_oecd.models.share_price_index import OECDSharePriceIndexFetcher from openbb_oecd.models.short_term_interest_rate import OECDSTIRFetcher @@ -13,13 +15,15 @@ oecd_provider = Provider( name="oecd", - website="https://stats.oecd.org", - description="""OECD.Stat includes data and metadata for OECD countries and selected + website="https://data-explorer.oecd.org/", + description="""OECD Data Explorer includes data and metadata for OECD countries and selected non-member economies.""", fetcher_dict={ "GdpNominal": OECDGdpNominalFetcher, "GdpReal": OECDGdpRealFetcher, "GdpForecast": OECDGdpForecastFetcher, + "HousePriceIndex": OECDHousePriceIndexFetcher, + "ImmediateInterestRate": OECDImmediateInterestRateFetcher, "Unemployment": OECDUnemploymentFetcher, "CLI": OECDCLIFetcher, "SharePriceIndex": OECDSharePriceIndexFetcher, diff --git a/openbb_platform/providers/oecd/openbb_oecd/models/house_price_index.py b/openbb_platform/providers/oecd/openbb_oecd/models/house_price_index.py new file mode 100644 index 000000000000..eaa2bc45290f --- /dev/null +++ b/openbb_platform/providers/oecd/openbb_oecd/models/house_price_index.py @@ -0,0 +1,158 @@ +"""OECD House Price Index Model.""" + +# pylint: disable=unused-argument + +from datetime import date +from io import StringIO +from typing import Any, Dict, List, Optional +from warnings import warn + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.house_price_index import ( + HousePriceIndexData, + HousePriceIndexQueryParams, +) +from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import check_item, make_request +from openbb_oecd.utils.constants import ( + CODE_TO_COUNTRY_RGDP, + COUNTRY_TO_CODE_RGDP, +) +from openbb_oecd.utils.helpers import oecd_date_to_python_date +from pandas import read_csv +from pydantic import Field, field_validator + +countries = tuple(CODE_TO_COUNTRY_RGDP.values()) + ("all",) +CountriesList = list(countries) # type: ignore +frequency_dict = { + "monthly": "M", + "quarter": "Q", + "annual": "A", +} +transform_dict = {"yoy": "PA", "period": "PC", "index": "IX"} + + +class OECDHousePriceIndexQueryParams(HousePriceIndexQueryParams): + """OECD House Price Index Query. + + Source: https://data-explorer.oecd.org/?lc=en + """ + + __json_schema_extra__ = {"country": ["multiple_items_allowed"]} + + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + choices=CountriesList, + ) + + @field_validator("country", mode="before", check_fields=False) + @classmethod + def validate_country(cls, c): + """Validate country.""" + result: List = [] + values = c.replace(" ", "_").split(",") + for v in values: + if v.upper() in CODE_TO_COUNTRY_RGDP: + result.append(CODE_TO_COUNTRY_RGDP.get(v.upper())) + continue + try: + check_item(v.lower(), CountriesList) + except Exception as e: + if len(values) == 1: + raise e from e + else: + warn(f"Invalid country: {v}. Skipping...") + continue + result.append(v.lower()) + if result: + return ",".join(result) + raise ValueError(f"No valid country found. -> {values}") + + +class OECDHousePriceIndexData(HousePriceIndexData): + """OECD House Price Index Data.""" + + +class OECDHousePriceIndexFetcher( + Fetcher[OECDHousePriceIndexQueryParams, List[OECDHousePriceIndexData]] +): + """OECD House Price Index Fetcher.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> OECDHousePriceIndexQueryParams: + """Transform the query.""" + transformed_params = params.copy() + if transformed_params.get("start_date") is None: + transformed_params["start_date"] = ( + date(2000, 1, 1) + if transformed_params.get("country") == "all" + else date(1969, 1, 1) + ) + if transformed_params.get("end_date") is None: + transformed_params["end_date"] = date(date.today().year, 12, 31) + if transformed_params.get("country") is None: + transformed_params["country"] = "united_states" + + return OECDHousePriceIndexQueryParams(**transformed_params) + + @staticmethod + def extract_data( + query: OECDHousePriceIndexQueryParams, + credentials: Optional[Dict[str, str]], + **kwargs: Any, + ) -> List[Dict]: + """Return the raw data from the OECD endpoint.""" + frequency = frequency_dict.get(query.frequency, "Q") + transform = transform_dict.get(query.transform, "PA") + + def country_string(input_str: str): + if input_str == "all": + return "" + countries = input_str.split(",") + return "+".join([COUNTRY_TO_CODE_RGDP[country] for country in countries]) + + country = country_string(query.country) if query.country else "" + start_date = query.start_date.strftime("%Y-%m") if query.start_date else "" + end_date = query.end_date.strftime("%Y-%m") if query.end_date else "" + url = ( + "https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_RHPI_TARGET@DF_RHPI_TARGET,1.0/" + + f"COU.{country}.{frequency}.RHPI.{transform}....?" + + f"startPeriod={start_date}&endPeriod={end_date}" + + "&dimensionAtObservation=TIME_PERIOD&detail=dataonly" + ) + headers = {"Accept": "application/vnd.sdmx.data+csv; charset=utf-8"} + response = make_request(url, headers=headers, timeout=20) + if response.status_code == 404 and frequency == "M": + warn("No monthly data found. Switching to quarterly data.") + response = make_request( + url.replace(".M.RHPI.", ".Q.RHPI."), headers=headers + ) + if response.status_code != 200: + raise Exception(f"Error with the OECD request: {response.status_code}") + df = read_csv(StringIO(response.text)).get( + ["REF_AREA", "TIME_PERIOD", "OBS_VALUE"] + ) + if df.empty: + raise EmptyDataError() + df = df.rename( + columns={"REF_AREA": "country", "TIME_PERIOD": "date", "OBS_VALUE": "value"} + ) + df.country = df.country.map(CODE_TO_COUNTRY_RGDP) + df.date = df.date.apply(oecd_date_to_python_date) + df = ( + df.query("value.notnull()") + .set_index(["date", "country"]) + .sort_index() + .reset_index() + ) + + return df.to_dict("records") + + @staticmethod + def transform_data( + query: OECDHousePriceIndexQueryParams, data: List[Dict], **kwargs: Any + ) -> List[OECDHousePriceIndexData]: + """Transform the data from the OECD endpoint.""" + return [OECDHousePriceIndexData.model_validate(d) for d in data] diff --git a/openbb_platform/providers/oecd/openbb_oecd/models/immediate_interest_rate.py b/openbb_platform/providers/oecd/openbb_oecd/models/immediate_interest_rate.py new file mode 100644 index 000000000000..dfca5420edfa --- /dev/null +++ b/openbb_platform/providers/oecd/openbb_oecd/models/immediate_interest_rate.py @@ -0,0 +1,153 @@ +"""OECD Immediate Interest Rate Data.""" + +# pylint: disable=unused-argument + +from datetime import date +from io import StringIO +from typing import Any, Dict, List, Literal, Optional +from warnings import warn + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.immediate_interest_rate import ( + ImmediateInterestRateData, + ImmediateInterestRateQueryParams, +) +from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import check_item, make_request +from openbb_oecd.utils.constants import CODE_TO_COUNTRY_IR, COUNTRY_TO_CODE_IR +from openbb_oecd.utils.helpers import oecd_date_to_python_date +from pandas import read_csv +from pydantic import Field, field_validator + +countries = tuple(CODE_TO_COUNTRY_IR.values()) + ("all",) +CountriesList = list(countries) +frequency_dict = { + "monthly": "M", + "quarter": "Q", + "annual": "A", +} + + +class OECDImmediateInterestRateQueryParams(ImmediateInterestRateQueryParams): + """OECD Immediate Interest Rate Query. + + Source: https://data-explorer.oecd.org/?lc=en + """ + + __json_schema_extra__ = {"country": ["multiple_items_allowed"]} + + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + json_schema_extra={"choices": CountriesList}, + ) + frequency: Literal["monthly", "quarter", "annual"] = Field( + description=QUERY_DESCRIPTIONS.get("frequency", ""), + default="monthly", + ) + + @field_validator("country", mode="before", check_fields=False) + @classmethod + def validate_country(cls, c): + """Validate country.""" + result: List = [] + values = c.replace(" ", "_").split(",") + for v in values: + if v.upper() in CODE_TO_COUNTRY_IR: + result.append(CODE_TO_COUNTRY_IR.get(v.upper())) + continue + try: + check_item(v.lower(), CountriesList) + except Exception as e: + if len(values) == 1: + raise e from e + else: + warn(f"Invalid country: {v}. Skipping...") + continue + result.append(v.lower()) + if result: + return ",".join(result) + raise ValueError(f"No valid country found. -> {values}") + + +class OECDImmediateInterestRateData(ImmediateInterestRateData): + """OECD Immediate Interest Rate Data.""" + + +class OECDImmediateInterestRateFetcher( + Fetcher[OECDImmediateInterestRateQueryParams, List[OECDImmediateInterestRateData]] +): + """Transform the query, extract and transform the data from the OECD endpoints.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> OECDImmediateInterestRateQueryParams: + """Transform the query.""" + transformed_params = params.copy() + if transformed_params.get("start_date") is None: + transformed_params["start_date"] = ( + date(2020, 1, 1) + if transformed_params.get("country") == "all" + else date(1954, 1, 1) + ) + if transformed_params.get("end_date") is None: + transformed_params["end_date"] = date(date.today().year, 12, 31) + if transformed_params.get("country") is None: + transformed_params["country"] = "united_states" + + return OECDImmediateInterestRateQueryParams(**transformed_params) + + @staticmethod + def extract_data( + query: OECDImmediateInterestRateQueryParams, + credentials: Optional[Dict[str, str]], + **kwargs: Any, + ) -> List[Dict]: + """Return the raw data from the OECD endpoint.""" + frequency = frequency_dict.get(query.frequency, "Q") + + def country_string(input_str: str): + if input_str == "all": + return "" + countries = input_str.split(",") + return "+".join([COUNTRY_TO_CODE_IR[country] for country in countries]) + + country = country_string(query.country) if query.country else "" + start_date = query.start_date.strftime("%Y-%m") if query.start_date else "" + end_date = query.end_date.strftime("%Y-%m") if query.end_date else "" + url = ( + "https://sdmx.oecd.org/public/rest/data/OECD.SDD.STES,DSD_STES@DF_FINMARK,4.0/" + + f"{country}.{frequency}.IRSTCI.PA.....?" + + f"startPeriod={start_date}&endPeriod={end_date}" + + "&dimensionAtObservation=TIME_PERIOD&detail=dataonly" + ) + headers = {"Accept": "application/vnd.sdmx.data+csv; charset=utf-8"} + response = make_request(url, headers=headers, timeout=20) + if response.status_code != 200: + raise Exception(f"Error with the OECD request: {response.status_code}") + df = read_csv(StringIO(response.text)).get( + ["REF_AREA", "TIME_PERIOD", "OBS_VALUE"] + ) + if df.empty: + raise EmptyDataError() + df = df.rename( + columns={"REF_AREA": "country", "TIME_PERIOD": "date", "OBS_VALUE": "value"} + ) + df.country = [CODE_TO_COUNTRY_IR.get(d, d) for d in df.country] + df.date = df.date.apply(oecd_date_to_python_date) + df.value = df.value.astype(float) / 100 + df = ( + df.query("value.notnull()") + .set_index(["date", "country"]) + .sort_index() + .reset_index() + ) + + return df.to_dict("records") + + @staticmethod + def transform_data( + query: OECDImmediateInterestRateQueryParams, data: List[Dict], **kwargs: Any + ) -> List[OECDImmediateInterestRateData]: + """Transform the data from the OECD endpoint.""" + return [OECDImmediateInterestRateData.model_validate(d) for d in data] diff --git a/openbb_platform/providers/oecd/openbb_oecd/models/share_price_index.py b/openbb_platform/providers/oecd/openbb_oecd/models/share_price_index.py index 7eaedfce51b7..36aa346f8b97 100644 --- a/openbb_platform/providers/oecd/openbb_oecd/models/share_price_index.py +++ b/openbb_platform/providers/oecd/openbb_oecd/models/share_price_index.py @@ -24,7 +24,7 @@ from pydantic import Field, field_validator countries = tuple(CODE_TO_COUNTRY_RGDP.values()) + ("all",) -CountriesList = list(countries) # type: ignore +CountriesList = sorted(list(countries)) # type: ignore frequency_dict = { "monthly": "M", "quarter": "Q", @@ -121,7 +121,7 @@ def country_string(input_str: str): + "&dimensionAtObservation=TIME_PERIOD&detail=dataonly" ) headers = {"Accept": "application/vnd.sdmx.data+csv; charset=utf-8"} - response = make_request(url, headers=headers) + response = make_request(url, headers=headers, timeout=20) if response.status_code != 200: raise Exception(f"Error: {response.status_code}") df = read_csv(StringIO(response.text)).get( diff --git a/openbb_platform/providers/oecd/openbb_oecd/models/unemployment.py b/openbb_platform/providers/oecd/openbb_oecd/models/unemployment.py index b85098c69e06..2f91d735b5cb 100644 --- a/openbb_platform/providers/oecd/openbb_oecd/models/unemployment.py +++ b/openbb_platform/providers/oecd/openbb_oecd/models/unemployment.py @@ -1,23 +1,46 @@ """OECD Unemployment Data.""" -import re -from datetime import date, timedelta -from typing import Any, Dict, List, Literal, Optional, Union +# pylint: disable=unused-argument + +from datetime import date +from io import StringIO +from typing import Any, Dict, List, Literal, Optional +from warnings import warn from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.unemployment import ( UnemploymentData, UnemploymentQueryParams, ) +from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import check_item, make_request from openbb_oecd.utils import helpers from openbb_oecd.utils.constants import ( CODE_TO_COUNTRY_UNEMPLOYMENT, COUNTRY_TO_CODE_UNEMPLOYMENT, ) +from pandas import read_csv from pydantic import Field, field_validator countries = tuple(CODE_TO_COUNTRY_UNEMPLOYMENT.values()) + ("all",) -CountriesLiteral = Literal[countries] # type: ignore +CountriesList = sorted(list(countries)) # type: ignore +AGES = [ + "total", + "15-24", + "25-54", + "55-64", + "15-64", + "15-74", +] +AgesLiteral = Literal[ + "total", + "15-24", + "25-54", + "55-64", + "15-64", + "15-74", +] class OECDUnemploymentQueryParams(UnemploymentQueryParams): @@ -26,61 +49,55 @@ class OECDUnemploymentQueryParams(UnemploymentQueryParams): Source: https://data-explorer.oecd.org/?lc=en """ - country: CountriesLiteral = Field( - description="Country to get GDP for.", default="united_states" + __json_schema_extra__ = {"country": ["multiple_items_allowed"]} + + country: str = Field( + description=QUERY_DESCRIPTIONS.get("country", ""), + default="united_states", + choices=CountriesList, ) sex: Literal["total", "male", "female"] = Field( - description="Sex to get unemployment for.", default="total" - ) - frequency: Literal["monthly", "quarterly", "annual"] = Field( - description="Frequency to get unemployment for.", default="monthly" + description="Sex to get unemployment for.", + default="total", + json_schema_extra={"choices": ["total", "male", "female"]}, ) - age: Literal["total", "15-24", "15-64", "25-54", "55-64"] = Field( + age: Literal[AgesLiteral] = Field( description="Age group to get unemployment for. Total indicates 15 years or over", default="total", + json_schema_extra={"choices": AGES}, ) seasonal_adjustment: bool = Field( description="Whether to get seasonally adjusted unemployment. Defaults to False.", default=False, ) + @field_validator("country", mode="before", check_fields=False) + @classmethod + def validate_country(cls, c): + """Validate country.""" + result: List = [] + values = c.replace(" ", "_").split(",") + for v in values: + if v.upper() in CODE_TO_COUNTRY_UNEMPLOYMENT: + result.append(CODE_TO_COUNTRY_UNEMPLOYMENT.get(v.upper())) + continue + try: + check_item(v.lower(), CountriesList) + except Exception as e: + if len(values) == 1: + raise e from e + else: + warn(f"Invalid country: {v}. Skipping...") + continue + result.append(v.lower()) + if result: + return ",".join(result) + raise ValueError(f"No valid country found. -> {values}") + class OECDUnemploymentData(UnemploymentData): """OECD Unemployment Data.""" - @field_validator("date", mode="before") - @classmethod - def date_validate(cls, in_date: Union[date, str]): # pylint: disable=E0213 - """Validate value.""" - if isinstance(in_date, str): - # i.e 2022-Q1 - if re.match(r"\d{4}-Q[1-4]$", in_date): - year, quarter = in_date.split("-") - _year = int(year) - if quarter == "Q1": - return date(_year, 3, 31) - if quarter == "Q2": - return date(_year, 6, 30) - if quarter == "Q3": - return date(_year, 9, 30) - if quarter == "Q4": - return date(_year, 12, 31) - # Now match if it is monthly, i.e 2022-01 - elif re.match(r"\d{4}-\d{2}$", in_date): - year, month = map(int, in_date.split("-")) # type: ignore - if month == 12: - return date(year, month, 31) # type: ignore - next_month = date(year, month + 1, 1) # type: ignore - return date(next_month.year, next_month.month, 1) - timedelta(days=1) - # Now match if it is yearly, i.e 2022 - elif re.match(r"\d{4}$", in_date): - return date(int(in_date), 12, 31) - # If the input date is a year - if isinstance(in_date, int): - return date(in_date, 12, 31) - - return in_date - class OECDUnemploymentFetcher( Fetcher[OECDUnemploymentQueryParams, List[OECDUnemploymentData]] @@ -92,13 +109,16 @@ def transform_query(params: Dict[str, Any]) -> OECDUnemploymentQueryParams: """Transform the query.""" transformed_params = params.copy() if transformed_params["start_date"] is None: - transformed_params["start_date"] = date(1950, 1, 1) + transformed_params["start_date"] = ( + date(2010, 1, 1) + if transformed_params.get("country") == "all" + else date(1950, 1, 1) + ) if transformed_params["end_date"] is None: transformed_params["end_date"] = date(date.today().year, 12, 31) return OECDUnemploymentQueryParams(**transformed_params) - # pylint: disable=unused-argument @staticmethod def extract_data( query: OECDUnemploymentQueryParams, @@ -112,49 +132,54 @@ def extract_data( "total": "Y_GE15", "15-24": "Y15T24", "15-64": "Y15T64", + "15-74": "Y15T74", "25-54": "Y25T54", "55-64": "Y55T64", }[query.age] seasonal_adjustment = "Y" if query.seasonal_adjustment else "N" - country = ( - "" - if query.country == "all" - else COUNTRY_TO_CODE_UNEMPLOYMENT[query.country] - ) - # For caching, include this in the key - query_dict = { - k: v - for k, v in query.__dict__.items() - if k not in ["start_date", "end_date"] - } + def country_string(input_str: str): + if input_str == "all": + return "" + countries = input_str.split(",") + return "+".join( + [COUNTRY_TO_CODE_UNEMPLOYMENT[country] for country in countries] + ) + + country = country_string(query.country) + start_date = query.start_date.strftime("%Y-%m") if query.start_date else "" + end_date = query.end_date.strftime("%Y-%m") if query.end_date else "" url = ( - f"https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_LFS@DF_IALFS_INDIC," - f"1.0/{country}.UNE_LF...{seasonal_adjustment}.{sex}.{age}..." + "https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_LFS@DF_IALFS_UNE_M,1.0/" + + f"{country}..._Z.{seasonal_adjustment}.{sex}.{age}..{frequency}" + + f"?startPeriod={start_date}&endPeriod={end_date}" + + "&dimensionAtObservation=TIME_PERIOD&detail=dataonly" ) - data = helpers.get_possibly_cached_data( - url, function="economy_unemployment", query_dict=query_dict + headers = {"Accept": "application/vnd.sdmx.data+csv; charset=utf-8"} + response = make_request(url, headers=headers, timeout=20) + if response.status_code != 200: + raise Exception(f"Error: {response.status_code}") + df = read_csv(StringIO(response.text)).get( + ["REF_AREA", "TIME_PERIOD", "OBS_VALUE"] ) - url_query = f"AGE=='{age}' & SEX=='{sex}' & FREQ=='{frequency}' & ADJUSTMENT=='{seasonal_adjustment}'" - url_query = url_query + f" & REF_AREA=='{country}'" if country else url_query - # Filter down - data = ( - data.query(url_query) - .reset_index(drop=True)[["REF_AREA", "TIME_PERIOD", "VALUE"]] - .rename( - columns={"REF_AREA": "country", "TIME_PERIOD": "date", "VALUE": "value"} - ) + if df.empty: + raise EmptyDataError() + df = df.rename( + columns={"REF_AREA": "country", "TIME_PERIOD": "date", "OBS_VALUE": "value"} ) - data["country"] = data["country"].map(CODE_TO_COUNTRY_UNEMPLOYMENT) - - data["date"] = data["date"].apply(helpers.oecd_date_to_python_date) - data = data[ - (data["date"] <= query.end_date) & (data["date"] >= query.start_date) - ] + df["value"] = df["value"].astype(float) / 100 + df["country"] = df["country"].map(CODE_TO_COUNTRY_UNEMPLOYMENT) + df["date"] = df["date"].apply(helpers.oecd_date_to_python_date) + df = ( + df.query("value.notnull()") + .set_index(["date", "country"]) + .sort_index() + .reset_index() + ) + df = df[(df["date"] <= query.end_date) & (df["date"] >= query.start_date)] - return data.to_dict(orient="records") + return df.to_dict(orient="records") - # pylint: disable=unused-argument @staticmethod def transform_data( query: OECDUnemploymentQueryParams, data: List[Dict], **kwargs: Any diff --git a/openbb_platform/providers/oecd/openbb_oecd/utils/constants.py b/openbb_platform/providers/oecd/openbb_oecd/utils/constants.py index 67daa4b05313..540c91727d42 100644 --- a/openbb_platform/providers/oecd/openbb_oecd/utils/constants.py +++ b/openbb_platform/providers/oecd/openbb_oecd/utils/constants.py @@ -67,6 +67,7 @@ "czech_republic": "CZE", "denmark": "DNK", "estonia": "EST", + "euro_area_20": "EA20", "euro_area_19": "EA19", "europe": "OECDE", "european_union_27": "EU27_2020", @@ -464,7 +465,6 @@ "united_kingdom": "GBR", "italy": "ITA", "luxembourg": "LUX", - "euro_area19": "EA19", "sweden": "SWE", "oecd": "OECD", "south_africa": "ZAF", @@ -494,7 +494,7 @@ "turkey": "TUR", "australia": "AUS", "poland": "POL", - "south_korea": "KOR", + "korea": "KOR", "chile": "CHL", "finland": "FIN", "european_union27_2020": "EU27_2020", @@ -503,8 +503,7 @@ "euro_area20": "EA20", "estonia": "EST", "belgium": "BEL", - "brazil": "BRA", - "indonesia": "IDN", + "g7": "G7", } CODE_TO_COUNTRY_UNEMPLOYMENT = {v: k for k, v in COUNTRY_TO_CODE_UNEMPLOYMENT.items()} @@ -535,6 +534,8 @@ COUNTRY_TO_CODE_IR = { "belgium": "BEL", + "bulgaria": "BGR", + "brazil": "BRA", "ireland": "IRL", "mexico": "MEX", "indonesia": "IDN", @@ -572,6 +573,7 @@ "slovakia": "SVK", "finland": "FIN", "spain": "ESP", + "romania": "ROU", "russia": "RUS", "euro_area19": "EA19", "colombia": "COL", diff --git a/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_house_price_index_fetcher.yaml b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_house_price_index_fetcher.yaml new file mode 100644 index 000000000000..6522430b652d --- /dev/null +++ b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_house_price_index_fetcher.yaml @@ -0,0 +1,54 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/vnd.sdmx.data+csv; charset=utf-8 + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_RHPI_TARGET@DF_RHPI_TARGET,1.0/COU.GBR.Q.RHPI.IX....?detail=dataonly&dimensionAtObservation=TIME_PERIOD&endPeriod=2024-04&startPeriod=2020-01 + response: + body: + string: !!binary | + H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcpl + VmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ip4evzl+ + 9vzL745enT77/Y9fnR7//m9+n5en9q/Rs1enPzH64vT49VevTkdfvTh78/ubP46ffuer12++OH3x + ZvTm1fGL18++fPXF8ZuzL1+MfvLsxZvjz09HT797+vz52YvPX4/enH1x+vu/PH119uXT0ZdPXv/+ + P3n8/KtT/u31m+M3X71WyF89fzN6enpy9sXx89ejJ8ev+Z3fOPny9OTp+PXTp+M3L18/evr66e// + 6tsvz37/N8evPj9983s+feb/ubU73rkzOvnyq9HnT16NfmKEr0Znv/foxej3/6nR7/8G/9vb2dvZ + /ond0e7ug/HuzsGInp+dLva4i3t7n1IPP0td3Bvt7u2MD3b3qIefpS72qYv98d7+zxahdnku9j4d + 7+0+oB5+lrqgudg7GO9/ep96+FnqgubiHs3F/s/WXFAXNBf37o33Du5RD99QF0EXezwX9z4d7z/c + px5+lrqgudjfGe883KUefpa6oLnYvz/e3/tZJBTNBXXx6e7PFkfd47nY3xvv/KxNN3WBudgd39/5 + 2Zpu6gJzsT/evfezpUCoC8zFvfHuAx3F/wOSfHj51AYAAA== + headers: + Accept-Ranges: + - values + Cache-Control: + - no-store,no-cache + Content-Encoding: + - gzip + Content-Language: + - en,en-US + Content-Type: + - application/vnd.sdmx.data+csv; charset=utf-8 + Date: + - Wed, 29 May 2024 22:58:50 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=2592000 + Transfer-Encoding: + - chunked + Vary: + - Accept,Accept-Encoding,Accept-Encoding + X-Server-Node: + - Server 2 + api-supported-versions: + - '1' + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_immediate_interest_rate_fetcher.yaml b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_immediate_interest_rate_fetcher.yaml new file mode 100644 index 000000000000..2e101d959026 --- /dev/null +++ b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_immediate_interest_rate_fetcher.yaml @@ -0,0 +1,57 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/vnd.sdmx.data+csv; charset=utf-8 + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://sdmx.oecd.org/public/rest/data/OECD.SDD.STES,DSD_STES@DF_FINMARK,4.0/GBR.M.IRSTCI.PA.....?detail=dataonly&dimensionAtObservation=TIME_PERIOD&endPeriod=2024-01&startPeriod=2021-01 + response: + body: + string: !!binary | + H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcpl + VmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ip4evzl+ + 9vzL745enT77/Y9fnR6Pnr06/YnRF6fHr796dTr66sXZm9/f/HF88ubsJ8/e/D6j46ff+er1my9O + X7wZvXl1/OL1sy9ffXH85uzLF6M3Z1+c/v7f/vLV2U8RiDff/vLpl8+//Pz3kY9fnr46+/Lp6Msn + r3//nzx+/tUp//b6zfGbr15rP189fzN6enpy9sXx89ejJ8ev+Z3fOPny9OTp+PVT+v+b09ePnr5+ + Sm+dvv49nz77/Z+dvfji+NXvtbU/3rkz+vzJq9EXo7NXr9+cnI1eHo9+/59y/3sx2tvZ293e2R3t + jHf2H+6P6PlGAe8x4INPCe43C/jezxbg/Z8twPcZ8MP7BPebBfypAD4guN8s4AcAfJ/g0/ONAj4Q + wN88uz1kwAT1Q8ESTPqfgt3dYbDEzPR8k/juitx9+o1P3S7kbnd3f5fgfoOA90RT7D68/w1jTICB + 8f7uw4cE95sFDE1x/9O9ewT3mwUMTfHpw29aPAgwNMXD3Z8FGn862h3vPPj0AcH9ZgE/IMC7D0mu + 6flGAR8Q4E/3vmHBI7gPCe7B/U8Hue3rAiZVsTfePbj/jZOYVMUeYfzNywepinvj3QcPvmHA96Aq + 7o339x58w+qYAAPjh6TmCO43C/jeiJru3PvmAe8TYKLxN2zwCPB9Anzv/t43LHgE+FMCfP/gwTcs + eQT4AQF+eI/mkJ5vFPDB6P5491OSbHo+GLAP+CEAH9z/xiePdAUAP/jG2Y10BQP+xiWPdAUDJrDf + INx9qAqGqwj/P85u9899DQAA + headers: + Accept-Ranges: + - values + Cache-Control: + - no-store,no-cache + Content-Encoding: + - gzip + Content-Language: + - en,en-US + Content-Type: + - application/vnd.sdmx.data+csv; charset=utf-8 + Date: + - Thu, 30 May 2024 06:00:37 GMT + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=2592000 + Transfer-Encoding: + - chunked + Vary: + - Accept,Accept-Encoding,Accept-Encoding + X-Server-Node: + - Server 2 + api-supported-versions: + - '1' + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_unemployment_fetcher.yaml b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_unemployment_fetcher.yaml index 57d5c41d85cb..a4f7e36af43c 100644 --- a/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_unemployment_fetcher.yaml +++ b/openbb_platform/providers/oecd/tests/record/http/test_oecd_fetchers/test_oecd_unemployment_fetcher.yaml @@ -3,301 +3,24 @@ interactions: body: null headers: Accept: - - '*/*' + - application/vnd.sdmx.data+csv; charset=utf-8 Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_LFS@DF_IALFS_INDIC,1.0/USA.UNE_LF...N._T.Y_GE15... + uri: https://sdmx.oecd.org/public/rest/data/OECD.SDD.TPS,DSD_LFS@DF_IALFS_UNE_M,1.0/USA..._Z.N._T.Y_GE15..M?detail=dataonly&dimensionAtObservation=TIME_PERIOD&endPeriod=2023-06&startPeriod=2023-01 response: body: string: !!binary | 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 - AwA= + VmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/Ip4evzl+ + 9vzL745enT77/Y9fnR6Pvjg9fv3Vq9PRVy/O3vz+5o83r45fvH725asvjt+cfflidPz0O1+9fvPF + 6Ys3o9env/fo+PPT0fHJm7OfPHvz+4yevTr9idGbsy9Of/+Xp6/Ovnw6+vLJ69//J4+ff3U6enL8 + mj/lj16/OX7z1Wvt5qvnb0ZPT0/Ovjh+/vo3Tr48PXk6fv306fjNy9ePnr5++vs/f/b693z67Pc/ + O6Zffv+vXpz+/l9s7Y537oy+en1MAE7p+9//i9HLN/j5+qsno9//p0YvRr//m9Hv8/t/frp7H39+ + Mdrb2bu3vbM7ujd+OKLnZ7OTvR9GJ/eok0+pj5/VTvapk13q42e1k/vUyT718bPayafUyQH1MfqN + k/8H8vTbtPMCAAA= headers: Accept-Ranges: - values @@ -305,10 +28,12 @@ interactions: - no-store,no-cache Content-Encoding: - gzip + Content-Language: + - en,en-US Content-Type: - - application/vnd.sdmx.genericdata+xml; version=2.1; charset=utf-8 + - application/vnd.sdmx.data+csv; charset=utf-8 Date: - - Thu, 29 Feb 2024 19:36:26 GMT + - Thu, 30 May 2024 00:59:53 GMT Pragma: - no-cache Strict-Transport-Security: @@ -318,7 +43,7 @@ interactions: Vary: - Accept,Accept-Encoding,Accept-Encoding X-Server-Node: - - Server 2 + - Server 3 api-supported-versions: - '1' status: diff --git a/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py b/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py index b0e3a76e06ea..627083359946 100644 --- a/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py +++ b/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py @@ -9,6 +9,8 @@ from openbb_oecd.models.gdp_forecast import OECDGdpForecastFetcher from openbb_oecd.models.gdp_nominal import OECDGdpNominalFetcher from openbb_oecd.models.gdp_real import OECDGdpRealFetcher +from openbb_oecd.models.house_price_index import OECDHousePriceIndexFetcher +from openbb_oecd.models.immediate_interest_rate import OECDImmediateInterestRateFetcher from openbb_oecd.models.long_term_interest_rate import OECDLTIRFetcher from openbb_oecd.models.share_price_index import OECDSharePriceIndexFetcher from openbb_oecd.models.short_term_interest_rate import OECDSTIRFetcher @@ -145,3 +147,32 @@ def test_oecd_share_price_index_fetcher(credentials=test_credentials): fetcher = OECDSharePriceIndexFetcher() result = fetcher.test(params, credentials) assert result is None + + +@pytest.mark.record_http +def test_oecd_house_price_index_fetcher(credentials=test_credentials): + """Test the OECD House Price Index fetcher.""" + params = { + "start_date": datetime.date(2020, 1, 1), + "end_date": datetime.date(2024, 4, 1), + "country": "united_kingdom", + } + + fetcher = OECDHousePriceIndexFetcher() + result = fetcher.test(params, credentials) + assert result is None + + +@pytest.mark.record_http +def test_oecd_immediate_interest_rate_fetcher(credentials=test_credentials): + """Test the OECD Immediate Interest Rate fetcher.""" + params = { + "start_date": datetime.date(2021, 1, 1), + "end_date": datetime.date(2024, 1, 1), + "country": "united_kingdom", + "frequency": "monthly", + } + + fetcher = OECDImmediateInterestRateFetcher() + result = fetcher.test(params, credentials) + assert result is None