mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Refactoring econometrics for SDK usability (#3379)
* Econometrics enhancements * Docsring * norm show chart when true * isort + lint * Make coint sdk friendly * mypy? * Why you miss this locally pylint? * Clean up granger command * Tests * #3323 * Fix up dwat function * Fix rounding error in test--hopefully * Update bgod and bpag * testing mypy * small commit to help rebase? * Update Panel OLS stuff. Need some more examples and to fix mypy * add docstring example * update controller complete and duplicate printing Co-authored-by: Jeroen Bouma <jer.bouma@gmail.com>
This commit is contained in:
14
.pre-commit-config.yaml
vendored
14
.pre-commit-config.yaml
vendored
@@ -42,12 +42,16 @@ repos:
|
||||
"--quiet-level=2",
|
||||
"--skip=./tests,.git,*.css,*.csv,*.html,*.ini,*.ipynb,*.js,*.json,*.lock,*.scss,*.txt,*.yaml,build/pyinstaller/*,./website/config.toml",
|
||||
]
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: "v0.982"
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: ["--ignore-missing-imports", 'openbb_terminal']
|
||||
additional_dependencies: [types-all]
|
||||
- id: mypy
|
||||
name: mypy
|
||||
description: ''
|
||||
entry: mypy
|
||||
language: python
|
||||
'types_or': [python, pyi]
|
||||
args: ["--ignore-missing-imports", "--scripts-are-modules"]
|
||||
require_serial: true
|
||||
- repo: https://github.com/kynan/nbstripout
|
||||
rev: 0.6.1
|
||||
hooks:
|
||||
|
||||
@@ -5,40 +5,42 @@ __docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
from itertools import chain
|
||||
import os
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any
|
||||
from typing import Any, Dict, List
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
|
||||
import openbb_terminal.econometrics.regression_model
|
||||
import openbb_terminal.econometrics.regression_view
|
||||
from openbb_terminal.core.config.paths import USER_CUSTOM_IMPORTS_DIRECTORY
|
||||
from openbb_terminal import feature_flags as obbff
|
||||
from openbb_terminal.core.config.paths import USER_EXPORTS_DIRECTORY
|
||||
from openbb_terminal.common import common_model
|
||||
from openbb_terminal.core.config.paths import (
|
||||
USER_CUSTOM_IMPORTS_DIRECTORY,
|
||||
USER_EXPORTS_DIRECTORY,
|
||||
)
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.helper_funcs import (
|
||||
check_positive,
|
||||
check_positive_float,
|
||||
NO_EXPORT,
|
||||
EXPORT_ONLY_FIGURES_ALLOWED,
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
EXPORT_BOTH_RAW_DATA_AND_FIGURES,
|
||||
export_data,
|
||||
from openbb_terminal.econometrics import (
|
||||
econometrics_model,
|
||||
econometrics_view,
|
||||
regression_model,
|
||||
regression_view,
|
||||
)
|
||||
from openbb_terminal.helper_funcs import (
|
||||
print_rich_table,
|
||||
EXPORT_BOTH_RAW_DATA_AND_FIGURES,
|
||||
EXPORT_ONLY_FIGURES_ALLOWED,
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
NO_EXPORT,
|
||||
check_list_values,
|
||||
check_positive,
|
||||
check_positive_float,
|
||||
export_data,
|
||||
print_rich_table,
|
||||
)
|
||||
from openbb_terminal.menu import session
|
||||
from openbb_terminal.parent_classes import BaseController
|
||||
from openbb_terminal.rich_config import console, MenuText
|
||||
from openbb_terminal.econometrics import econometrics_model, econometrics_view
|
||||
from openbb_terminal.common import common_model
|
||||
from openbb_terminal.rich_config import MenuText, console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -88,6 +90,19 @@ class EconometricsController(BaseController):
|
||||
"pie",
|
||||
"hexbin",
|
||||
]
|
||||
|
||||
PANEL_CHOICES = [
|
||||
"pols",
|
||||
"re",
|
||||
"bols",
|
||||
"fe",
|
||||
"fdols",
|
||||
"POLS",
|
||||
"RE",
|
||||
"BOLS",
|
||||
"FE",
|
||||
"FDOLS",
|
||||
]
|
||||
PATH = "/econometrics/"
|
||||
|
||||
loaded_dataset_cols = "\n"
|
||||
@@ -170,7 +185,7 @@ class EconometricsController(BaseController):
|
||||
|
||||
choices["support"] = self.SUPPORT_CHOICES
|
||||
choices["about"] = self.ABOUT_CHOICES
|
||||
|
||||
choices["panel"]["-r"] = {c: {} for c in self.PANEL_CHOICES}
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def update_runtime_choices(self):
|
||||
@@ -262,13 +277,11 @@ class EconometricsController(BaseController):
|
||||
mt.add_cmd("bpag", self.files and self.regression["OLS"]["model"])
|
||||
|
||||
console.print(text=mt.menu_text, menu="Econometrics")
|
||||
console.print()
|
||||
|
||||
def custom_reset(self):
|
||||
"""Class specific component of reset command"""
|
||||
if self.files:
|
||||
load_files = [f"load -f {file}" for file in self.files]
|
||||
return ["econometrics"] + load_files
|
||||
return []
|
||||
return ["econometrics"]
|
||||
|
||||
def update_loaded(self):
|
||||
self.list_dataset_cols = []
|
||||
@@ -355,7 +368,7 @@ class EconometricsController(BaseController):
|
||||
|
||||
if not file:
|
||||
console.print(
|
||||
"[red]The file/dataset selected does not exist.[/red]\n"
|
||||
"[red]The file/dataset selected does not exist.[/red]"
|
||||
)
|
||||
return
|
||||
else:
|
||||
@@ -372,7 +385,7 @@ class EconometricsController(BaseController):
|
||||
# check if this dataset has been added already
|
||||
if alias in self.files:
|
||||
console.print(
|
||||
"[red]The file/dataset selected has already been loaded.[/red]\n"
|
||||
"[red]The file/dataset selected has already been loaded.[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -388,8 +401,6 @@ class EconometricsController(BaseController):
|
||||
|
||||
self.update_loaded()
|
||||
|
||||
console.print()
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_export(self, other_args: List[str]):
|
||||
"""Process export command"""
|
||||
@@ -1189,6 +1200,13 @@ class EconometricsController(BaseController):
|
||||
),
|
||||
required="-h" not in other_args,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-output",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Hide the output of the regression",
|
||||
dest="no_output",
|
||||
)
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-d")
|
||||
@@ -1204,15 +1222,25 @@ class EconometricsController(BaseController):
|
||||
)
|
||||
elif ns_parser.dependent in self.choices["regressions"]:
|
||||
(
|
||||
self.regression["OLS"]["data"],
|
||||
self.regression["OLS"]["dependent"],
|
||||
self.regression["OLS"]["independent"],
|
||||
self.regression["OLS"]["model"],
|
||||
) = openbb_terminal.econometrics.regression_model.get_ols(
|
||||
regression_df,
|
||||
dependent_variable,
|
||||
independent_variables,
|
||||
) = regression_model.get_regression_data(
|
||||
[ns_parser.dependent] + ns_parser.independent,
|
||||
self.datasets,
|
||||
export=ns_parser.export,
|
||||
"OLS",
|
||||
)
|
||||
self.regression["OLS"]["data"] = regression_df
|
||||
self.regression["OLS"]["dependent"] = dependent_variable
|
||||
self.regression["OLS"]["independent"] = independent_variables
|
||||
model = regression_model.get_ols(
|
||||
regression_df[dependent_variable],
|
||||
regression_df[independent_variables],
|
||||
)
|
||||
self.regression["OLS"]["model"] = model
|
||||
if not ns_parser.no_output:
|
||||
console.print(model.summary())
|
||||
|
||||
else:
|
||||
console.print(
|
||||
f"{ns_parser.dependent} not in {','.join(self.choices['regressions'])}\n"
|
||||
@@ -1273,7 +1301,7 @@ class EconometricsController(BaseController):
|
||||
else:
|
||||
return console.print(f"Can not find {dataset}. Did you load the data?")
|
||||
|
||||
return econometrics_view.display_norm(
|
||||
econometrics_view.display_norm(
|
||||
data, dataset, column, ns_parser.plot, ns_parser.export
|
||||
)
|
||||
|
||||
@@ -1386,18 +1414,7 @@ class EconometricsController(BaseController):
|
||||
"-r",
|
||||
"--regression",
|
||||
type=str,
|
||||
choices=[
|
||||
"pols",
|
||||
"re",
|
||||
"bols",
|
||||
"fe",
|
||||
"fdols",
|
||||
"POLS",
|
||||
"RE",
|
||||
"BOLS",
|
||||
"FE",
|
||||
"FDOLS",
|
||||
],
|
||||
choices=self.PANEL_CHOICES,
|
||||
dest="type",
|
||||
help="The type of regression you wish to perform. This can be either pols (Pooled OLS), "
|
||||
"re (Random Effects), bols (Between OLS), fe (Fixed Effects) or fdols (First Difference OLS)",
|
||||
@@ -1459,7 +1476,7 @@ class EconometricsController(BaseController):
|
||||
)
|
||||
|
||||
# Ensure that OLS is always ran to be able to perform tests
|
||||
regression_types = ["OLS", ns_parser.type.upper()]
|
||||
regression_types = [ns_parser.type.upper(), "OLS"]
|
||||
|
||||
for regression in regression_types:
|
||||
regression_name = regression
|
||||
@@ -1470,18 +1487,29 @@ class EconometricsController(BaseController):
|
||||
regression_name = regression_name + "_IE"
|
||||
|
||||
(
|
||||
self.regression[regression_name]["data"],
|
||||
self.regression[regression_name]["dependent"],
|
||||
self.regression[regression_name]["independent"],
|
||||
self.regression[regression_name]["model"],
|
||||
) = openbb_terminal.econometrics.regression_view.display_panel(
|
||||
regression_df,
|
||||
dependent_variable,
|
||||
independent_variables,
|
||||
) = regression_model.get_regression_data(
|
||||
[ns_parser.dependent] + ns_parser.independent,
|
||||
self.datasets,
|
||||
regression_vars,
|
||||
regression,
|
||||
)
|
||||
self.regression[regression]["data"] = regression_df
|
||||
self.regression[regression]["dependent"] = dependent_variable
|
||||
self.regression[regression][
|
||||
"independent"
|
||||
] = independent_variables
|
||||
self.regression[regression_name][
|
||||
"model"
|
||||
] = regression_view.display_panel(
|
||||
regression_df[dependent_variable],
|
||||
regression_df[independent_variables],
|
||||
regression,
|
||||
ns_parser.entity_effects,
|
||||
ns_parser.time_effects,
|
||||
ns_parser.export,
|
||||
)
|
||||
console.print()
|
||||
else:
|
||||
console.print(
|
||||
f"{ns_parser.dependent} not in {','.join(self.choices['regressions'])}\n"
|
||||
@@ -1501,9 +1529,7 @@ class EconometricsController(BaseController):
|
||||
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if ns_parser:
|
||||
openbb_terminal.econometrics.regression_model.get_comparison(
|
||||
self.regression, ns_parser.export
|
||||
)
|
||||
regression_model.get_comparison(self.regression, ns_parser.export)
|
||||
console.print()
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@@ -1538,9 +1564,9 @@ class EconometricsController(BaseController):
|
||||
dependent_variable = self.regression["OLS"]["data"][
|
||||
self.regression["OLS"]["dependent"]
|
||||
]
|
||||
openbb_terminal.econometrics.regression_view.display_dwat(
|
||||
regression_view.display_dwat(
|
||||
self.regression["OLS"]["model"],
|
||||
dependent_variable,
|
||||
self.regression["OLS"]["model"].resid,
|
||||
ns_parser.plot,
|
||||
ns_parser.export,
|
||||
)
|
||||
@@ -1578,7 +1604,7 @@ class EconometricsController(BaseController):
|
||||
"Perform an OLS regression before estimating the Breusch-Godfrey statistic.\n"
|
||||
)
|
||||
else:
|
||||
openbb_terminal.econometrics.regression_view.display_bgod(
|
||||
regression_view.display_bgod(
|
||||
self.regression["OLS"]["model"], ns_parser.lags, ns_parser.export
|
||||
)
|
||||
|
||||
@@ -1590,7 +1616,7 @@ class EconometricsController(BaseController):
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="bpag",
|
||||
description=(
|
||||
"Show Breusch-Pagan heteroscedasticity test results."
|
||||
"Show Breusch-Pagan heteroscedasticity test results. "
|
||||
"Needs OLS to be run in advance with independent and dependent variables"
|
||||
),
|
||||
)
|
||||
@@ -1605,7 +1631,7 @@ class EconometricsController(BaseController):
|
||||
"Perform an OLS regression before estimating the Breusch-Pagan statistic.\n"
|
||||
)
|
||||
else:
|
||||
openbb_terminal.econometrics.regression_view.display_bpag(
|
||||
regression_view.display_bpag(
|
||||
self.regression["OLS"]["model"], ns_parser.export
|
||||
)
|
||||
|
||||
@@ -1626,6 +1652,7 @@ class EconometricsController(BaseController):
|
||||
"by the second time series.",
|
||||
type=str,
|
||||
dest="ts",
|
||||
metavar="Available time series",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
@@ -1708,24 +1735,24 @@ class EconometricsController(BaseController):
|
||||
if ns_parser:
|
||||
|
||||
if ns_parser.ts:
|
||||
|
||||
# We are going to pass through a variable number of series, so datasets will be a list of series
|
||||
if len(ns_parser.ts) > 1:
|
||||
datasets = {}
|
||||
for stock in ns_parser.ts:
|
||||
if "." not in stock:
|
||||
datasets = []
|
||||
for series in ns_parser.ts:
|
||||
if "." not in series:
|
||||
console.print(
|
||||
"[red]Invalid time series format. Should be dataset.column, "
|
||||
"e.g. historical.open[/red]\n"
|
||||
)
|
||||
else:
|
||||
dataset, column = stock.split(".")
|
||||
datasets[stock] = self.datasets[dataset][column]
|
||||
dataset, column = series.split(".")
|
||||
datasets.append(self.datasets[dataset][column])
|
||||
|
||||
econometrics_view.display_cointegration_test(
|
||||
datasets,
|
||||
ns_parser.significant,
|
||||
ns_parser.plot,
|
||||
ns_parser.export,
|
||||
*datasets,
|
||||
significant=ns_parser.significant,
|
||||
plot=ns_parser.plot,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from typing import Dict
|
||||
|
||||
import pandas as pd
|
||||
|
||||
|
||||
|
||||
@@ -5,14 +5,16 @@ __docformat__ = "numpy"
|
||||
|
||||
import logging
|
||||
import warnings
|
||||
from typing import Dict, Union, Any, Optional
|
||||
from itertools import combinations
|
||||
from typing import Any, Dict, Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from scipy import stats
|
||||
import statsmodels.api as sm
|
||||
from statsmodels.tsa.stattools import adfuller, kpss, grangercausalitytests
|
||||
from scipy import stats
|
||||
from statsmodels.tsa.stattools import adfuller, grangercausalitytests, kpss
|
||||
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -205,7 +207,7 @@ def get_root(
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_granger_causality(dependent_series, independent_series, lags):
|
||||
def get_granger_causality(dependent_series, independent_series, lags=3):
|
||||
"""Calculate granger tests
|
||||
|
||||
Parameters
|
||||
@@ -221,7 +223,82 @@ def get_granger_causality(dependent_series, independent_series, lags):
|
||||
|
||||
granger = grangercausalitytests(granger_set, [lags], verbose=False)
|
||||
|
||||
return granger
|
||||
for test in granger[lags][0]:
|
||||
# As ssr_chi2test and lrtest have one less value in the tuple, we fill
|
||||
# this value with a '-' to allow the conversion to a DataFrame
|
||||
if len(granger[lags][0][test]) != 4:
|
||||
pars = granger[lags][0][test]
|
||||
granger[lags][0][test] = (pars[0], pars[1], "-", pars[2])
|
||||
|
||||
granger_df = pd.DataFrame(
|
||||
granger[lags][0], index=["F-test", "P-value", "Count", "Lags"]
|
||||
).T
|
||||
|
||||
return granger_df
|
||||
|
||||
|
||||
# TODO: Maybe make a new function to return z instead of having this flag.
|
||||
# TODO: Allow for numpy arrays as well
|
||||
def get_coint_df(
|
||||
*datasets: pd.Series, return_z: bool = False
|
||||
) -> Union[pd.DataFrame, Dict]:
|
||||
"""Calculate cointegration tests between variable number of input series
|
||||
|
||||
Parameters
|
||||
----------
|
||||
datasets : pd.Series
|
||||
Input series to test cointegration for
|
||||
return_z : bool
|
||||
Flag to return the z data to plot
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[pd.DataFrame,Dict]
|
||||
Dataframe with results of cointegration tests or a Dict of the z results
|
||||
"""
|
||||
result: Dict[str, list] = {}
|
||||
z_values: Dict[str, pd.Series] = {}
|
||||
|
||||
# The *datasets lets us pass in a variable number of arguments
|
||||
# Here we are getting all possible combinations of unique inputs
|
||||
|
||||
pairs = list(combinations(datasets, 2))
|
||||
for x, y in pairs:
|
||||
if sum(y.isnull()) > 0:
|
||||
console.print(
|
||||
f"The Series {y} has nan-values. Please consider dropping or filling these "
|
||||
f"values with 'clean'."
|
||||
)
|
||||
elif sum(x.isnull()) > 0:
|
||||
console.print(
|
||||
f"The Series {x.name} has nan-values. Please consider dropping or filling these "
|
||||
f"values with 'clean'."
|
||||
)
|
||||
elif not y.index.equals(x.index):
|
||||
console.print(
|
||||
f"The Series {y.name} and {x.name} do not have the same index."
|
||||
)
|
||||
(
|
||||
c,
|
||||
gamma,
|
||||
alpha,
|
||||
z,
|
||||
adfstat,
|
||||
pvalue,
|
||||
) = get_engle_granger_two_step_cointegration_test(x, y)
|
||||
result[f"{x.name}/{y.name}"] = [c, gamma, alpha, adfstat, pvalue]
|
||||
z_values[f"{x.name}/{y.name}"] = z
|
||||
|
||||
if result and z_values:
|
||||
if return_z:
|
||||
return z_values
|
||||
df = pd.DataFrame.from_dict(
|
||||
result,
|
||||
orient="index",
|
||||
columns=["Constant", "Gamma", "Alpha", "Dickey-Fuller", "P Value"],
|
||||
)
|
||||
return df
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def get_engle_granger_two_step_cointegration_test(dependent_series, independent_series):
|
||||
|
||||
@@ -3,27 +3,20 @@ __docformat__ = "numpy"
|
||||
|
||||
import logging
|
||||
import os
|
||||
from itertools import combinations
|
||||
from typing import Dict, Optional, List, Union
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from matplotlib.units import ConversionError
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
from matplotlib.units import ConversionError
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
|
||||
from openbb_terminal.config_plot import PLOT_DPI
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.helper_funcs import (
|
||||
export_data,
|
||||
plot_autoscale,
|
||||
)
|
||||
from openbb_terminal.helper_funcs import (
|
||||
print_rich_table,
|
||||
)
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.econometrics import econometrics_model
|
||||
from openbb_terminal.config_terminal import theme
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.econometrics import econometrics_model
|
||||
from openbb_terminal.econometrics.econometrics_helpers import get_ending
|
||||
from openbb_terminal.helper_funcs import export_data, plot_autoscale, print_rich_table
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -137,7 +130,7 @@ def display_norm(
|
||||
data: pd.Series,
|
||||
dataset: str = "",
|
||||
column: str = "",
|
||||
plot: bool = False,
|
||||
plot: bool = True,
|
||||
export: str = "",
|
||||
external_axes: Optional[List[plt.axes]] = None,
|
||||
):
|
||||
@@ -284,21 +277,10 @@ def display_granger(
|
||||
f"{independent_series.dtype}. Consider using the command 'type' to change this."
|
||||
)
|
||||
else:
|
||||
granger = econometrics_model.get_granger_causality(
|
||||
granger_df = econometrics_model.get_granger_causality(
|
||||
dependent_series, independent_series, lags
|
||||
)
|
||||
|
||||
for test in granger[lags][0]:
|
||||
# As ssr_chi2test and lrtest have one less value in the tuple, we fill
|
||||
# this value with a '-' to allow the conversion to a DataFrame
|
||||
if len(granger[lags][0][test]) != 4:
|
||||
pars = granger[lags][0][test]
|
||||
granger[lags][0][test] = (pars[0], pars[1], "-", pars[2])
|
||||
|
||||
granger_df = pd.DataFrame(
|
||||
granger[lags][0], index=["F-test", "P-value", "Count", "Lags"]
|
||||
).T
|
||||
|
||||
print_rich_table(
|
||||
granger_df,
|
||||
headers=list(granger_df.columns),
|
||||
@@ -306,7 +288,7 @@ def display_granger(
|
||||
title=f"Granger Causality Test [Y: {dependent_series.name} | X: {independent_series.name} | Lags: {lags}]",
|
||||
)
|
||||
|
||||
result_ftest = round(granger[lags][0]["params_ftest"][1], 3)
|
||||
result_ftest = round(granger_df.loc["params_ftest"]["P-value"], 3)
|
||||
|
||||
if result_ftest > confidence_level:
|
||||
console.print(
|
||||
@@ -330,9 +312,9 @@ def display_granger(
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_cointegration_test(
|
||||
datasets: Union[pd.DataFrame, Dict[str, pd.Series]],
|
||||
*datasets: pd.Series,
|
||||
significant: bool = False,
|
||||
plot: bool = False,
|
||||
plot: bool = True,
|
||||
export: str = "",
|
||||
external_axes: Optional[List[plt.axes]] = None,
|
||||
):
|
||||
@@ -355,8 +337,8 @@ def display_cointegration_test(
|
||||
|
||||
Parameters
|
||||
----------
|
||||
datasets: Union[pd.DataFrame, Dict[str, pd.Series]]
|
||||
All time series to perform co-integration tests on.
|
||||
datasets: pd.Series
|
||||
Variable number of series to test for cointegration
|
||||
significant: float
|
||||
Show only companies that have p-values lower than this percentage
|
||||
plot: bool
|
||||
@@ -366,81 +348,45 @@ def display_cointegration_test(
|
||||
external_axes:Optional[List[plt.axes]]
|
||||
External axes to plot on
|
||||
"""
|
||||
if len(datasets) < 2:
|
||||
console.print("[red]Co-integration requires at least two time series.[/red]")
|
||||
return
|
||||
|
||||
pairs = list(combinations(datasets.keys(), 2))
|
||||
result: Dict[str, list] = {}
|
||||
z_values: Dict[str, pd.Series] = {}
|
||||
df: pd.DataFrame = econometrics_model.get_coint_df(*datasets)
|
||||
|
||||
for x, y in pairs:
|
||||
if sum(datasets[y].isnull()) > 0:
|
||||
console.print(
|
||||
f"The Series {y} has nan-values. Please consider dropping or filling these "
|
||||
f"values with 'clean'."
|
||||
)
|
||||
elif sum(datasets[x].isnull()) > 0:
|
||||
console.print(
|
||||
f"The Series {x} has nan-values. Please consider dropping or filling these "
|
||||
f"values with 'clean'."
|
||||
)
|
||||
elif not datasets[y].index.equals(datasets[x].index):
|
||||
console.print(f"The Series {y} and {x} do not have the same index.")
|
||||
if significant:
|
||||
console.print(
|
||||
f"Only showing pairs that are statistically significant ({significant} > p-value)."
|
||||
)
|
||||
df = df[significant > df["P Value"]]
|
||||
console.print()
|
||||
|
||||
print_rich_table(
|
||||
df,
|
||||
headers=list(df.columns),
|
||||
show_index=True,
|
||||
index_name="Pairs",
|
||||
title="Cointegration Tests",
|
||||
)
|
||||
|
||||
if plot:
|
||||
if external_axes is None:
|
||||
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
else:
|
||||
try:
|
||||
(
|
||||
c,
|
||||
gamma,
|
||||
alpha,
|
||||
z,
|
||||
adfstat,
|
||||
pvalue,
|
||||
) = econometrics_model.get_engle_granger_two_step_cointegration_test(
|
||||
datasets[x], datasets[y]
|
||||
)
|
||||
result[f"{x}/{y}"] = [c, gamma, alpha, adfstat, pvalue]
|
||||
z_values[f"{x}/{y}"] = z
|
||||
except ValueError:
|
||||
console.print(
|
||||
"[red]Error: please only send string and integer columns[/red]\n"
|
||||
)
|
||||
ax = external_axes[0]
|
||||
|
||||
if result and z_values:
|
||||
df = pd.DataFrame.from_dict(
|
||||
result,
|
||||
orient="index",
|
||||
columns=["Constant", "Gamma", "Alpha", "Dickey-Fuller", "P Value"],
|
||||
)
|
||||
z_values = econometrics_model.get_coint_df(*datasets, return_z=True)
|
||||
|
||||
if significant:
|
||||
console.print(
|
||||
f"Only showing pairs that are statistically significant ({significant} > p-value)."
|
||||
)
|
||||
df = df[significant > df["P Value"]]
|
||||
console.print()
|
||||
for pair, values in z_values.items():
|
||||
ax.plot(values, label=pair)
|
||||
|
||||
print_rich_table(
|
||||
df,
|
||||
headers=list(df.columns),
|
||||
show_index=True,
|
||||
index_name="Pairs",
|
||||
title="Cointegration Tests",
|
||||
)
|
||||
ax.legend()
|
||||
ax.set_title("Error correction terms")
|
||||
|
||||
if plot:
|
||||
if external_axes is None:
|
||||
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
else:
|
||||
ax = external_axes[0]
|
||||
theme.style_primary_axis(ax)
|
||||
|
||||
for pair, values in z_values.items():
|
||||
ax.plot(values, label=pair)
|
||||
|
||||
ax.legend()
|
||||
ax.set_title("Error correction terms")
|
||||
|
||||
theme.style_primary_axis(ax)
|
||||
|
||||
if external_axes is None:
|
||||
theme.visualize_output()
|
||||
if external_axes is None:
|
||||
theme.visualize_output()
|
||||
|
||||
export_data(
|
||||
export,
|
||||
|
||||
@@ -1,70 +1,107 @@
|
||||
"""Regression Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
import logging
|
||||
from typing import List, Tuple, Dict, Any
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
import pandas as pd
|
||||
import statsmodels
|
||||
import statsmodels.api as sm
|
||||
from linearmodels import PooledOLS
|
||||
from linearmodels.panel import (
|
||||
RandomEffects,
|
||||
BetweenOLS,
|
||||
PanelOLS,
|
||||
FirstDifferenceOLS,
|
||||
PanelOLS,
|
||||
RandomEffects,
|
||||
compare,
|
||||
)
|
||||
from pandas import DataFrame
|
||||
from statsmodels.api import add_constant
|
||||
import statsmodels.api as sm
|
||||
from statsmodels.stats.api import het_breuschpagan
|
||||
from statsmodels.stats.diagnostic import acorr_breusch_godfrey
|
||||
from statsmodels.stats.stattools import durbin_watson
|
||||
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.econometrics.econometrics_helpers import get_datasets
|
||||
from openbb_terminal.helper_funcs import export_data
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.econometrics.econometrics_helpers import get_datasets
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_regressions_results(
|
||||
regression_type: str,
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
Y: pd.DataFrame,
|
||||
X: pd.DataFrame,
|
||||
regression_type: str = "OLS",
|
||||
entity_effects: bool = False,
|
||||
time_effects: bool = False,
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
) -> Any:
|
||||
"""Based on the regression type, this function decides what regression to run.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_type: str
|
||||
The type of regression you wish to execute.
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
entity_effects: bool
|
||||
Whether to apply Fixed Effects on entities.
|
||||
time_effects: bool
|
||||
Whether to apply Fixed Effects on time.
|
||||
Parameters
|
||||
----------
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
regression_type: str
|
||||
The type of regression you wish to execute.
|
||||
entity_effects: bool
|
||||
Whether to apply Fixed Effects on entities.
|
||||
time_effects: bool
|
||||
Whether to apply Fixed Effects on time.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the regression model.
|
||||
Returns
|
||||
-------
|
||||
A regression model
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb_terminal.sdk import openbb
|
||||
>>> df = openbb.econometrics.load("wage_panel")
|
||||
>>> df = df.set_index(["nr","year"])
|
||||
>>> X = df[["exper","educ","union"]]
|
||||
>>> Y = df["lwage"]
|
||||
>>> pooled_ols_model = openbb.econometrics.panel(Y,X,"POLS")
|
||||
>>> print(pooled_ols_model.summary)
|
||||
PooledOLS Estimation Summary
|
||||
================================================================================
|
||||
Dep. Variable: lwage R-squared: 0.1634
|
||||
Estimator: PooledOLS R-squared (Between): 0.1686
|
||||
No. Observations: 4360 R-squared (Within): 0.1575
|
||||
Date: Sun, Nov 13 2022 R-squared (Overall): 0.1634
|
||||
Time: 13:04:02 Log-likelihood -3050.4
|
||||
Cov. Estimator: Unadjusted
|
||||
F-statistic: 283.68
|
||||
Entities: 545 P-value 0.0000
|
||||
Avg Obs: 8.0000 Distribution: F(3,4356)
|
||||
Min Obs: 8.0000
|
||||
Max Obs: 8.0000 F-statistic (robust): 283.68
|
||||
P-value 0.0000
|
||||
Time periods: 8 Distribution: F(3,4356)
|
||||
Avg Obs: 545.00
|
||||
Min Obs: 545.00
|
||||
Max Obs: 545.00
|
||||
|
||||
Parameter Estimates
|
||||
==============================================================================
|
||||
Parameter Std. Err. T-stat P-value Lower CI Upper CI
|
||||
------------------------------------------------------------------------------
|
||||
const -0.0308 0.0620 -0.4965 0.6196 -0.1523 0.0908
|
||||
exper 0.0561 0.0028 20.220 0.0000 0.0507 0.0616
|
||||
educ 0.1080 0.0045 24.034 0.0000 0.0992 0.1168
|
||||
union 0.1777 0.0172 10.344 0.0000 0.1441 0.2114
|
||||
==============================================================================
|
||||
"""
|
||||
regressions = {
|
||||
"OLS": lambda: get_ols(regression_variables, data, False),
|
||||
"POLS": lambda: get_pols(regression_variables, data),
|
||||
"RE": lambda: get_re(regression_variables, data),
|
||||
"BOLS": lambda: get_bols(regression_variables, data),
|
||||
"FE": lambda: get_fe(regression_variables, data, entity_effects, time_effects),
|
||||
"FDOLS": lambda: get_fdols(regression_variables, data),
|
||||
"OLS": lambda: get_ols(Y, X),
|
||||
"POLS": lambda: get_pols(Y, X),
|
||||
"RE": lambda: get_re(Y, X),
|
||||
"BOLS": lambda: get_bols(Y, X),
|
||||
"FE": lambda: get_fe(Y, X, entity_effects, time_effects),
|
||||
"FDOLS": lambda: get_fdols(Y, X),
|
||||
}
|
||||
if regression_type in regressions:
|
||||
return regressions[regression_type]()
|
||||
@@ -134,212 +171,185 @@ def get_regression_data(
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_ols(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
show_regression: bool = True,
|
||||
export: str = "",
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
Y: pd.DataFrame,
|
||||
X: pd.DataFrame,
|
||||
) -> Any:
|
||||
"""Performs an OLS regression on timeseries data. [Source: Statsmodels]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
show_regression: bool
|
||||
Whether to show the regression results table.
|
||||
export: str
|
||||
Format to export data
|
||||
Parameters
|
||||
----------
|
||||
Y: pd.DataFrame
|
||||
Dependent variable series.
|
||||
X: pd.DataFrame
|
||||
Dataframe of independent variables series.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the OLS model.
|
||||
Returns
|
||||
-------
|
||||
statsmodels.regression.linear_model.RegressionResultsWrapper
|
||||
Regression model wrapper from statsmodels.
|
||||
|
||||
Examples
|
||||
-------
|
||||
>>> import openbb_terminal.sdk as openbb
|
||||
>>> df = openbb.econometrics.load("wage_panel")
|
||||
>>> OLS_model = openbb.econometrics.OLS(df["lwage"], df[["educ", "exper", "expersq"]])
|
||||
>>> print(OLS_model.summary())
|
||||
OLS Regression Results
|
||||
=======================================================================================
|
||||
Dep. Variable: lwage R-squared (uncentered): 0.920
|
||||
Model: OLS Adj. R-squared (uncentered): 0.919
|
||||
Method: Least Squares F-statistic: 1.659e+04
|
||||
Date: Thu, 10 Nov 2022 Prob (F-statistic): 0.00
|
||||
Time: 15:28:11 Log-Likelihood: -3091.3
|
||||
No. Observations: 4360 AIC: 6189.
|
||||
Df Residuals: 4357 BIC: 6208.
|
||||
Df Model: 3
|
||||
Covariance Type: nonrobust
|
||||
==============================================================================
|
||||
coef std err t P>|t| [0.025 0.975]
|
||||
------------------------------------------------------------------------------
|
||||
educ 0.0986 0.002 39.879 0.000 0.094 0.103
|
||||
exper 0.1018 0.009 10.737 0.000 0.083 0.120
|
||||
expersq -0.0034 0.001 -4.894 0.000 -0.005 -0.002
|
||||
==============================================================================
|
||||
Omnibus: 1249.642 Durbin-Watson: 0.954
|
||||
Prob(Omnibus): 0.000 Jarque-Bera (JB): 9627.436
|
||||
Skew: -1.152 Prob(JB): 0.00
|
||||
Kurtosis: 9.905 Cond. No. 86.4
|
||||
==============================================================================
|
||||
|
||||
Notes:
|
||||
[1] R² is computed without centering (uncentered) since the model does not contain a constant.
|
||||
[2] Standard Errors assume that the covariance matrix of the errors is correctly specified.
|
||||
"""
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "OLS"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if X.empty or Y.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
model = sm.OLS(
|
||||
regression_df[dependent_variable], regression_df[independent_variables]
|
||||
).fit()
|
||||
|
||||
if show_regression:
|
||||
console.print(model.summary())
|
||||
console.print("")
|
||||
model = sm.OLS(Y, X).fit()
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
if export:
|
||||
results_as_html = model.summary().tables[1].as_html()
|
||||
df = pd.read_html(results_as_html, header=0, index_col=0)[0]
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
f"{dependent_variable}_ols_regression",
|
||||
df,
|
||||
)
|
||||
else:
|
||||
console.print("")
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_pols(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
def get_pols(Y: pd.DataFrame, X: pd.DataFrame) -> Any:
|
||||
"""PooledOLS is just plain OLS that understands that various panel data structures.
|
||||
It is useful as a base model. [Source: LinearModels]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the Pooled OLS model.
|
||||
PooledOLS model
|
||||
"""
|
||||
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "POLS"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if Y.empty or X.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
exogenous = add_constant(regression_df[independent_variables])
|
||||
model = PooledOLS(regression_df[dependent_variable], exogenous).fit()
|
||||
console.print(model)
|
||||
exogenous = add_constant(X)
|
||||
model = PooledOLS(Y, exogenous).fit()
|
||||
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_re(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
def get_re(Y: pd.DataFrame, X: pd.DataFrame) -> Any:
|
||||
"""The random effects model is virtually identical to the pooled OLS model except that is accounts for the
|
||||
structure of the model and so is more efficient. Random effects uses a quasi-demeaning strategy which
|
||||
subtracts the time average of the within entity values to account for the common shock. [Source: LinearModels]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the RandomEffects model.
|
||||
RandomEffects model
|
||||
"""
|
||||
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "RE"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if X.empty or Y.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
exogenous = add_constant(regression_df[independent_variables])
|
||||
model = RandomEffects(regression_df[dependent_variable], exogenous).fit()
|
||||
console.print(model)
|
||||
exogenous = add_constant(X)
|
||||
model = RandomEffects(Y, exogenous).fit()
|
||||
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_bols(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
def get_bols(Y: pd.DataFrame, X: pd.DataFrame) -> Any:
|
||||
"""The between estimator is an alternative, usually less efficient estimator, can can be used to
|
||||
estimate model parameters. It is particular simple since it first computes the time averages of
|
||||
y and x and then runs a simple regression using these averages. [Source: LinearModels]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the Between OLS model.
|
||||
BetweenOLS model
|
||||
"""
|
||||
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "BOLS"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if Y.empty or X.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
exogenous = add_constant(regression_df[independent_variables])
|
||||
model = BetweenOLS(regression_df[dependent_variable], exogenous).fit()
|
||||
console.print(model)
|
||||
exogenous = add_constant(X)
|
||||
model = BetweenOLS(Y, exogenous).fit()
|
||||
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_fe(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
Y: pd.DataFrame,
|
||||
X: pd.DataFrame,
|
||||
entity_effects: bool = False,
|
||||
time_effects: bool = False,
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
) -> Any:
|
||||
"""When effects are correlated with the regressors the RE and BE estimators are not consistent.
|
||||
The usual solution is to use Fixed Effects which are called entity_effects when applied to
|
||||
entities and time_effects when applied to the time dimension. [Source: LinearModels]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
entity_effects : bool
|
||||
Whether to include entity effects
|
||||
time_effects : bool
|
||||
@@ -347,40 +357,30 @@ def get_fe(
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the OLS model.
|
||||
PanelOLS model with Fixed Effects
|
||||
"""
|
||||
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "FE"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if X.empty or Y.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
exogenous = add_constant(regression_df[independent_variables])
|
||||
exogenous = add_constant(X)
|
||||
model = PanelOLS(
|
||||
regression_df[dependent_variable],
|
||||
Y,
|
||||
exogenous,
|
||||
entity_effects=entity_effects,
|
||||
time_effects=time_effects,
|
||||
).fit()
|
||||
console.print(model)
|
||||
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_fdols(
|
||||
regression_variables: List[Tuple],
|
||||
data: Dict[str, pd.DataFrame],
|
||||
) -> Tuple[DataFrame, Any, List[Any], Any]:
|
||||
def get_fdols(Y: pd.DataFrame, X: pd.DataFrame) -> Any:
|
||||
"""First differencing is an alternative to using fixed effects when there might be correlation.
|
||||
When using first differences, time-invariant variables must be excluded. Additionally,
|
||||
only one linear time-trending variable can be included since this will look like a constant.
|
||||
@@ -389,41 +389,31 @@ def get_fdols(
|
||||
|
||||
Parameters
|
||||
----------
|
||||
regression_variables : list
|
||||
The regressions variables entered where the first variable is
|
||||
the dependent variable.
|
||||
data : dict
|
||||
A dictionary containing the datasets.
|
||||
Y: pd.DataFrame
|
||||
Dataframe containing the dependent variable.
|
||||
X: pd.DataFrame
|
||||
Dataframe containing the independent variables.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the OLS model.
|
||||
First Difference OLS model
|
||||
"""
|
||||
|
||||
regression_df, dependent_variable, independent_variables = get_regression_data(
|
||||
regression_variables, data, "FDOLS"
|
||||
)
|
||||
|
||||
if regression_df.empty:
|
||||
if X.empty or Y.empty:
|
||||
model = None
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as warning_messages:
|
||||
model = FirstDifferenceOLS(
|
||||
regression_df[dependent_variable], regression_df[independent_variables]
|
||||
).fit()
|
||||
console.print(model)
|
||||
model = FirstDifferenceOLS(Y, X).fit()
|
||||
|
||||
if len(warning_messages) > 0:
|
||||
console.print("Warnings:")
|
||||
for warning in warning_messages:
|
||||
console.print(f"[red]{warning.message}[/red]".replace("\n", ""))
|
||||
|
||||
return regression_df, dependent_variable, independent_variables, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_comparison(regressions, export: str = ""):
|
||||
def get_comparison(regressions: Dict, export: str = ""):
|
||||
"""Compare regression results between Panel Data regressions.
|
||||
|
||||
Parameters
|
||||
@@ -471,51 +461,76 @@ def get_comparison(regressions, export: str = ""):
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_dwat(residual: pd.DataFrame) -> pd.DataFrame:
|
||||
"""Calculate test statistics for Durbing Watson autocorrelation
|
||||
def get_dwat(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
|
||||
) -> float:
|
||||
"""Calculate test statistics for Durbin Watson autocorrelation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
residual : OLS Model
|
||||
Model containing residual values.
|
||||
model : statsmodels.regression.linear_model.RegressionResultsWrapper
|
||||
Previously fit statsmodels OLS.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Test statistic of the Durbin Watson test.
|
||||
float
|
||||
Test statistic of the Durbin Watson test.
|
||||
|
||||
Notes
|
||||
------
|
||||
When using chart = True, the dependent variable in the regression must be passed to view the residuals
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> from openbb_terminal.sdk import openbb
|
||||
>>> df = openbb.econometrics.load("wage_panel")
|
||||
>>> Y, X = df["lwage"], df[["exper","educ"]]
|
||||
>>> model = openbb.econometrics.ols(Y,X)
|
||||
>>> durbin_watson_value = openbb.econometrics.dwat(model)
|
||||
>>> durbin_watson_value
|
||||
0.96
|
||||
"""
|
||||
# Durbin Watson test: The test statistic is approximately equal to 2*(1-r) where r is the
|
||||
# sample autocorrelation of the residuals. Thus, for r == 0, indicating no serial correlation,
|
||||
# the test statistic equals 2. This statistic will always be between 0 and 4. The closer
|
||||
# to 0 the statistic, the more evidence for positive serial correlation. The closer to 4,
|
||||
# the more evidence for negative serial correlation.
|
||||
result = durbin_watson(residual)
|
||||
result = durbin_watson(model.resid)
|
||||
|
||||
return round(result, 2)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_bgod(model: pd.DataFrame, lags: int = 3) -> tuple:
|
||||
def get_bgod(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper, lags: int = 3
|
||||
) -> pd.DataFrame:
|
||||
"""Calculate test statistics for autocorrelation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : OLS Model
|
||||
Model containing residual values.
|
||||
OLS model that has been fit.
|
||||
lags : int
|
||||
The amount of lags.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Test results from the Breusch-Godfrey Test
|
||||
pd.DataFrame
|
||||
Test results from the Breusch-Godfrey Test
|
||||
"""
|
||||
|
||||
lm_stat, p_value, f_stat, fp_value = acorr_breusch_godfrey(model, nlags=lags)
|
||||
|
||||
return lm_stat, p_value, f_stat, fp_value
|
||||
return pd.DataFrame(
|
||||
[lm_stat, p_value, f_stat, fp_value],
|
||||
index=["lm-stat", "p-value", "f-stat", "fp-value"],
|
||||
)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def get_bpag(model: pd.DataFrame) -> tuple:
|
||||
def get_bpag(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
|
||||
) -> pd.DataFrame:
|
||||
"""Calculate test statistics for heteroscedasticity
|
||||
|
||||
Parameters
|
||||
@@ -525,9 +540,12 @@ def get_bpag(model: pd.DataFrame) -> tuple:
|
||||
|
||||
Returns
|
||||
-------
|
||||
Test results from the Breusch-Pagan Test
|
||||
pd.DataFrame
|
||||
Test results from the Breusch-Pagan Test
|
||||
"""
|
||||
|
||||
lm_stat, p_value, f_stat, fp_value = het_breuschpagan(model.resid, model.model.exog)
|
||||
|
||||
return lm_stat, p_value, f_stat, fp_value
|
||||
return pd.DataFrame(
|
||||
[lm_stat, p_value, f_stat, fp_value],
|
||||
index=["lm-stat", "p-value", "f-stat", "fp-value"],
|
||||
)
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
"""Regression View"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from typing import Optional, List, Tuple, Dict
|
||||
import os
|
||||
import logging
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
import pandas as pd
|
||||
from matplotlib import pyplot as plt
|
||||
import statsmodels
|
||||
|
||||
from openbb_terminal.config_plot import PLOT_DPI
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.helper_funcs import plot_autoscale, export_data
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.econometrics import regression_model
|
||||
from openbb_terminal.helper_funcs import (
|
||||
print_rich_table,
|
||||
)
|
||||
from openbb_terminal.config_terminal import theme
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.econometrics import regression_model
|
||||
from openbb_terminal.helper_funcs import export_data, plot_autoscale, print_rich_table
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_panel(
|
||||
data: Dict[str, pd.DataFrame],
|
||||
regression_variables: List[Tuple],
|
||||
Y: pd.DataFrame,
|
||||
X: pd.DataFrame,
|
||||
regression_type: str = "OLS",
|
||||
entity_effects: bool = False,
|
||||
time_effects: bool = False,
|
||||
@@ -54,23 +53,20 @@ def display_panel(
|
||||
The dataset used, the dependent variable, the independent variable and
|
||||
the regression model.
|
||||
"""
|
||||
(
|
||||
regression_df,
|
||||
dependent,
|
||||
independent,
|
||||
model,
|
||||
) = regression_model.get_regressions_results(
|
||||
model = regression_model.get_regressions_results(
|
||||
Y,
|
||||
X,
|
||||
regression_type,
|
||||
regression_variables,
|
||||
data,
|
||||
entity_effects,
|
||||
time_effects,
|
||||
)
|
||||
if regression_type != "OLS":
|
||||
console.print(model)
|
||||
|
||||
if export:
|
||||
results_as_html = model.summary.tables[1].as_html()
|
||||
df = pd.read_html(results_as_html, header=0, index_col=0)[0]
|
||||
|
||||
dependent = Y.columns[0]
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
@@ -78,14 +74,14 @@ def display_panel(
|
||||
df,
|
||||
)
|
||||
|
||||
return regression_df, dependent, independent, model
|
||||
return model
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_dwat(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
|
||||
dependent_variable: pd.Series,
|
||||
residual: pd.DataFrame,
|
||||
plot: bool = False,
|
||||
plot: bool = True,
|
||||
export: str = "",
|
||||
external_axes: Optional[List[plt.axes]] = None,
|
||||
):
|
||||
@@ -93,10 +89,10 @@ def display_dwat(
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : OLS Model
|
||||
A fit statsmodels OLS model.
|
||||
dependent_variable : pd.Series
|
||||
The dependent variable.
|
||||
residual : OLS Model
|
||||
The residual of an OLS model.
|
||||
The dependent variable for plotting
|
||||
plot : bool
|
||||
Whether to plot the residuals
|
||||
export : str
|
||||
@@ -104,7 +100,7 @@ def display_dwat(
|
||||
external_axes: Optional[List[plt.axes]]
|
||||
External axes to plot on
|
||||
"""
|
||||
autocorr = regression_model.get_dwat(residual)
|
||||
autocorr = regression_model.get_dwat(model)
|
||||
|
||||
if 1.5 < autocorr < 2.5:
|
||||
console.print(
|
||||
@@ -123,7 +119,7 @@ def display_dwat(
|
||||
else:
|
||||
ax = external_axes[0]
|
||||
|
||||
ax.scatter(dependent_variable, residual)
|
||||
ax.scatter(dependent_variable, model.resid)
|
||||
ax.axhline(y=0, color="r", linestyle="-")
|
||||
ax.set_ylabel("Residual")
|
||||
ax.set_xlabel(dependent_variable.name.capitalize())
|
||||
@@ -140,33 +136,25 @@ def display_dwat(
|
||||
autocorr,
|
||||
)
|
||||
|
||||
console.print()
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_bgod(model: pd.DataFrame, lags: int = 3, export: str = ""):
|
||||
def display_bgod(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
|
||||
lags: int = 3,
|
||||
export: str = "",
|
||||
):
|
||||
"""Show Breusch-Godfrey autocorrelation test
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : OLS Model
|
||||
Model containing residual values.
|
||||
OLS model that has been fit.
|
||||
lags : int
|
||||
The amount of lags included.
|
||||
export : str
|
||||
Format to export data
|
||||
"""
|
||||
(
|
||||
lm_stat,
|
||||
p_value,
|
||||
f_stat,
|
||||
fp_value,
|
||||
) = regression_model.get_bgod(model, lags)
|
||||
|
||||
df = pd.DataFrame(
|
||||
[lm_stat, p_value, f_stat, fp_value],
|
||||
index=["LM-stat", "p-value", "f-stat", "fp-value"],
|
||||
)
|
||||
df = regression_model.get_bgod(model, lags)
|
||||
|
||||
print_rich_table(
|
||||
df,
|
||||
@@ -174,7 +162,7 @@ def display_bgod(model: pd.DataFrame, lags: int = 3, export: str = ""):
|
||||
show_index=True,
|
||||
title=f"Breusch-Godfrey autocorrelation test [Lags: {lags}]",
|
||||
)
|
||||
|
||||
p_value = df.loc["p-value"][0]
|
||||
if p_value > 0.05:
|
||||
console.print(
|
||||
f"{round(p_value, 2)} indicates the autocorrelation. Consider re-estimating with "
|
||||
@@ -191,27 +179,20 @@ def display_bgod(model: pd.DataFrame, lags: int = 3, export: str = ""):
|
||||
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def display_bpag(model: pd.DataFrame, export: str = ""):
|
||||
def display_bpag(
|
||||
model: statsmodels.regression.linear_model.RegressionResultsWrapper,
|
||||
export: str = "",
|
||||
):
|
||||
"""Show Breusch-Pagan heteroscedasticity test
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : OLS Model
|
||||
Model containing residual values.
|
||||
OLS model that has been fit.
|
||||
export : str
|
||||
Format to export data
|
||||
"""
|
||||
(
|
||||
lm_stat,
|
||||
p_value,
|
||||
f_stat,
|
||||
fp_value,
|
||||
) = regression_model.get_bpag(model)
|
||||
|
||||
df = pd.DataFrame(
|
||||
[lm_stat, p_value, f_stat, fp_value],
|
||||
index=["lm-stat", "p-value", "f-stat", "fp-value"],
|
||||
)
|
||||
df = regression_model.get_bpag(model)
|
||||
|
||||
print_rich_table(
|
||||
df,
|
||||
@@ -219,7 +200,7 @@ def display_bpag(model: pd.DataFrame, export: str = ""):
|
||||
show_index=True,
|
||||
title="Breusch-Pagan heteroscedasticity test",
|
||||
)
|
||||
|
||||
p_value = df.loc["p-value"][0]
|
||||
if p_value > 0.05:
|
||||
console.print(
|
||||
f"{round(p_value, 2)} indicates heteroscedasticity. Consider taking the log "
|
||||
|
||||
1118
openbb_terminal/miscellaneous/library/trail_map.csv
vendored
1118
openbb_terminal/miscellaneous/library/trail_map.csv
vendored
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
,F-test,P-value,Count,Lags
|
||||
ssr_ftest,2.66991,0.04882,193.0,3.0
|
||||
ssr_chi2test,8.30024,0.0402,-,3.0
|
||||
lrtest,8.13263,0.04335,-,3.0
|
||||
params_ftest,2.66991,0.04882,193.0,3.0
|
||||
|
@@ -0,0 +1,5 @@
|
||||
,F-test,P-value,Count,Lags
|
||||
ssr_ftest,3.26559,0.04026,196.0,2.0
|
||||
ssr_chi2test,6.69779,0.03512,-,2.0
|
||||
lrtest,6.58862,0.03709,-,2.0
|
||||
params_ftest,3.26559,0.04026,196.0,2.0
|
||||
|
@@ -0,0 +1,5 @@
|
||||
,F-test,P-value,Count,Lags
|
||||
ssr_ftest,1.01264,0.31549,199.0,1.0
|
||||
ssr_chi2test,1.0279,0.31065,-,1.0
|
||||
lrtest,1.0253,0.31127,-,1.0
|
||||
params_ftest,1.01264,0.31549,199.0,1.0
|
||||
|
@@ -218,11 +218,9 @@ def test_get_root(recorder, df, fuller_reg, kpss_reg):
|
||||
def test_get_granger_causality(recorder, time_series_y, time_series_x, lags):
|
||||
result = econometrics_model.get_granger_causality(
|
||||
dependent_series=time_series_y, independent_series=time_series_x, lags=lags
|
||||
)
|
||||
).applymap(lambda x: round(float(x), 5) if x != "-" else x)
|
||||
|
||||
# The first item is taken since the second item contains Statsmodels
|
||||
# objects (which change their identifier on every iteration)
|
||||
recorder.capture_list(result[lags][0])
|
||||
recorder.capture(result)
|
||||
|
||||
|
||||
@pytest.mark.vcr()
|
||||
|
||||
@@ -148,34 +148,34 @@ def test_display_granger(time_series_y, time_series_x, lags, confidence_level):
|
||||
"datasets, significant, plot",
|
||||
[
|
||||
(
|
||||
{
|
||||
"y": common_model.load(
|
||||
[
|
||||
common_model.load(
|
||||
"interest_inflation",
|
||||
{},
|
||||
{"interest_inflation": "interest_inflation"},
|
||||
)["Dp"],
|
||||
"x": common_model.load(
|
||||
common_model.load(
|
||||
"interest_inflation",
|
||||
{},
|
||||
{"interest_inflation": "interest_inflation"},
|
||||
)["R"],
|
||||
},
|
||||
],
|
||||
True,
|
||||
False,
|
||||
),
|
||||
(
|
||||
{
|
||||
"y": common_model.load(
|
||||
[
|
||||
common_model.load(
|
||||
"interest_inflation",
|
||||
{},
|
||||
{"interest_inflation": "interest_inflation"},
|
||||
)["Dp"],
|
||||
"x": common_model.load(
|
||||
common_model.load(
|
||||
"interest_inflation",
|
||||
{},
|
||||
{"interest_inflation": "interest_inflation"},
|
||||
)["R"],
|
||||
},
|
||||
],
|
||||
False,
|
||||
False,
|
||||
),
|
||||
@@ -183,5 +183,5 @@ def test_display_granger(time_series_y, time_series_x, lags, confidence_level):
|
||||
)
|
||||
def test_get_engle_granger_two_step_cointegration_test(datasets, significant, plot):
|
||||
econometrics_view.display_cointegration_test(
|
||||
datasets=datasets, significant=significant, plot=plot
|
||||
*datasets, significant=significant, plot=plot
|
||||
)
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['-n', 'dataset']
|
||||
|
||||
Perform an OLS regression before estimating the Breusch-Godfrey statistic.
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
Perform an OLS regression before estimating the Breusch-Godfrey statistic.
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['data']
|
||||
|
||||
Perform an OLS regression before estimating the Breusch-Pagan statistic.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['-n', 'dataset']
|
||||
|
||||
Perform an OLS regression before estimating the Breusch-Pagan statistic.
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
Perform an OLS regression before estimating the Breusch-Pagan statistic.
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
[red]'data' is not valid.[/red]
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
No Panel regression estimates available. Please use the command 'panel' before using this command.
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
Empty dataset
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
cancer population
|
||||
count 301.000000 301.000000
|
||||
mean 39.857143 11288.056478
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
Empty dataset
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['data']
|
||||
|
||||
Please perform an OLS regression before estimating the Durbin-Watson statistic.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['-n', 'dataset']
|
||||
|
||||
Please perform an OLS regression before estimating the Durbin-Watson statistic.
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
Please perform an OLS regression before estimating the Durbin-Watson statistic.
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
The following args couldn't be interpreted: ['-n', 'dataset']
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
The following args couldn't be interpreted: ['cancer']
|
||||
|
||||
cancer population
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
|
||||
[red]No data available for dataset.[/red]
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
[red]badcol not a valid column. Showing without sorting.
|
||||
[/red]
|
||||
cancer population
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
cancer population
|
||||
300 360.0 88456.0
|
||||
293 302.0 60161.0
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
cancer population
|
||||
0 1.0 445.0
|
||||
1 0.0 559.0
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
0
|
||||
cancer float64
|
||||
population float64
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
0
|
||||
cancer float64
|
||||
population float64
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Only showing pairs that are statistically significant (True > p-value).
|
||||
|
||||
Constant Gamma Alpha Dickey-Fuller P Value
|
||||
y/x -0.003126 0.154512 -1.2884 -13.123662 1.544757e-24
|
||||
Constant Gamma Alpha Dickey-Fuller P Value
|
||||
Dp/R -0.003126 0.154512 -1.2884 -13.123662 1.544757e-24
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Constant Gamma Alpha Dickey-Fuller P Value
|
||||
y/x -0.003126 0.154512 -1.2884 -13.123662 1.544757e-24
|
||||
Constant Gamma Alpha Dickey-Fuller P Value
|
||||
Dp/R -0.003126 0.154512 -1.2884 -13.123662 1.544757e-24
|
||||
|
||||
Reference in New Issue
Block a user