Files
OpenBB/openbb_platform/providers/fred/integration/test_fred_python.py
Danglewood 124a420f79 [V5] openbb-fred: Refactor as V5 extension. (#7669)
* refactor fred extension for v5

* fix markdown MD037 lint error in README

* codespell
2026-09-23 12:54:02 -07:00

1788 lines
60 KiB
Python

"""FRED provider module integration tests."""
from datetime import date, datetime
from math import inf, isfinite
from statistics import median
import pytest
from openbb_core.app.model.obbject import OBBject
from openbb_fred.models.ameribor import MATURITY_TO_FRED_ID, FredAmeriborData
from openbb_fred.models.balance_of_payments import FredBalanceOfPaymentsData
from openbb_fred.models.bond_indices import BAML_CATEGORIES, FredBondIndicesData
from openbb_fred.models.commercial_paper import CP_SERIES_IDS, FREDCommercialPaperData
from openbb_fred.models.commodity_spot_prices import (
SERIES_MAP,
FredCommoditySpotPricesData,
)
from openbb_fred.models.consumer_price_index import FREDConsumerPriceIndexData
from openbb_fred.models.dwpcr_rates import FREDDiscountWindowPrimaryCreditRateData
from openbb_fred.models.ecb_interest_rates import (
FREDEuropeanCentralBankInterestRatesData,
)
from openbb_fred.models.economic_calendar import FredEconomicCalendarData
from openbb_fred.models.euro_short_term_rate import FredEuroShortTermRateData
from openbb_fred.models.fed_projections import FREDPROJECTIONData
from openbb_fred.models.federal_funds_rate import FredFederalFundsRateData
from openbb_fred.models.ffrmc import FREDSelectedTreasuryConstantMaturityData
from openbb_fred.models.high_quality_market import (
FredHighQualityMarketCorporateBondData,
)
from openbb_fred.models.iorb_rates import FREDIORBData
from openbb_fred.models.manufacturing_outlook_ny import FredManufacturingOutlookNYData
from openbb_fred.models.manufacturing_outlook_texas import (
FredManufacturingOutlookTexasData,
)
from openbb_fred.models.mortgage_indices import (
MORTGAGE_CHOICES_TO_ID,
FredMortgageIndicesData,
)
from openbb_fred.models.non_farm_payrolls import FredNonFarmPayrollsData
from openbb_fred.models.overnight_bank_funding_rate import (
FredOvernightBankFundingRateData,
)
from openbb_fred.models.personal_consumption_expenditures import (
FredPersonalConsumptionExpendituresData,
)
from openbb_fred.models.regional import FredRegionalData
from openbb_fred.models.release_table import FredReleaseTableData
from openbb_fred.models.retail_prices import FredRetailPricesData
from openbb_fred.models.search import FredSearchData
from openbb_fred.models.senior_loan_officer_survey import (
SLOOS_CATEGORIES,
FredSeniorLoanOfficerSurveyData,
)
from openbb_fred.models.series import FredSeriesData
from openbb_fred.models.sofr import FREDSOFRData
from openbb_fred.models.sonia_rates import FREDSONIAData
from openbb_fred.models.spot import FREDSpotRateData
from openbb_fred.models.survey_of_economic_conditions_chicago import (
FredSurveyOfEconomicConditionsChicagoData,
)
from openbb_fred.models.tbffr import FREDSelectedTreasuryBillData
from openbb_fred.models.tips_yields import FredTipsYieldsData
from openbb_fred.models.tmc import FREDTreasuryConstantMaturityData
from openbb_fred.models.university_of_michigan import FredUofMichiganData
from openbb_fred.models.yield_curve import FREDYieldCurveData
from openbb_fred.utils.api import observation_dates
from openbb_fred.utils.fred_helpers import YIELD_CURVES
PERCENT_BAND = (-100.0, 100.0)
POSITIVE_BAND = (0.0, 1.0e6)
INDEX_BAND = (0.0, 1.0e5)
COUNT_BAND = (0.0, 1.0e12)
WIDE_BAND = (-1.0e15, 1.0e15)
TRANSFORMS = ("chg", "ch1", "pch", "pc1", "pca", "cch", "cca", "log")
def results_of(result, data_class, minimum=1):
"""Return the rows an OBBject carries, asserting the model it validated as.
Parameters
----------
result : OBBject
The command output.
data_class : type
The provider Data model the rows are expected to validate as.
minimum : int
The fewest rows the parameters can legitimately return.
Returns
-------
list
The validated rows.
"""
assert isinstance(result, OBBject)
assert isinstance(result.results, list)
assert len(result.results) >= minimum
assert isinstance(result.results[0], data_class)
assert set(data_class.model_fields) <= set(result.results[0].model_dump())
return result.results
def dates_of(rows, field="date"):
"""Return one date per row, asserting every one of them is a real date."""
dates = [getattr(row, field) for row in rows]
assert dates
assert all(isinstance(value, date) for value in dates)
return dates
def assert_oldest_first(dates):
"""Assert the observations are ordered oldest first."""
assert list(dates) == sorted(dates)
def assert_newest_first(dates):
"""Assert the observations are ordered newest first."""
assert list(dates) == sorted(dates, reverse=True)
def assert_inside_window(dates, params):
"""Assert every observation falls inside the window the query asked for."""
start = params.get("start_date")
end = params.get("end_date")
if start:
assert min(dates) >= date.fromisoformat(start)
if end:
assert max(dates) <= date.fromisoformat(end)
def assert_finite(values, low, high):
"""Assert the published numbers are finite and inside a plausible band.
Parameters
----------
values : list
The values read off the rows, nulls included.
low : float
The lowest value the field can plausibly carry.
high : float
The highest value the field can plausibly carry.
Returns
-------
list
The values that were actually published.
"""
seen = [value for value in values if value is not None]
assert all(isinstance(value, (int, float)) for value in seen)
assert all(isfinite(value) for value in seen)
assert all(low <= value <= high for value in seen)
return seen
def assert_months(dates, requested):
"""Assert every observation falls in one of the months the query asked for."""
months = {tuple(entry[:7].split("-")) for entry in observation_dates(requested)}
assert {(f"{value.year:04d}", f"{value.month:02d}") for value in dates} <= months
def median_gap(dates):
"""Return the median number of days between consecutive observations."""
ordered = sorted(set(dates))
assert len(ordered) > 1
return median(
(later - earlier).days for earlier, later in zip(ordered, ordered[1:])
)
def band_for(params, tight):
"""Return the band a field sits in, widened when the query transforms it."""
return WIDE_BAND if params.get("transform") in TRANSFORMS else tight
@pytest.fixture(scope="session")
def obb(pytestconfig):
"""Fixture to setup obb."""
if pytestconfig.getoption("markexpr") != "not integration":
import openbb
return openbb.obb
return None
class TestCommodityPrice:
"""Test the commodity price commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"commodity": "all",
"start_date": None,
"end_date": None,
"frequency": None,
"transform": None,
"aggregation_method": None,
"provider": "fred",
},
{
"commodity": "wti",
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "avg",
"transform": "pc1",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_commodity_spot_prices_are_returned(self, params, obb):
"""Test the commodity price spot command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.commodity.price.spot(**params)
commodity = params.get("commodity", "all")
rows = results_of(result, FredCommoditySpotPricesData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.symbol for row in rows} <= set(SERIES_MAP[commodity].split(","))
assert all(row.commodity for row in rows)
assert assert_finite(
[row.price for row in rows], *band_for(params, POSITIVE_BAND)
)
if params.get("frequency") == "m":
assert len(rows) <= 13
else:
assert len(rows) > 100
class TestEconomy:
"""Test the economy commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"country": "united_states",
"start_date": None,
"end_date": None,
"provider": "fred",
},
{
"country": "japan",
"start_date": "2020-01-01",
"end_date": "2023-12-31",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_balance_of_payments_is_returned(self, params, obb):
"""Test the economy balance_of_payments command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.balance_of_payments(**params)
rows = results_of(result, FredBalanceOfPaymentsData)
periods = dates_of(rows, "period")
assert_newest_first(periods)
assert_inside_window(periods, params)
assert median_gap(periods) >= 80
assert assert_finite(
[row.balance_total for row in rows]
+ [row.credits_total for row in rows]
+ [row.debits_total for row in rows],
*WIDE_BAND,
)
assert_finite(
[row.balance_percent_of_gdp for row in rows],
-200.0,
200.0,
)
if params.get("start_date"):
assert len(rows) <= 24
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2025-07-01",
"end_date": "2025-07-02",
"release_id": None,
"provider": "fred",
},
{
"start_date": "2024-01-02",
"end_date": "2024-01-09",
"release_id": 10,
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_calendar_is_returned(self, params, obb):
"""Test the economy calendar command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.calendar(**params)
rows = results_of(result, FredEconomicCalendarData)
stamps = [row.date for row in rows]
assert all(isinstance(stamp, datetime) for stamp in stamps)
assert_inside_window([stamp.date() for stamp in stamps], params)
assert all(row.event for row in rows)
assert all(isinstance(row.release_id, int) for row in rows)
if params.get("release_id"):
assert {row.release_id for row in rows} == {params["release_id"]}
@pytest.mark.parametrize(
"params",
[
{"country": "united_states", "provider": "fred"},
{
"country": "spain",
"transform": "yoy",
"frequency": "annual",
"harmonized": False,
"start_date": "2020-01-01",
"end_date": "2023-06-06",
"provider": "fred",
},
{
"country": "portugal,spain",
"transform": "period",
"frequency": "monthly",
"harmonized": True,
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_cpi_is_returned(self, params, obb):
"""Test the economy cpi command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.cpi(**params)
rows = results_of(result, FREDConsumerPriceIndexData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.country for row in rows} <= set(params["country"].split(","))
assert assert_finite([row.value for row in rows], *PERCENT_BAND)
if params.get("frequency") == "annual":
assert len(rows) <= 8
@pytest.mark.parametrize(
"params",
[
{"symbol": "NYUR", "provider": "fred"},
{
"symbol": "CAICLAIMS",
"is_series_group": False,
"start_date": "1990-01-01",
"end_date": "2010-01-01",
"provider": "fred",
},
{
"symbol": "156241",
"is_series_group": True,
"start_date": "2000-01-01",
"end_date": None,
"frequency": "w",
"units": "Number",
"region_type": "state",
"season": "nsa",
"aggregation_method": "eop",
"transform": "ch1",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_fred_regional_is_returned(self, params, obb):
"""Test the economy fred_regional command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.fred_regional(**params)
rows = results_of(result, FredRegionalData)
dates = dates_of(rows)
assert all(isinstance(row.region, str) and row.region for row in rows)
assert all(isinstance(row.series_id, str) and row.series_id for row in rows)
assert all(row.code not in (None, "") for row in rows)
assert assert_finite([row.value for row in rows], *WIDE_BAND)
if params.get("end_date"):
assert max(dates) <= date.fromisoformat(params["end_date"])
@pytest.mark.parametrize(
"params",
[
{"release_id": "50", "provider": "fred"},
{"release_id": "14", "element_id": "7930", "provider": "fred"},
{
"release_id": "53",
"element_id": "12883",
"date": "2023-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_fred_release_table_is_returned(self, params, obb):
"""Test the economy fred_release_table command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.fred_release_table(**params)
rows = results_of(result, FredReleaseTableData)
keys = [
(str(row.date or ""), inf if row.line is None else row.line) for row in rows
]
assert keys == sorted(keys)
assert all(row.element_id for row in rows)
assert all(row.name for row in rows)
assert_finite([row.value for row in rows], *WIDE_BAND)
observed = [row for row in rows if row.symbol]
if observed:
assert all(isinstance(row.date, date) for row in observed)
assert all(row.value is not None for row in observed)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{"query": "gdp", "provider": "fred"},
{
"query": "GDP*",
"search_type": "series_id",
"release_id": None,
"offset": 0,
"limit": 10,
"order_by": "observation_end",
"sort_order": "desc",
"filter_variable": None,
"filter_value": None,
"tag_names": None,
"exclude_tag_names": None,
"series_id": None,
"provider": "fred",
},
{
"query": None,
"search_type": "release",
"release_id": 10,
"limit": 10,
"use_cache": False,
"provider": "fred",
},
{"series_id": "NYICLAIMS", "provider": "fred"},
],
)
@pytest.mark.integration
def test_fred_search_is_returned(self, params, obb):
"""Test the economy fred_search command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.fred_search(**params)
rows = results_of(result, FredSearchData)
ends = [row.observation_end for row in rows]
if params.get("limit"):
assert len(rows) <= params["limit"]
if all(end is not None for end in ends):
assert ends == sorted(ends, reverse=True)
if params.get("series_id"):
assert {row.series_id for row in rows} == {params["series_id"]}
assert all(row.series_group for row in rows)
elif params.get("release_id"):
assert all(row.series_id for row in rows)
elif params.get("query"):
assert all(row.series_id for row in rows)
if params.get("search_type") != "series_id":
term = params["query"].lower()
assert all(
term in " ".join(str(v) for v in row.model_dump().values()).lower()
for row in rows
)
else:
assert all(row.release_id for row in rows)
@pytest.mark.parametrize(
"params",
[
{"symbol": "GDP", "provider": "fred"},
{
"symbol": "SP500",
"start_date": None,
"end_date": None,
"limit": 10000,
"frequency": "q",
"aggregation_method": "eop",
"transform": "chg",
"provider": "fred",
},
{
"symbol": "GDP,UNRATE",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_fred_series_is_returned(self, params, obb):
"""Test the economy fred_series command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.fred_series(**params)
rows = results_of(result, FredSeriesData)
dates = dates_of(rows)
symbols = params["symbol"].split(",")
carried = {key.lower().replace("_", "") for key in rows[0].model_dump()}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {symbol.lower().replace("_", "") for symbol in symbols} <= carried
assert assert_finite(
[
value
for row in rows
for key, value in row.model_dump().items()
if key != "date"
],
*WIDE_BAND,
)
if params.get("limit"):
assert len(rows) <= params["limit"]
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"date": "2024-05-01,2024-04-01,2023-05-01",
"category": "pce_price_index",
"provider": "fred",
},
{
"date": "2024-06-01",
"category": "real_pce_percent_change",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_pce_is_returned(self, params, obb):
"""Test the economy pce command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.pce(**params)
rows = results_of(result, FredPersonalConsumptionExpendituresData)
dates = dates_of(rows)
keys = [(row.date, row.line) for row in rows]
assert keys == sorted(keys)
assert all(row.symbol and row.name and row.units for row in rows)
assert all(row.element_id and row.parent_id for row in rows)
assert all(isinstance(row.level, int) for row in rows)
assert assert_finite([row.value for row in rows], *WIDE_BAND)
if params.get("date"):
assert_months(dates, params["date"])
assert len(set(dates)) <= len(observation_dates(params["date"]))
@pytest.mark.parametrize(
"params",
[
{},
{"release_id": "9", "element_id": "201241"},
{
"release_id": "9",
"element_id": "201241",
"frequency": "monthly",
"limit": 4,
"use_cache": False,
},
],
)
@pytest.mark.integration
def test_release_table_is_returned(self, params, obb):
"""Test the economy release_table command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.release_table(**params)
fixed = {"series", "symbol", "units", "trend"}
assert isinstance(result, list)
assert len(result) > 0
assert all(isinstance(row, dict) for row in result)
assert all(fixed <= set(row) for row in result)
assert all(row["series"] for row in result)
periods = [key for key in result[0] if key not in fixed]
assert periods
assert len(periods) <= params.get("limit", 8)
assert all(date.fromisoformat(period) for period in periods)
assert all(set(row) - fixed == set(periods) for row in result)
observed = [row for row in result if row["symbol"]]
assert observed
assert all(isinstance(row["trend"], list) and row["trend"] for row in observed)
assert assert_finite(
[value for row in observed for value in row["trend"]], *WIDE_BAND
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"country": "united_states",
"item": "meats",
"region": "all_city",
"frequency": "annual",
"start_date": "2022-01-01",
"end_date": "2024-04-01",
"transform": "pc1",
"provider": "fred",
},
{
"item": "eggs",
"region": "northeast",
"frequency": "monthly",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_retail_prices_are_returned(self, params, obb):
"""Test the economy retail_prices command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.retail_prices(**params)
rows = results_of(result, FredRetailPricesData)
dates = dates_of(rows)
keys = [(row.date, row.description) for row in rows]
assert keys == sorted(keys)
assert_inside_window(dates, params)
assert {row.country for row in rows} == {"united_states"}
assert all(row.symbol and row.description for row in rows)
assert assert_finite(
[row.value for row in rows], *band_for(params, POSITIVE_BAND)
)
class TestEconomySurvey:
"""Test the economy survey commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2024-01-01",
"end_date": "2024-04-01",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"frequency": "quarter",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_economic_conditions_chicago_is_returned(self, params, obb):
"""Test the economy survey economic_conditions_chicago command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.economic_conditions_chicago(**params)
rows = results_of(result, FredSurveyOfEconomicConditionsChicagoData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite(
[row.activity_index for row in rows]
+ [row.one_year_outlook for row in rows]
+ [row.current_hiring for row in rows],
*band_for(params, PERCENT_BAND),
)
if params.get("frequency") == "quarter":
assert len(rows) <= 20
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"topic": "new_orders",
"start_date": "2024-01-01",
"end_date": "2024-04-01",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"topic": "business_outlook,employment",
"seasonally_adjusted": True,
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"frequency": "quarter",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_manufacturing_outlook_ny_is_returned(self, params, obb):
"""Test the economy survey manufacturing_outlook_ny command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.manufacturing_outlook_ny(**params)
rows = results_of(result, FredManufacturingOutlookNYData)
dates = dates_of(rows)
topics = params.get("topic", "new_orders").split(",")
expected = {
f"{side}_{topic}" for topic in topics for side in ("current", "future")
}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.topic for row in rows} <= expected
assert assert_finite(
[row.diffusion_index for row in rows], *band_for(params, PERCENT_BAND)
)
assert_finite(
[row.percent_reporting_increase for row in rows]
+ [row.percent_reporting_decrease for row in rows]
+ [row.percent_reporting_no_change for row in rows],
*band_for(params, (0.0, 100.0)),
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"topic": "new_orders",
"start_date": "2024-01-01",
"end_date": "2024-04-01",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"topic": "business_activity,production",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"frequency": "annual",
"aggregation_method": "eop",
"transform": "ch1",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_manufacturing_outlook_texas_is_returned(self, params, obb):
"""Test the economy survey manufacturing_outlook_texas command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.manufacturing_outlook_texas(**params)
rows = results_of(result, FredManufacturingOutlookTexasData)
dates = dates_of(rows)
topics = params.get("topic", "new_orders_growth").split(",")
expected = {
f"{side}_{topic}" for topic in topics for side in ("current", "future")
}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.topic for row in rows} <= expected
assert assert_finite(
[row.diffusion_index for row in rows], *band_for(params, PERCENT_BAND)
)
if params.get("frequency") == "annual":
assert len(rows) <= 5 * len(expected)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"date": "2024-06-01,2023-06-01",
"category": "avg_earnings_hourly",
"provider": "fred",
},
{
"date": "2024-06-01",
"category": "employees_sa",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_nonfarm_payrolls_are_returned(self, params, obb):
"""Test the economy survey nonfarm_payrolls command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.nonfarm_payrolls(**params)
rows = results_of(result, FredNonFarmPayrollsData)
dates = dates_of(rows)
category = params.get("category", "employees_nsa")
assert_oldest_first(dates)
assert all(row.symbol and row.name for row in rows)
assert all(row.element_id and row.parent_id for row in rows)
assert all(isinstance(row.level, int) for row in rows)
if category.startswith("employees") and not category.endswith("percent"):
assert assert_finite([row.value for row in rows], *COUNT_BAND)
else:
assert assert_finite([row.value for row in rows], *WIDE_BAND)
if params.get("date"):
assert_months(dates, params["date"])
assert len(set(dates)) <= len(observation_dates(params["date"]))
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"category": "auto",
"start_date": "2022-01-01",
"end_date": "2024-04-01",
"provider": "fred",
},
{
"category": "credit_card",
"transform": "pch",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_sloos_is_returned(self, params, obb):
"""Test the economy survey sloos command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.sloos(**params)
rows = results_of(result, FredSeniorLoanOfficerSurveyData)
dates = dates_of(rows)
wanted = SLOOS_CATEGORIES[params.get("category", "spreads")].split(",")
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.symbol for row in rows} <= set(wanted)
assert all(row.title for row in rows)
assert assert_finite(
[row.value for row in rows], *band_for(params, PERCENT_BAND)
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"frequency": None,
"start_date": "2022-01-01",
"end_date": "2024-04-01",
"transform": None,
"aggregation_method": None,
"provider": "fred",
},
{
"frequency": "quarter",
"aggregation_method": "avg",
"transform": "pch",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_university_of_michigan_is_returned(self, params, obb):
"""Test the economy survey university_of_michigan command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.economy.survey.university_of_michigan(**params)
rows = results_of(result, FredUofMichiganData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite(
[row.consumer_sentiment for row in rows], *band_for(params, (0.0, 200.0))
)
assert assert_finite(
[row.inflation_expectation for row in rows],
*band_for(params, PERCENT_BAND),
)
if params.get("frequency") == "quarter":
assert len(rows) <= 20
class TestFixedIncome:
"""Test the top-level fixed income commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"category": "high_yield",
"index": "us,europe,emerging",
"index_type": "total_return",
"start_date": "2023-05-31",
"end_date": "2024-06-01",
"transform": None,
"frequency": None,
"aggregation_method": "avg",
"provider": "fred",
},
{
"category": "us",
"index": "corporate",
"index_type": "oas",
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "eop",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_bond_indices_are_returned(self, params, obb):
"""Test the fixedincome bond_indices command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.bond_indices(**params)
rows = results_of(result, FredBondIndicesData)
dates = dates_of(rows)
index = params.get("index", "yield_curve")
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert all(row.title for row in rows)
if index == "yield_curve":
maturities = set(BAML_CATEGORIES[params.get("category", "us")][index])
assert {row.maturity for row in rows} <= maturities
else:
assert {row.maturity for row in rows} == {None}
if params.get("index_type") == "total_return":
assert assert_finite([row.value for row in rows], *INDEX_BAND)
else:
assert assert_finite([row.value for row in rows], *PERCENT_BAND)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"index": "usda_30y,fha_30y",
"start_date": "2023-05-31",
"end_date": "2024-06-01",
"transform": None,
"frequency": None,
"aggregation_method": "avg",
"provider": "fred",
},
{
"index": "conforming_30y",
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "eop",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_mortgage_indices_are_returned(self, params, obb):
"""Test the fixedincome mortgage_indices command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.mortgage_indices(**params)
rows = results_of(result, FredMortgageIndicesData)
dates = dates_of(rows)
wanted = {
symbol
for index in params.get("index", "primary").split(",")
for symbol in MORTGAGE_CHOICES_TO_ID[index].split(",")
}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.symbol for row in rows} <= wanted
assert all(row.name for row in rows)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
class TestFixedIncomeCorporate:
"""Test the corporate bond commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"maturity": "overnight",
"category": "financial",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"maturity": "30d",
"category": "asset_backed",
"frequency": "m",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_commercial_paper_is_returned(self, params, obb):
"""Test the fixedincome corporate commercial_paper command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.corporate.commercial_paper(**params)
rows = results_of(result, FREDCommercialPaperData)
dates = dates_of(rows)
maturity = params.get("maturity", "all")
category = params.get("category", "all")
published = {
(entry["maturity"], entry["asset"]) for entry in CP_SERIES_IDS.values()
}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {(row.maturity, row.asset_type) for row in rows} <= published
assert all(row.title for row in rows)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
if category != "all":
assert {row.asset_type for row in rows} == set(category.split(","))
if maturity != "all":
assert {row.maturity for row in rows} == {
entry if entry == "overnight" else f"day_{entry.rstrip('d')}"
for entry in maturity.split(",")
}
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{"date": "2023-01-01", "yield_curve": "spot", "provider": "fred"},
{
"date": "2023-01-01,2024-01-01",
"yield_curve": "par",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_hqm_is_returned(self, params, obb):
"""Test the fixedincome corporate hqm command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.corporate.hqm(**params)
rows = results_of(result, FredHighQualityMarketCorporateBondData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert all(row.maturity.startswith("year_") for row in rows)
assert all(float(row.maturity[len("year_") :]) > 0 for row in rows)
assert assert_finite([row.rate for row in rows], *PERCENT_BAND)
assert 1 <= len(set(dates)) <= len(observation_dates(params.get("date")))
if params.get("date"):
assert_months(dates, params["date"])
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"maturity": "10",
"category": "spot_rate",
"provider": "fred",
},
{
"start_date": None,
"end_date": None,
"maturity": "1,5.5,10",
"category": "spot_rate,par_yield",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_spot_rates_are_returned(self, params, obb):
"""Test the fixedincome corporate spot_rates command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.corporate.spot_rates(**params)
rows = results_of(result, FREDSpotRateData)
dates = dates_of(rows)
labels = {"spot_rate": "Spot Rate", "par_yield": "Par Yield"}
assert_inside_window(dates, params)
assert assert_finite([row.rate for row in rows], *PERCENT_BAND)
assert all("High Quality Market (HQM)" in row.title for row in rows)
if params.get("maturity"):
heads = tuple(
f"{entry}-Year" for entry in str(params["maturity"]).split(",")
)
assert all(row.title.startswith(heads) for row in rows)
if params.get("category"):
wanted = {labels[entry] for entry in str(params["category"]).split(",")}
assert {row.title.rsplit("Bond ", 1)[-1] for row in rows} == wanted
class TestFixedIncomeGovernment:
"""Test the government bond commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"maturity": None,
"start_date": None,
"end_date": None,
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"maturity": "10",
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "eop",
"transform": "pc1",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_tips_yields_are_returned(self, params, obb):
"""Test the fixedincome government tips_yields command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.government.tips_yields(**params)
rows = results_of(result, FredTipsYieldsData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert all(row.symbol.startswith("DTP") for row in rows)
assert all(isinstance(row.due, date) for row in rows)
assert all(row.name for row in rows)
assert assert_finite(
[row.value for row in rows], *band_for(params, PERCENT_BAND)
)
if params.get("maturity"):
assert all(
row.symbol.rsplit("DTP", 1)[-1].startswith(params["maturity"])
for row in rows
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"yield_curve_type": "nominal",
"date": "2023-05-01,2024-05-01",
"provider": "fred",
},
{
"yield_curve_type": "real",
"date": None,
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_yield_curve_is_returned(self, params, obb):
"""Test the fixedincome government yield_curve command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.government.yield_curve(**params)
rows = results_of(result, FREDYieldCurveData)
dates = dates_of(rows)
curve = params.get("yield_curve_type", "nominal")
maturities = set(YIELD_CURVES[curve].values())
wanted = len(str(params["date"]).split(",")) if params.get("date") else 1
published = [
value
for value in (row.model_dump()["rate"] for row in rows)
if value is not None and isfinite(value)
]
assert_oldest_first(dates)
assert {row.maturity for row in rows} <= maturities
assert len(set(dates)) == wanted
assert len(rows) == wanted * len({row.maturity for row in rows})
assert published
assert all(PERCENT_BAND[0] <= value <= PERCENT_BAND[1] for value in published)
class TestFixedIncomeRate:
"""Test the reference rate commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"maturity": "overnight",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"maturity": "average_30d,term_90d",
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_ameribor_is_returned(self, params, obb):
"""Test the fixedincome rate ameribor command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.ameribor(**params)
rows = results_of(result, FredAmeriborData)
dates = dates_of(rows)
wanted = {
symbol
for entry in params.get("maturity", "all").split(",")
for symbol in MATURITY_TO_FRED_ID[entry].split(",")
}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert {row.symbol for row in rows} <= wanted
assert {row.maturity for row in rows} <= {"overnight", "day_30", "day_90"}
assert all(row.title for row in rows)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"parameter": "daily_excl_weekend",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"provider": "fred",
},
{
"parameter": "weekly",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_dpcredit_is_returned(self, params, obb):
"""Test the fixedincome rate dpcredit command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.dpcredit(**params)
rows = results_of(result, FREDDiscountWindowPrimaryCreditRateData)
dates = dates_of(rows)
cadence = {"daily_excl_weekend": (1, 4), "weekly": (6, 8)}
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], 0.0, 25.0)
low, high = cadence[params.get("parameter", "daily_excl_weekend")]
assert low <= median_gap(dates) <= high
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"interest_rate_type": "lending",
"provider": "fred",
},
{
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"interest_rate_type": "deposit",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_ecb_is_returned(self, params, obb):
"""Test the fixedincome rate ecb command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.ecb(**params)
rows = results_of(result, FREDEuropeanCentralBankInterestRatesData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], -5.0, 25.0)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"frequency": "w",
"transform": None,
"aggregation_method": "avg",
"effr_only": False,
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"provider": "fred",
},
{
"effr_only": True,
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_effr_is_returned(self, params, obb):
"""Test the fixedincome rate effr command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.effr(**params)
rows = results_of(result, FredFederalFundsRateData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite([row.rate for row in rows], *PERCENT_BAND)
if params.get("effr_only"):
assert {row.target_range_upper for row in rows} == {None}
assert {row.volume for row in rows} == {None}
else:
assert assert_finite(
[row.target_range_upper for row in rows]
+ [row.target_range_lower for row in rows],
*PERCENT_BAND,
)
assert assert_finite(
[row.volume for row in rows], *band_for(params, COUNT_BAND)
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{"long_run": False, "provider": "fred"},
{"long_run": True, "use_cache": False, "provider": "fred"},
],
)
@pytest.mark.integration
def test_effr_forecast_is_returned(self, params, obb):
"""Test the fixedincome rate effr_forecast command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.effr_forecast(**params)
rows = results_of(result, FREDPROJECTIONData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert assert_finite(
[row.median for row in rows]
+ [row.range_high for row in rows]
+ [row.range_low for row in rows],
-5.0,
25.0,
)
assert all(
row.range_low <= row.median <= row.range_high
for row in rows
if None not in (row.range_low, row.median, row.range_high)
)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_estr_is_returned(self, params, obb):
"""Test the fixedincome rate estr command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.estr(**params)
rows = results_of(result, FredEuroShortTermRateData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
assert_finite(
[row.number_of_banks for row in rows], *band_for(params, (0.0, 1000.0))
)
assert_finite([row.transactions for row in rows], *band_for(params, COUNT_BAND))
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{"start_date": "2023-01-01", "end_date": "2023-06-06", "provider": "fred"},
{
"start_date": "2021-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_iorb_is_returned(self, params, obb):
"""Test the fixedincome rate iorb command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.iorb(**params)
rows = results_of(result, FREDIORBData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], 0.0, 25.0)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"transform": None,
"aggregation_method": None,
"frequency": None,
"provider": "fred",
},
{
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "eop",
"transform": "chg",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_overnight_bank_funding_is_returned(self, params, obb):
"""Test the fixedincome rate overnight_bank_funding command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.overnight_bank_funding(**params)
rows = results_of(result, FredOvernightBankFundingRateData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
assert_finite(
[row.percentile_1 for row in rows] + [row.percentile_99 for row in rows],
*band_for(params, PERCENT_BAND),
)
assert_finite([row.volume for row in rows], *band_for(params, COUNT_BAND))
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"frequency": None,
"transform": None,
"aggregation_method": None,
"provider": "fred",
},
{
"start_date": "2023-01-01",
"end_date": "2024-01-01",
"frequency": "m",
"aggregation_method": "avg",
"transform": "pch",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_sofr_is_returned(self, params, obb):
"""Test the fixedincome rate sofr command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.sofr(**params)
rows = results_of(result, FREDSOFRData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert assert_finite(
[row.rate for row in rows], *band_for(params, PERCENT_BAND)
)
assert_finite(
[row.average_30d for row in rows] + [row.average_180d for row in rows],
*band_for(params, PERCENT_BAND),
)
assert_finite([row.volume for row in rows], *band_for(params, COUNT_BAND))
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"parameter": "rate",
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"provider": "fred",
},
{
"parameter": "index",
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_sonia_is_returned(self, params, obb):
"""Test the fixedincome rate sonia command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.rate.sonia(**params)
rows = results_of(result, FREDSONIAData)
dates = dates_of(rows)
rates = [row.rate for row in rows]
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
if params.get("parameter") == "index":
assert assert_finite(rates, 0.0, 1.0e6)
else:
assert assert_finite(rates, -5.0, 25.0)
class TestFixedIncomeSpreads:
"""Test the rate spread commands the FRED router serves."""
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"maturity": "3m",
"provider": "fred",
},
{
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"maturity": "2y",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_tcm_is_returned(self, params, obb):
"""Test the fixedincome spreads tcm command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.spreads.tcm(**params)
rows = results_of(result, FREDTreasuryConstantMaturityData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], -25.0, 25.0)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"maturity": "10y",
"provider": "fred",
},
{
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"maturity": "6m",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_tcm_effr_is_returned(self, params, obb):
"""Test the fixedincome spreads tcm_effr command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.spreads.tcm_effr(**params)
rows = results_of(result, FREDSelectedTreasuryConstantMaturityData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], -25.0, 25.0)
@pytest.mark.parametrize(
"params",
[
{"provider": "fred"},
{
"start_date": "2023-01-01",
"end_date": "2023-06-06",
"maturity": "3m",
"provider": "fred",
},
{
"start_date": "2020-01-01",
"end_date": "2024-01-01",
"maturity": "6m",
"use_cache": False,
"provider": "fred",
},
],
)
@pytest.mark.integration
def test_treasury_effr_is_returned(self, params, obb):
"""Test the fixedincome spreads treasury_effr command."""
params = {p: v for p, v in params.items() if v is not None}
result = obb.fred.fixedincome.spreads.treasury_effr(**params)
rows = results_of(result, FREDSelectedTreasuryBillData)
dates = dates_of(rows)
assert_oldest_first(dates)
assert_inside_window(dates, params)
assert len(set(dates)) == len(dates)
assert assert_finite([row.rate for row in rows], -25.0, 25.0)