Skip to content

Commit

Permalink
Adding GARCH (#4815)
Browse files Browse the repository at this point in the history
* Add GARCH

* Linting

* Rearrange the econometrics menu

* Add integration test

* Add ret command + fixes

* Fix linting

* Fix linting

* Fix pylint

* Add logger to functions

* bump pywry

* fix rm command (#4890)

Co-authored-by: Henrique Joaquim <[email protected]>

* Fix `crypto/defi/anchor` (#4892)

* handle defi anchor exceptions

* reason

* mypy

---------

Co-authored-by: Henrique Joaquim <[email protected]>

* fix windows pyinstaller subprocess fail if space in path

* remove API_IEX_TOKEN

* remove API_SENTIMENTINVESTOR_TOKEN

* Convert to latex + requested changes

* Fix linting

* Remove unnecessary logger

* Add example

* SDK updated

* fix syntax on elite level math that I def know

* Fix docstring

* Fix example

* Fix

* Linting

---------

Co-authored-by: James Maslek <[email protected]>
Co-authored-by: teh_coderer <[email protected]>
Co-authored-by: montezdesousa <[email protected]>
Co-authored-by: Henrique Joaquim <[email protected]>
Co-authored-by: andrewkenreich <[email protected]>
  • Loading branch information
6 people authored May 10, 2023
1 parent 33da518 commit bde21f0
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 19 deletions.
4 changes: 4 additions & 0 deletions openbb_terminal/core/sdk/models/econometrics_sdk_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class EconometricsRoot(Category):
`dwat_chart`: Show Durbin-Watson autocorrelation tests\n
`fdols`: First differencing is an alternative to using fixed effects when there might be correlation.\n
`fe`: When effects are correlated with the regressors the RE and BE estimators are not consistent.\n
`garch`: Calculates annualized volatility forecasts based on GARCH.\n
`garch_chart`: Plots the annualized volatility forecasts based on GARCH\n
`get_regression_data`: This function creates a DataFrame with the required regression data as\n
`granger`: Calculate granger tests\n
`granger_chart`: Show granger tests\n
Expand Down Expand Up @@ -56,6 +58,8 @@ def __init__(self):
self.dwat_chart = lib.econometrics_regression_view.display_dwat
self.fdols = lib.econometrics_regression_model.get_fdols
self.fe = lib.econometrics_regression_model.get_fe
self.garch = lib.econometrics_model.get_garch
self.garch_chart = lib.econometrics_view.display_garch
self.get_regression_data = lib.econometrics_regression_model.get_regression_data
self.granger = lib.econometrics_model.get_granger_causality
self.granger_chart = lib.econometrics_view.display_granger
Expand Down
1 change: 1 addition & 0 deletions openbb_terminal/core/sdk/trail_map.csv
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ econometrics.panel,econometrics_regression_model.get_regressions_results,econome
econometrics.pols,econometrics_regression_model.get_pols,
econometrics.re,econometrics_regression_model.get_re,
econometrics.root,econometrics_model.get_root,econometrics_view.display_root
econometrics.garch,econometrics_model.get_garch,econometrics_view.display_garch
economy.available_indices,economy_yfinance_model.get_available_indices,
economy.balance,economy_oecd_model.get_balance,economy_oecd_view.plot_balance
economy.bigmac,economy_nasdaq_model.get_big_mac_indices,economy_nasdaq_view.display_big_mac_index
Expand Down
178 changes: 173 additions & 5 deletions openbb_terminal/econometrics/econometrics_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class EconometricsController(BaseController):
"combine",
"rename",
"lag",
"ret",
"ols",
"norm",
"root",
Expand All @@ -73,6 +74,7 @@ class EconometricsController(BaseController):
"dwat",
"bgod",
"bpag",
"garch",
"granger",
"coint",
]
Expand Down Expand Up @@ -181,6 +183,7 @@ def __init__(self, queue: Optional[List[str]] = None):
"plot",
"norm",
"root",
"garch",
"granger",
"coint",
"corr",
Expand Down Expand Up @@ -217,6 +220,7 @@ def update_runtime_choices(self):
"ols",
"panel",
"delete",
"garch",
]:
self.choices[feature] = dataset_columns
for feature in [
Expand Down Expand Up @@ -280,17 +284,19 @@ def print_help(self):
mt.add_cmd("combine", self.files)
mt.add_cmd("rename", self.files)
mt.add_cmd("lag", self.files)
mt.add_cmd("ret", self.files)
mt.add_cmd("export", self.files)
mt.add_info("_tests_")
mt.add_info("time_series_")
mt.add_cmd("norm", self.files)
mt.add_cmd("root", self.files)
mt.add_cmd("ols", self.files)
mt.add_cmd("granger", self.files)
mt.add_cmd("root", self.files)
mt.add_cmd("coint", self.files)
mt.add_info("_regression_")
mt.add_cmd("ols", self.files)
mt.add_cmd("garch", self.files)
mt.add_info("_panel_")
mt.add_cmd("panel", self.files)
mt.add_cmd("compare", self.files)
mt.add_info("_regression_tests_")
mt.add_info("_residuals_")
mt.add_cmd("dwat", self.files and self.regression["OLS"]["model"])
mt.add_cmd("bgod", self.files and self.regression["OLS"]["model"])
mt.add_cmd("bpag", self.files and self.regression["OLS"]["model"])
Expand Down Expand Up @@ -1224,6 +1230,50 @@ def call_lag(self, other_args: List[str]):

self.update_runtime_choices()

@log_start_end(log=logger)
def call_ret(self, other_args: List[str]):
"""Process ret command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="ret",
description="Calculate returns for the given column.",
)
parser.add_argument(
"-v",
"--values",
help="Dataset.column values to calculate returns.",
dest="values",
choices={
f"{dataset}.{column}": {column: None, dataset: None}
for dataset, dataframe in self.datasets.items()
for column in dataframe.columns
},
type=str,
required="-h" not in other_args,
)

if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-v")
ns_parser = self.parse_known_args_and_warn(
parser, other_args, export_allowed=NO_EXPORT
)

if not ns_parser:
return

try:
dataset, col = ns_parser.values.split(".")
data = self.datasets[dataset]
except ValueError:
console.print("[red]Please enter 'dataset'.'column'.[/red]\n")
return

data[col + "_returns"] = econometrics_model.get_returns(data[col])
self.datasets[dataset] = data

self.update_runtime_choices()

@log_start_end(log=logger)
def call_eval(self, other_args):
"""Process eval command"""
Expand Down Expand Up @@ -1890,6 +1940,124 @@ def call_bpag(self, other_args):
self.regression["OLS"]["model"], ns_parser.export
)

@log_start_end(log=logger)
def call_garch(self, other_args: List[str]):
"""Process garch command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="garch",
description=r"""Calculates annualized volatility forecasts based on GARCH.
GARCH (Generalized autoregressive conditional heteroskedasticity) is stochastic model for time series,
which is for instance used to model volatility clusters, stock return and inflation. It is a
generalisation of the ARCH models.
$\text{GARCH}(p, q) = (1 - \alpha - \beta) \sigma_l + \sum_{i=1}^q \alpha u_{t-i}^2 + \sum_{i=1}^p \beta
\sigma_{t-i}^2$ [1]
The GARCH-model assumes that the variance estimate consists of 3 components:
- $\sigma_l$ ; the long term component, which is unrelated to the current market conditions
- $u_t$ ; the innovation/discovery through current market price changes
- $\sigma_t$ ; the last estimate
GARCH can be understood as a model, which allows to optimize these 3 variance components to the time
series. This is done assigning weights to variance components: $(1 - \alpha - \beta)$ for $\sigma_l$ ,
$\alpha$ for $u_t$ and $\beta$ for $\sigma_t$ . [2]
The weights can be estimated by iterating over different values of $(1 - \alpha - \beta) \sigma_l$
which we will call $\omega$ , $\alpha$ and $\beta$ , while maximizing:
$\sum_{i} -ln(v_i) - (u_i ^ 2) / v_i$ . With the constraints:
- $\alpha > 0$
- $\beta > 0$
- $\alpha + \beta < 1$
Note that there is no restriction on $\omega$ .
Another method used for estimation is "variance targeting", where one first sets $\omega$
equal to the variance of the time series. This method nearly as effective as the previously mentioned and
is less computationally effective.
One can measure the fit of the time series to the GARCH method by using the Ljung-Box statistic. [3]
See the sources below for reference and for greater detail.
Sources:
[1] Generalized Autoregressive Conditional Heteroskedasticity, by Tim Bollerslev
[2] Finance Compact Plus Band 1, by Yvonne Seler Zimmerman and Heinz Zimmerman; ISBN: 978-3-907291-31-1
[3] Options, Futures & other Derivates, by John C. Hull; ISBN: 0-13-022444-8""",
)
parser.add_argument(
"-v",
"--value",
type=str,
choices=self.choices["garch"],
dest="column",
help="The column and name of the database you want to estimate volatility for",
required="-h" not in other_args,
)
parser.add_argument(
"-p",
help="The lag order of the symmetric innovation",
dest="p",
type=int,
default=1,
)
parser.add_argument(
"-o",
help="The lag order of the asymmetric innovation",
dest="o",
type=int,
default=0,
)
parser.add_argument(
"-q",
help="The lag order of lagged volatility or equivalent",
dest="q",
type=int,
default=1,
)
parser.add_argument(
"-m",
"--mean",
help="Choose mean model",
choices=["LS", "AR", "ARX", "HAR", "HARX", "constant", "zero"],
default="constant",
type=str,
dest="mean",
)
parser.add_argument(
"-l",
"--length",
help="The length of the estimate",
dest="horizon",
type=int,
default=100,
)
parser.add_argument(
"-d",
"--detailed",
help="Display the details about the parameter fit, for instance the confidence interval",
dest="detailed",
action="store_true",
default=False,
)
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-v")
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES
)
if ns_parser:
dataset, column = ns_parser.column.split(".")
econometrics_view.display_garch(
self.datasets[dataset],
column,
ns_parser.p,
ns_parser.o,
ns_parser.q,
ns_parser.mean,
ns_parser.horizon,
ns_parser.detailed,
)

@log_start_end(log=logger)
def call_granger(self, other_args: List[str]):
"""Process granger command"""
Expand Down
Loading

0 comments on commit bde21f0

Please sign in to comment.