From fc15b7ad411aecab6842fbd1511455867f018f32 Mon Sep 17 00:00:00 2001 From: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:00:17 +0200 Subject: [PATCH] Fix econometrics bugs. Make tests pass. Lint. --- .../integration/test_econometrics_api.py | 8 +-- .../econometrics_router.py | 67 ++++++++++--------- .../economy/integration/test_economy_api.py | 56 +++++++++++++--- .../integration/test_economy_python.py | 47 ++++++++++--- .../openbb/package/econometrics.py | 18 +++-- openbb_platform/openbb/package/qa.py | 38 ++++++++--- openbb_platform/openbb/package/ta.py | 6 +- .../oecd/tests/test_oecd_fetchers.py | 3 +- 8 files changed, 167 insertions(+), 76 deletions(-) diff --git a/openbb_platform/extensions/econometrics/integration/test_econometrics_api.py b/openbb_platform/extensions/econometrics/integration/test_econometrics_api.py index efde2e54bea..265636f389e 100644 --- a/openbb_platform/extensions/econometrics/integration/test_econometrics_api.py +++ b/openbb_platform/extensions/econometrics/integration/test_econometrics_api.py @@ -86,11 +86,11 @@ def test_econometrics_corr(params, data_type): "params, data_type", [ ( - {"data": "", "y_column": "close", "x_columns": ["date"]}, + {"data": "", "y_column": "close", "x_columns": ["high"]}, "stocks", ), ( - {"data": "", "y_column": "close", "x_columns": ["date"]}, + {"data": "", "y_column": "close", "x_columns": ["high"]}, "crypto", ), ], @@ -108,7 +108,7 @@ def test_econometrics_ols_summary(params, data_type): query_str = get_querystring(params, []) url = f"http://0.0.0.0:8000/api/v1/econometrics/ols_summary?{query_str}" - result = requests.post(url, headers=get_headers(), timeout=10, data=body) + result = requests.post(url, headers=get_headers(), timeout=20, data=body) assert isinstance(result, requests.Response) assert result.status_code == 200 @@ -257,7 +257,7 @@ def test_econometrics_granger(params, data_type): @pytest.mark.parametrize( "params, data_type", - [({"data": "", "column": "", "regression": ""}, "stocks")], + [({"data": "", "column": "high", "regression": "c"}, "stocks")], ) @pytest.mark.integration def test_econometrics_unitroot(params, data_type): diff --git a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py index 867b2bf8c0e..3111fe396be 100644 --- a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py +++ b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py @@ -111,6 +111,12 @@ def ols_summary( X = sm.add_constant(get_target_columns(basemodel_to_df(data), x_columns)) y = get_target_column(basemodel_to_df(data), y_column) + try: + X = X.astype(float) + y = y.astype(float) + except ValueError as exc: + raise ValueError("All columns must be numeric") from exc + results = sm.OLS(y, X).fit() results_summary = results.summary() results = {} @@ -201,10 +207,17 @@ def bgot( X = sm.add_constant(get_target_columns(basemodel_to_df(data), x_columns)) y = get_target_column(basemodel_to_df(data), y_column) model = sm.OLS(y, X) - lm_stat, p_value, f_stat, fp_value = acorr_breusch_godfrey(model, nlags=lags) - return OBBject( - results=Data(lm_stat=lm_stat, p_value=p_value, f_stat=f_stat, fp_value=fp_value) - ) + results = model.fit() + lm_stat, p_value, f_stat, fp_value = acorr_breusch_godfrey(results, nlags=lags) + + results = { + "lm_stat": lm_stat, + "p_value": p_value, + "f_stat": f_stat, + "fp_value": fp_value, + } + + return OBBject(results=results) @router.command(methods=["POST"]) @@ -230,7 +243,7 @@ def coint( """ pairs = list(combinations(columns, 2)) dataset = get_target_columns(basemodel_to_df(data), columns) - result = [] + result = {} for x, y in pairs: ( c, @@ -240,16 +253,13 @@ def coint( adfstat, pvalue, ) = get_engle_granger_two_step_cointegration_test(dataset[x], dataset[y]) - result.append( - Data( - pair=f"{x}/{y}", - c=c, - gamma=gamma, - alpha=alpha, - adfstat=adfstat, - pvalue=pvalue, - ) - ) + result[f"{x}/{y}"] = { + "c": c, + "gamma": gamma, + "alpha": alpha, + "adfstat": adfstat, + "pvalue": pvalue, + } return OBBject(results=result) @@ -292,15 +302,9 @@ def granger( granger[lag][0][test] = (pars[0], pars[1], "-", pars[2]) df = pd.DataFrame(granger[lag][0], index=["F-test", "P-value", "Count", "Lags"]).T + results = df.to_dict() - return OBBject( - results=[ - Data(**d) - for d in df.reset_index() - .rename(columns={"index": "test"}) - .to_dict(orient="records") - ] - ) + return OBBject(results=results) @router.command(methods=["POST"]) @@ -328,15 +332,14 @@ def unitroot( """ dataset = get_target_column(basemodel_to_df(data), column) adfstat, pvalue, usedlag, nobs, _, icbest = adfuller(dataset, regression=regression) - return OBBject( - results=Data( - adfstat=adfstat, - pvalue=pvalue, - usedlag=usedlag, - nobs=nobs, - icbest=icbest, - ) - ) + results = { + "adfstat": adfstat, + "pvalue": pvalue, + "usedlag": usedlag, + "nobs": nobs, + "icbest": icbest, + } + return OBBject(results=results) @router.command(methods=["POST"], include_in_schema=False) diff --git a/openbb_platform/extensions/economy/integration/test_economy_api.py b/openbb_platform/extensions/economy/integration/test_economy_api.py index f7218bb5f9e..8a3398d9a87 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_api.py +++ b/openbb_platform/extensions/economy/integration/test_economy_api.py @@ -379,15 +379,25 @@ def test_economy_fred_index(params, headers): assert isinstance(result, requests.Response) assert result.status_code == 200 + @pytest.mark.parametrize( "params", - [({'units': 'usd', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), -({'country': 'united_states', 'provider': 'oecd', 'units': 'usd', 'start_date': '2023-01-01', 'end_date': '2023-06-06'})], + [ + ({"units": "usd", "start_date": "2023-01-01", "end_date": "2023-06-06"}), + ( + { + "country": "united_states", + "provider": "oecd", + "units": "usd", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + } + ), + ], ) @pytest.mark.integration def test_economy_gdpnom(params, headers): params = {p: v for p, v in params.items() if v} - query_str = get_querystring(params, []) url = f"http://0.0.0.0:8000/api/v1/economy/gdpnom?{query_str}" @@ -395,15 +405,25 @@ def test_economy_gdpnom(params, headers): assert isinstance(result, requests.Response) assert result.status_code == 200 + @pytest.mark.parametrize( "params", - [({'units': 'yoy', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), -({'country': 'united_states', 'provider': 'oecd', 'units': 'yoy', 'start_date': '2023-01-01', 'end_date': '2023-06-06'})], + [ + ({"units": "yoy", "start_date": "2023-01-01", "end_date": "2023-06-06"}), + ( + { + "country": "united_states", + "provider": "oecd", + "units": "yoy", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + } + ), + ], ) @pytest.mark.integration def test_economy_gdpreal(params, headers): params = {p: v for p, v in params.items() if v} - query_str = get_querystring(params, []) url = f"http://0.0.0.0:8000/api/v1/economy/gdpreal?{query_str}" @@ -411,15 +431,33 @@ def test_economy_gdpreal(params, headers): assert isinstance(result, requests.Response) assert result.status_code == 200 + @pytest.mark.parametrize( "params", - [({'period': 'annual', 'start_date': '2023-01-01', 'end_date': '2023-06-06', 'type': 'real'}), -({'country': 'united_states', 'provider': 'oecd', 'period': 'annual', 'start_date': '2023-01-01', 'end_date': '2023-06-06', 'type': 'real'})], + [ + ( + { + "period": "annual", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + "type": "real", + } + ), + ( + { + "country": "united_states", + "provider": "oecd", + "period": "annual", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + "type": "real", + } + ), + ], ) @pytest.mark.integration def test_economy_gdpforecast(params, headers): params = {p: v for p, v in params.items() if v} - query_str = get_querystring(params, []) url = f"http://0.0.0.0:8000/api/v1/economy/gdpforecast?{query_str}" diff --git a/openbb_platform/extensions/economy/integration/test_economy_python.py b/openbb_platform/extensions/economy/integration/test_economy_python.py index 4c117bb5617..ae543fba596 100644 --- a/openbb_platform/extensions/economy/integration/test_economy_python.py +++ b/openbb_platform/extensions/economy/integration/test_economy_python.py @@ -366,9 +366,16 @@ def test_economy_fred_index(params): @pytest.mark.parametrize( "params", [ - ({'units': 'usd', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), -({'country': 'united_states', 'provider': 'oecd', 'units': 'usd', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), - + ({"units": "usd", "start_date": "2023-01-01", "end_date": "2023-06-06"}), + ( + { + "country": "united_states", + "provider": "oecd", + "units": "usd", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + } + ), ], ) @pytest.mark.integration @@ -384,9 +391,16 @@ def test_economy_gdpnom(params, obb): @pytest.mark.parametrize( "params", [ - ({'units': 'yoy', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), -({'country': 'united_states', 'provider': 'oecd', 'units': 'yoy', 'start_date': '2023-01-01', 'end_date': '2023-06-06'}), - + ({"units": "yoy", "start_date": "2023-01-01", "end_date": "2023-06-06"}), + ( + { + "country": "united_states", + "provider": "oecd", + "units": "yoy", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + } + ), ], ) @pytest.mark.integration @@ -402,9 +416,24 @@ def test_economy_gdpreal(params, obb): @pytest.mark.parametrize( "params", [ - ({'period': 'annual', 'start_date': '2023-01-01', 'end_date': '2023-06-06', 'type': 'real'}), -({'country': 'united_states', 'provider': 'oecd', 'period': 'annual', 'start_date': '2023-01-01', 'end_date': '2023-06-06', 'type': 'real'}), - + ( + { + "period": "annual", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + "type": "real", + } + ), + ( + { + "country": "united_states", + "provider": "oecd", + "period": "annual", + "start_date": "2023-01-01", + "end_date": "2023-06-06", + "type": "real", + } + ), ], ) @pytest.mark.integration diff --git a/openbb_platform/openbb/package/econometrics.py b/openbb_platform/openbb/package/econometrics.py index ea0c1f3846c..c7bfcd960ba 100644 --- a/openbb_platform/openbb/package/econometrics.py +++ b/openbb_platform/openbb/package/econometrics.py @@ -53,6 +53,7 @@ class ROUTER_econometrics(Container): List of columns to use as exogenous variables. lags: PositiveInt Number of lags to use in the test. + Returns ------- OBBject[Data] @@ -85,6 +86,7 @@ class ROUTER_econometrics(Container): Data columns to check cointegration maxlag: PositiveInt Number of lags to use in the test. + Returns ------- OBBject[Data] @@ -132,7 +134,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Perform Durbin-Watson test for autocorrelation + """Perform Durbin-Watson test for autocorrelation. Parameters ---------- @@ -180,6 +182,7 @@ class ROUTER_econometrics(Container): Columns to use as exogenous variables. lag: PositiveInt Number of lags to use in the test. + Returns ------- OBBject[Data] @@ -275,7 +278,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Perform a Between estimator regression on panel data + """Perform a Between estimator regression on panel data. Parameters ---------- @@ -310,7 +313,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Perform a first-difference estimate for panel data + """Perform a first-difference estimate for panel data. Parameters ---------- @@ -345,7 +348,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Fama-MacBeth estimator for panel data + """Fama-MacBeth estimator for panel data. Parameters ---------- @@ -380,7 +383,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """One- and two-way fixed effects estimator for panel data + """One- and two-way fixed effects estimator for panel data. Parameters ---------- @@ -415,7 +418,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Perform a Pooled coefficvient estimator regression on panel data + """Perform a Pooled coefficvient estimator regression on panel data. Parameters ---------- @@ -450,7 +453,7 @@ class ROUTER_econometrics(Container): y_column: str, x_columns: List[str], ) -> OBBject[Dict]: - """Perform One-way Random Effects model for panel data + """Perform One-way Random Effects model for panel data. Parameters ---------- @@ -496,6 +499,7 @@ class ROUTER_econometrics(Container): regression: str Regression type to use in the test. Either "c" for constant only, "ct" for constant and trend, or "ctt" for constant, trend, and trend-squared. + Returns ------- OBBject[Data] diff --git a/openbb_platform/openbb/package/qa.py b/openbb_platform/openbb/package/qa.py index d582ebd779b..d3401a9fcc3 100644 --- a/openbb_platform/openbb/package/qa.py +++ b/openbb_platform/openbb/package/qa.py @@ -40,7 +40,7 @@ class ROUTER_qa(Container): def capm( self, data: Union[List[Data], pandas.DataFrame], target: str ) -> OBBject[CAPMModel]: - """Capital Asset Pricing Model.""" # noqa: E501 + """Get Capital Asset Pricing Model.""" # noqa: E501 inputs = filter_inputs( data=data, @@ -59,7 +59,7 @@ class ROUTER_qa(Container): target: str, window: Annotated[int, Gt(gt=0)], ) -> OBBject[List[Data]]: - """Kurtosis. + """Get the Kurtosis. Parameters ---------- @@ -91,8 +91,7 @@ class ROUTER_qa(Container): def normality( self, data: Union[List[Data], pandas.DataFrame], target: str ) -> OBBject[NormalityModel]: - """ - Normality Statistics. + """Get Normality Statistics. - **Kurtosis**: whether the kurtosis of a sample differs from the normal distribution. - **Skewness**: whether the skewness of a sample differs from the normal distribution. @@ -131,7 +130,7 @@ class ROUTER_qa(Container): threshold_start: float = 0.0, threshold_end: float = 1.5, ) -> OBBject[List[OmegaModel]]: - """Omega Ratio. + """Calculate the Omega Ratio. Parameters ---------- @@ -170,7 +169,24 @@ class ROUTER_qa(Container): window: Annotated[int, Gt(gt=0)], quantile_pct: Annotated[float, Ge(ge=0)] = 0.5, ) -> OBBject[List[Data]]: - """Quantile.""" # noqa: E501 + """Get Quantile. + + Parameters + ---------- + data : List[Data] + Time series data. + target : str + Target column name. + window : PositiveInt + Window size. + quantile_pct : NonNegativeFloat, optional + Quantile percentage, by default 0.5 + + Returns + ------- + OBBject[List[Data]] + Quantile. + """ # noqa: E501 inputs = filter_inputs( data=data, @@ -192,7 +208,7 @@ class ROUTER_qa(Container): rfr: float = 0.0, window: Annotated[int, Gt(gt=0)] = 252, ) -> OBBject[List[Data]]: - """Sharpe Ratio. + """Get Sharpe Ratio. Parameters ---------- @@ -230,7 +246,7 @@ class ROUTER_qa(Container): target: str, window: Annotated[int, Gt(gt=0)], ) -> OBBject[List[Data]]: - """Skewness. + """Get Skewness. Parameters ---------- @@ -267,7 +283,7 @@ class ROUTER_qa(Container): window: Annotated[int, Gt(gt=0)] = 252, adjusted: bool = False, ) -> OBBject[List[Data]]: - """Sortino Ratio. + """Get Sortino Ratio. For method & terminology see: http://www.redrockcapital.com/Sortino__A__Sharper__Ratio_Red_Rock_Capital.pdf @@ -307,7 +323,7 @@ class ROUTER_qa(Container): def summary( self, data: Union[List[Data], pandas.DataFrame], target: str ) -> OBBject[SummaryModel]: - """Summary. + """Get Summary Statistics. Parameters ---------- @@ -340,7 +356,7 @@ class ROUTER_qa(Container): fuller_reg: Literal["c", "ct", "ctt", "nc"] = "c", kpss_reg: Literal["c", "ct"] = "c", ) -> OBBject[UnitRootModel]: - """Unit Root Test. + """Get Unit Root Test. Augmented Dickey-Fuller test for unit root. Kwiatkowski-Phillips-Schmidt-Shin test for unit root. diff --git a/openbb_platform/openbb/package/ta.py b/openbb_platform/openbb/package/ta.py index 152284e210f..f008dd1626b 100644 --- a/openbb_platform/openbb/package/ta.py +++ b/openbb_platform/openbb/package/ta.py @@ -612,8 +612,8 @@ class ROUTER_ta(Container): data: Union[List[Data], pandas.DataFrame], index: str = "date", target: str = "close", - show_all: bool = False, - asint: bool = False, + show_all: bool = True, + asint: bool = True, offset: int = 0, ) -> OBBject[List[Data]]: """ @@ -630,7 +630,7 @@ class ROUTER_ta(Container): show_all : bool, optional Show 1 - 13. If set to False, show 6 - 9 asint : bool, optional - If True, fill NAs with 0 and change type to int, by default False + If True, fill NAs with 0 and change type to int, by default True. offset : int, optional How many periods to offset the result diff --git a/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py b/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py index b1bfed598d1..08ba368ff99 100644 --- a/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py +++ b/openbb_platform/providers/oecd/tests/test_oecd_fetchers.py @@ -1,9 +1,10 @@ import datetime + import pytest from openbb_core.app.service.user_service import UserService +from openbb_oecd.models.gdpforecast import OECDGDPForecastFetcher from openbb_oecd.models.gdpnom import OECDGDPNomFetcher from openbb_oecd.models.gdpreal import OECDGDPRealFetcher -from openbb_oecd.models.gdpforecast import OECDGDPForecastFetcher test_credentials = UserService().default_user_settings.credentials.dict()