diff options
author | Danglewood <85772166+deeleeramone@users.noreply.github.com> | 2024-06-16 14:30:46 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-16 21:30:46 +0000 |
commit | 650912bf0c21714a109ff50ff8ed94651eaf1d63 (patch) | |
tree | 88554e5c019e8b85042b2300c77dc0c77d460ad3 | |
parent | 3db89dae5e6fc9a56d1499d9e4176fbe9f06af46 (diff) |
add mortgage indices (#6501)
10 files changed, 869 insertions, 0 deletions
diff --git a/openbb_platform/core/openbb_core/provider/standard_models/mortgage_indices.py b/openbb_platform/core/openbb_core/provider/standard_models/mortgage_indices.py new file mode 100644 index 00000000000..bfba892bb2d --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/standard_models/mortgage_indices.py @@ -0,0 +1,46 @@ +"""Mortgage Indices 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 MortgageIndicesQueryParams(QueryParams): + """Mortgage Indices Query.""" + + 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 MortgageIndicesData(Data): + """Mortgage Indices Data.""" + + date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", "")) + symbol: Optional[str] = Field( + default=None, + description=DATA_DESCRIPTIONS.get("symbol", ""), + ) + name: Optional[str] = Field( + default=None, + description="Name of the index.", + ) + rate: float = Field( + description="Mortgage rate.", + json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100}, + ) diff --git a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py index 1e9844767f3..521040398c2 100644 --- a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py +++ b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py @@ -694,3 +694,29 @@ def test_fixedincome_bond_indices(params, headers): result = requests.get(url, headers=headers, timeout=10) assert isinstance(result, requests.Response) assert result.status_code == 200 + + +@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", + }, + ], +) +@pytest.mark.integration +def test_fixedincome_mortgage_indices(params, headers): + """Test the mortgage indices endpoint.""" + 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/fixedincome/mortgage_indices?{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/fixedincome/integration/test_fixedincome_python.py b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py index 433b96a3d8f..6058c18ecc9 100644 --- a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py +++ b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py @@ -647,3 +647,28 @@ def test_fixedincome_bond_indices(params, obb): assert result assert isinstance(result, OBBject) assert len(result.results) > 0 + + +@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", + }, + ], +) +@pytest.mark.integration +def test_fixedincome_mortgage_indices(params, obb): + """Test the mortgage indices endpoint.""" + params = {p: v for p, v in params.items() if v} + + result = obb.fixedincome.mortgage_indices(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 diff --git a/openbb_platform/extensions/fixedincome/openbb_fixedincome/fixedincome_router.py b/openbb_platform/extensions/fixedincome/openbb_fixedincome/fixedincome_router.py index fb346dd3cc3..f7d62a1b16b 100644 --- a/openbb_platform/extensions/fixedincome/openbb_fixedincome/fixedincome_router.py +++ b/openbb_platform/extensions/fixedincome/openbb_fixedincome/fixedincome_router.py @@ -81,3 +81,29 @@ async def bond_indices( ) -> OBBject: # type: ignore """Bond Indices.""" return await OBBject.from_query(Query(**locals())) + + +@router.command( + model="MortgageIndices", + examples=[ + APIEx( + description="The default state for FRED are the primary mortgage indices from Optimal Blue.", + parameters={"provider": "fred"}, + ), + APIEx( + description="Multiple indices can be requested.", + parameters={ + "index": "jumbo_30y,conforming_30y,conforming_15y", + "provider": "fred", + }, + ), + ], +) +async def mortgage_indices( + cc: CommandContext, + provider_choices: ProviderChoices, + standard_params: StandardParams, + extra_params: ExtraParams, +) -> OBBject: # type: ignore + """Mortgage Indices.""" + return await OBBject.from_query(Query(**locals())) diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index 7b5bf13451f..ca1dcb3f376 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -32235,6 +32235,191 @@ }, "model": "BondIndices" }, + "/fixedincome/mortgage_indices": { + "deprecated": { + "flag": null, + "message": null + }, + "description": "Mortgage Indices.", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\n# The default state for FRED are the primary mortgage indices from Optimal Blue.\nobb.fixedincome.mortgage_indices(provider='fred')\n# Multiple indices can be requested.\nobb.fixedincome.mortgage_indices(index=jumbo_30y,conforming_30y,conforming_15y, provider='fred')\n```\n\n", + "parameters": { + "standard": [ + { + "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['fred']", + "description": "The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: f, r, e, d.", + "default": null, + "optional": true + } + ], + "fred": [ + { + "name": "index", + "type": "Union[Union[Literal['primary', 'ltv_lte_80', 'ltv_gt_80', 'conforming_30y', 'conforming_30y_na', 'jumbo_30y', 'fha_30y', 'va_30y', 'usda_30y', 'conforming_15y', 'ltv_lte80_fico_ge740', 'ltv_lte80_fico_a720b739', 'ltv_lte80_fico_a700b719', 'ltv_lte80_fico_a680b699', 'ltv_lte80_fico_lt680', 'ltv_gt80_fico_ge740', 'ltv_gt80_fico_a720b739', 'ltv_gt80_fico_a700b719', 'ltv_gt80_fico_a680b699', 'ltv_gt80_fico_lt680'], str], List[Union[Literal['primary', 'ltv_lte_80', 'ltv_gt_80', 'conforming_30y', 'conforming_30y_na', 'jumbo_30y', 'fha_30y', 'va_30y', 'usda_30y', 'conforming_15y', 'ltv_lte80_fico_ge740', 'ltv_lte80_fico_a720b739', 'ltv_lte80_fico_a700b719', 'ltv_lte80_fico_a680b699', 'ltv_lte80_fico_lt680', 'ltv_gt80_fico_ge740', 'ltv_gt80_fico_a720b739', 'ltv_gt80_fico_a700b719', 'ltv_gt80_fico_a680b699', 'ltv_gt80_fico_lt680'], str]]]", + "description": "The specific index, or index group, to query. Default is the 'primary' group. Multiple items allowed for provider(s): fred.", + "default": "primary", + "optional": true, + "choices": [ + "primary", + "ltv_lte_80", + "ltv_gt_80", + "conforming_30y", + "conforming_30y_na", + "jumbo_30y", + "fha_30y", + "va_30y", + "usda_30y", + "conforming_15y", + "ltv_lte80_fico_ge740", + "ltv_lte80_fico_a720b739", + "ltv_lte80_fico_a700b719", + "ltv_lte80_fico_a680b699", + "ltv_lte80_fico_lt680", + "ltv_gt80_fico_ge740", + "ltv_gt80_fico_a720b739", + "ltv_gt80_fico_a700b719", + "ltv_gt80_fico_a680b699", + "ltv_gt80_fico_lt680" + ] + }, + { + "name": "frequency", + "type": "Literal['a', 'q', 'm', 'w', 'd', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem']", + "description": "Frequency aggregation to convert daily data to lower frequency. None = No change a = Annual q = Quarterly m = Monthly w = Weekly d = Daily wef = Weekly, Ending Friday weth = Weekly, Ending Thursday wew = Weekly, Ending Wednesday wetu = Weekly, Ending Tuesday wem = Weekly, Ending Monday wesu = Weekly, Ending Sunday wesa = Weekly, Ending Saturday bwew = Biweekly, Ending Wednesday bwem = Biweekly, Ending Monday", + "default": null, + "optional": true, + "choices": [ + "a", + "q", + "m", + "w", + "d", + "wef", + "weth", + "wew", + "wetu", + "wem", + "wesu", + "wesa", + "bwew", + "bwem" + ] + }, + { + "name": "aggregation_method", + "type": "Literal['avg', 'sum', 'eop']", + "description": "A key that indicates the aggregation method used for frequency aggregation. This parameter has no affect if the frequency parameter is not set, default is 'avg'. avg = Average sum = Sum eop = End of Period", + "default": "avg", + "optional": true, + "choices": [ + "avg", + "sum", + "eop" + ] + }, + { + "name": "transform", + "type": "Literal['chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log']", + "description": "Transformation type None = No transformation chg = Change ch1 = Change from Year Ago pch = Percent Change pc1 = Percent Change from Year Ago pca = Compounded Annual Rate of Change cch = Continuously Compounded Rate of Change cca = Continuously Compounded Annual Rate of Change log = Natural Log", + "default": null, + "optional": true, + "choices": [ + "chg", + "ch1", + "pch", + "pc1", + "pca", + "cch", + "cca", + "log" + ] + } + ] + }, + "returns": { + "OBBject": [ + { + "name": "results", + "type": "List[MortgageIndices]", + "description": "Serializable results." + }, + { + "name": "provider", + "type": "Optional[Literal['fred']]", + "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": "", + "optional": false, + "choices": null + }, + { + "name": "symbol", + "type": "str", + "description": "Symbol representing the entity requested in the data.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "name", + "type": "str", + "description": "Name of the index.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "rate", + "type": "float", + "description": "Mortgage rate.", + "default": "", + "optional": false, + "choices": null + } + ], + "fred": [] + }, + "model": "MortgageIndices" + }, "/index/price/historical": { "deprecated": { "flag": null, diff --git a/openbb_platform/openbb/package/fixedincome.py b/openbb_platform/openbb/package/fixedincome.py index 456845abcf0..6f5dbb27f60 100644 --- a/openbb_platform/openbb/package/fixedincome.py +++ b/openbb_platform/openbb/package/fixedincome.py @@ -16,6 +16,7 @@ class ROUTER_fixedincome(Container): bond_indices /corporate /government + mortgage_indices /rate sofr /spreads @@ -184,6 +185,132 @@ class ROUTER_fixedincome(Container): command_runner=self._command_runner ) + @exception_handler + @validate + def mortgage_indices( + self, + 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["fred"]], + OpenBBField( + description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fred." + ), + ] = None, + **kwargs + ) -> OBBject: + """Mortgage Indices. + + Parameters + ---------- + 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['fred']] + The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fred. + index : Union[Literal['primary', 'ltv_lte_80', 'ltv_gt_80', 'conforming_30y', 'conforming_30y_na', 'jumbo_30y', 'fha_30y', 'va_30y', 'usda_30y', 'conforming_15y', 'ltv_lte80_fico_ge740', 'ltv_lte80_fico_a720b739', 'ltv_lte80_fico_a700b719', 'ltv_lte80_fico_a680b699', 'ltv_lte80_fico_lt680', 'ltv_gt80_fico_ge740', 'ltv_gt80_fico_a720b739', 'ltv_gt80_fico_a700b719', 'ltv_gt80_fico_a680b699', 'ltv_gt80_fico_lt680'], str] + The specific index, or index group, to query. Default is the 'primary' group. Multiple comma separated items allowed. (provider: fred) + frequency : Optional[Literal['a', 'q', 'm', 'w', 'd', 'wef', 'weth', 'wew', 'wetu', 'wem', 'wesu', 'wesa', 'bwew', 'bwem']] + + Frequency aggregation to convert daily data to lower frequency. + None = No change + a = Annual + q = Quarterly + m = Monthly + w = Weekly + d = Daily + wef = Weekly, Ending Friday + weth = Weekly, Ending Thursday + wew = Weekly, Ending Wednesday + wetu = Weekly, Ending Tuesday + wem = Weekly, Ending Monday + wesu = Weekly, Ending Sunday + wesa = Weekly, Ending Saturday + bwew = Biweekly, Ending Wednesday + bwem = Biweekly, Ending Monday + (provider: fred) + aggregation_method : Literal['avg', 'sum', 'eop'] + + A key that indicates the aggregation method used for frequency aggregation. + This parameter has no affect if the frequency parameter is not set, default is 'avg'. + avg = Average + sum = Sum + eop = End of Period + (provider: fred) + transform : Optional[Literal['chg', 'ch1', 'pch', 'pc1', 'pca', 'cch', 'cca', 'log']] + + Transformation type + None = No transformation + chg = Change + ch1 = Change from Year Ago + pch = Percent Change + pc1 = Percent Change from Year Ago + pca = Compounded Annual Rate of Change + cch = Continuously Compounded Rate of Change + cca = Continuously Compounded Annual Rate of Change + log = Natural Log + (provider: fred) + + Returns + ------- + OBBject + results : List[MortgageIndices] + Serializable results. + provider : Optional[Literal['fred']] + Provider name. + warnings : Optional[List[Warning_]] + List of warnings. + chart : Optional[Chart] + Chart object. + extra : Dict[str, Any] + Extra info. + + MortgageIndices + --------------- + date : date + The date of the data. + symbol : Optional[str] + Symbol representing the entity requested in the data. + name : Optional[str] + Name of the index. + rate : float + Mortgage rate. + + Examples + -------- + >>> from openbb import obb + >>> # The default state for FRED are the primary mortgage indices from Optimal Blue. + >>> obb.fixedincome.mortgage_indices(provider='fred') + >>> # Multiple indices can be requested. + >>> obb.fixedincome.mortgage_indices(index='jumbo_30y,conforming_30y,conforming_15y', provider='fred') + """ # noqa: E501 + + return self._run( + "/fixedincome/mortgage_indices", + **filter_inputs( + provider_choices={ + "provider": self._get_provider( + provider, + "fixedincome.mortgage_indices", + ("fred",), + ) + }, + standard_params={ + "start_date": start_date, + "end_date": end_date, + }, + extra_params=kwargs, + info={"index": {"fred": {"multiple_items_allowed": True}}}, + ) + ) + @property def rate(self): # pylint: disable=import-outside-toplevel diff --git a/openbb_platform/providers/fred/openbb_fred/__init__.py b/openbb_platform/providers/fred/openbb_fred/__init__.py index d68a8d1558e..c55e2d55e16 100644 --- a/openbb_platform/providers/fred/openbb_fred/__init__.py +++ b/openbb_platform/providers/fred/openbb_fred/__init__.py @@ -18,6 +18,7 @@ from openbb_fred.models.hqm import FREDHighQualityMarketCorporateBondFetcher from openbb_fred.models.ice_bofa import FREDICEBofAFetcher from openbb_fred.models.iorb_rates import FREDIORBFetcher from openbb_fred.models.moody import FREDMoodyCorporateBondIndexFetcher +from openbb_fred.models.mortgage_indices import FredMortgageIndicesFetcher from openbb_fred.models.regional import FredRegionalDataFetcher from openbb_fred.models.retail_prices import FredRetailPricesFetcher from openbb_fred.models.search import ( @@ -57,6 +58,7 @@ Research division of the Federal Reserve Bank of St. Louis that has more than "EuropeanCentralBankInterestRates": FREDEuropeanCentralBankInterestRatesFetcher, "ICEBofA": FREDICEBofAFetcher, "MoodyCorporateBondIndex": FREDMoodyCorporateBondIndexFetcher, + "MortgageIndices": FredMortgageIndicesFetcher, "CommercialPaper": FREDCommercialPaperFetcher, "FredSearch": FredSearchFetcher, "FredSeries": FredSeriesFetcher, diff --git a/openbb_platform/providers/fred/openbb_fred/models/mortgage_indices.py b/openbb_platform/providers/fred/openbb_fred/models/mortgage_indices.py new file mode 100644 index 00000000000..68a59dca4fd --- /dev/null +++ b/openbb_platform/providers/fred/openbb_fred/models/mortgage_indices.py @@ -0,0 +1,312 @@ +"""FRED Mortgage Indices Model.""" + +# pylint: disable=unused-argument + +from typing import Any, Dict, List, Literal, Optional, Union +from warnings import warn + +from openbb_core.app.model.abstract.error import OpenBBError +from openbb_core.provider.abstract.annotated_result import AnnotatedResult +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.mortgage_indices import ( + MortgageIndicesData, + MortgageIndicesQueryParams, +) +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_fred.models.series import FredSeriesFetcher +from pandas import Categorical, DataFrame +from pydantic import Field, field_validator + +MORTGAGE_ID_TO_TITLE = { + "OBMMIC30YF": "30-Year Fixed Rate Conforming", + "OBMMIC30YFNA": "30-Year Fixed Rate Conforming Non-Adjusted", + "OBMMIJUMBO30YF": "30-Year Fixed Rate Jumbo", + "OBMMIFHA30YF": "30-Year Fixed Rate FHA", + "OBMMIVA30YF": "30-Year Fixed Rate Veterans Affairs", + "OBMMIUSDA30YF": "30-Year Fixed Rate USDA", + "OBMMIC15YF": "15-Year Fixed Rate Conforming", + "OBMMIC30YFLVLE80FGE740": "30-Year Fixed Rate Conforming LTV <= 80 FICO >= 740", + "OBMMIC30YFLVLE80FB720A739": "30-Year Fixed Rate Conforming LTV <= 80 FICO 720-739", + "OBMMIC30YFLVLE80FB700A719": "30-Year Fixed Rate Conforming LTV <= 80 FICO 700-719", + "OBMMIC30YFLVLE80FB680A699": "30-Year Fixed Rate Conforming LTV <= 80 FICO 680-699", + "OBMMIC30YFLVLE80FLT680": "30-Year Fixed Rate Conforming LTV <= 80 FICO < 680", + "OBMMIC30YFLVGT80FGE740": "30-Year Fixed Rate Conforming LTV > 80 FICO >= 740", + "OBMMIC30YFLVGT80FB720A739": "30-Year Fixed Rate Conforming LTV > 80 FICO 720-739", + "OBMMIC30YFLVGT80FB700A719": "30-Year Fixed Rate Conforming LTV > 80 FICO 700-719", + "OBMMIC30YFLVGT80FB680A699": "30-Year Fixed Rate Conforming LTV > 80 FICO 680-699", + "OBMMIC30YFLVGT80FLT680": "30-Year Fixed Rate Conforming LTV > 80 FICO < 680", +} + +MORTGAGE_GROUPS = { + "primary": [ + "OBMMIC30YF", + "OBMMIC30YFNA", + "OBMMIJUMBO30YF", + "OBMMIFHA30YF", + "OBMMIVA30YF", + "OBMMIUSDA30YF", + "OBMMIC15YF", + ], + "ltv_lte_80": [ + "OBMMIC30YFLVLE80FGE740", + "OBMMIC30YFLVLE80FB720A739", + "OBMMIC30YFLVLE80FB700A719", + "OBMMIC30YFLVLE80FB680A699", + "OBMMIC30YFLVLE80FLT680", + ], + "ltv_gt_80": [ + "OBMMIC30YFLVGT80FGE740", + "OBMMIC30YFLVGT80FB720A739", + "OBMMIC30YFLVGT80FB700A719", + "OBMMIC30YFLVGT80FB680A699", + "OBMMIC30YFLVGT80FLT680", + ], +} + +MORTGAGE_CHOICES_TO_ID = { + "primary": ",".join(MORTGAGE_GROUPS["primary"]), + "ltv_lte_80": ",".join(MORTGAGE_GROUPS["ltv_lte_80"]), + "ltv_gt_80": ",".join(MORTGAGE_GROUPS["ltv_gt_80"]), + "conforming_30y": "OBMMIC30YF", + "conforming_30y_na": "OBMMIC30YFNA", + "jumbo_30y": "OBMMIJUMBO30YF", + "fha_30y": "OBMMIFHA30YF", + "va_30y": "OBMMIVA30YF", + "usda_30y": "OBMMIUSDA30YF", + "conforming_15y": "OBMMIC15YF", + "ltv_lte80_fico_ge740": "OBMMIC30YFLVLE80FGE740", + "ltv_lte80_fico_a720b739": "OBMMIC30YFLVLE80FB720A739", + "ltv_lte80_fico_a700b719": "OBMMIC30YFLVLE80FB700A719", + "ltv_lte80_fico_a680b699": "OBMMIC30YFLVLE80FB680A699", + "ltv_lte80_fico_lt680": "OBMMIC30YFLVLE80FLT680", + "ltv_gt80_fico_ge740": "OBMMIC30YFLVGT80FGE740", + "ltv_gt80_fico_a720b739": "OBMMIC30YFLVGT80FB720A739", + "ltv_gt80_fico_a700b719": "OBMMIC30YFLVGT80FB700A719", + "ltv_gt80_fico_a680b699": "OBMMIC30YFLVGT80FB680A699", + "ltv_gt80_fico_lt680": "OBMMIC30YFLVGT80FLT680", +} + +MortgageChoices = Literal[ + "primary", + "ltv_lte_80", + "ltv_gt_80", + "conforming_30y", + "conforming_30y_na", + "jumbo_30y", + "fha_30y", + "va_30y", + "usda_30y", + "conforming_15y", + "ltv_lte80_fico_ge740", + "ltv_lte80_fico_a720b739", + "ltv_lte80_fico_a700b719", |