From 24276c1ec5459f9047bee99da424e3b27db7498b Mon Sep 17 00:00:00 2001 From: Ammar Siddiqui Date: Sat, 20 May 2023 16:52:33 -0400 Subject: [PATCH 1/4] Added new ml module folder and time series file --- quantpy/ml/__init__.py | 0 quantpy/ml/time_series.py | 15 +++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 quantpy/ml/__init__.py create mode 100644 quantpy/ml/time_series.py diff --git a/quantpy/ml/__init__.py b/quantpy/ml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/quantpy/ml/time_series.py b/quantpy/ml/time_series.py new file mode 100644 index 0000000..188c27c --- /dev/null +++ b/quantpy/ml/time_series.py @@ -0,0 +1,15 @@ +'''Models.''' + +''' +Ideas: + Regression/Time-series: + - ARIMA + - ARFIMA + - Seasonal Models (SARIMA, Winters) + - Spectral Analysis + - +''' + +import pandas as pd +from statsmodels.tsa.arima.model import ARIMA + From 50bd233b1a507b271df2b5d93c9a99ba03addffd Mon Sep 17 00:00:00 2001 From: Ammar Siddiqui Date: Mon, 22 May 2023 18:45:46 -0400 Subject: [PATCH 2/4] added new time series regression model --- quantpy/ml/models.py | 45 +++++++++++++++++++++++++++++++++++++++ quantpy/ml/time_series.py | 11 ++++++++++ 2 files changed, 56 insertions(+) create mode 100644 quantpy/ml/models.py diff --git a/quantpy/ml/models.py b/quantpy/ml/models.py new file mode 100644 index 0000000..9eaace8 --- /dev/null +++ b/quantpy/ml/models.py @@ -0,0 +1,45 @@ +import numpy as np +from pandas import DataFrame, Series +from typing import Union, Optional, Tuple, List +from sklearn.base import RegressorMixin +from statsmodels.base.models import Model as StatsModel +from statsmodels.tsa.arima.model import ARIMA + +class BenchmarkRegressor(): + ''' + Default Regression Model based on ARIMA (Auto-Regressive Integrated Moving + Averages). Aims to provide a basic compute-efficient time-series model to + make predictions. (Aim to beat this model's prediction accuracy) + ''' + def __init__( + self, + data: Union[DataFrame, Series], + param: Tuple[int, int, int] = (5, 2, 0) + ) -> None: + + self.model = ARIMA(data, order=param) + self.model_fit = self.model.fit(data) + self.residuals = DataFrame(self.model_fit.resid) + + + def describe_residuals(self) -> DataFrame: + return self.residuals.describe() + + + def plot_residuals(self) -> None: + self.residuals().plot() + + + def cross_validate( + self, + comparision_model: Optional[Union[ + List, + RegressorMixin, + StatsModel + ]] + ) -> None: + ... + + + def predict(self) -> np.float64: + ... diff --git a/quantpy/ml/time_series.py b/quantpy/ml/time_series.py index 188c27c..bb7b310 100644 --- a/quantpy/ml/time_series.py +++ b/quantpy/ml/time_series.py @@ -8,8 +8,19 @@ - Seasonal Models (SARIMA, Winters) - Spectral Analysis - + + - Brownian Motion + - Martingale + Random Walk + - Monte-Carlo + - Stochastic Calculus for Finance (Discrete and Continuous) + - Implied Volatility + - Black Scholes + - Merton + - Markov + - ''' import pandas as pd from statsmodels.tsa.arima.model import ARIMA + From a751c37ac942953a0ff75dd6e5b4ffd159506658 Mon Sep 17 00:00:00 2001 From: Ammar Siddiqui Date: Thu, 25 May 2023 19:15:45 -0400 Subject: [PATCH 3/4] added garch model and exceptions --- quantpy/ml/exceptions.py | 8 ++ quantpy/ml/models.py | 45 ---------- quantpy/ml/time_series.py | 167 ++++++++++++++++++++++++++++++++------ setup.py | 4 + 4 files changed, 156 insertions(+), 68 deletions(-) create mode 100644 quantpy/ml/exceptions.py delete mode 100644 quantpy/ml/models.py diff --git a/quantpy/ml/exceptions.py b/quantpy/ml/exceptions.py new file mode 100644 index 0000000..55e66eb --- /dev/null +++ b/quantpy/ml/exceptions.py @@ -0,0 +1,8 @@ +class ModelNotFittedError(Exception): + ... + +class ModelTypeNotSupportedError(Exception): + ... + +class DataTypeNotSupportedError(Exception): + ... \ No newline at end of file diff --git a/quantpy/ml/models.py b/quantpy/ml/models.py deleted file mode 100644 index 9eaace8..0000000 --- a/quantpy/ml/models.py +++ /dev/null @@ -1,45 +0,0 @@ -import numpy as np -from pandas import DataFrame, Series -from typing import Union, Optional, Tuple, List -from sklearn.base import RegressorMixin -from statsmodels.base.models import Model as StatsModel -from statsmodels.tsa.arima.model import ARIMA - -class BenchmarkRegressor(): - ''' - Default Regression Model based on ARIMA (Auto-Regressive Integrated Moving - Averages). Aims to provide a basic compute-efficient time-series model to - make predictions. (Aim to beat this model's prediction accuracy) - ''' - def __init__( - self, - data: Union[DataFrame, Series], - param: Tuple[int, int, int] = (5, 2, 0) - ) -> None: - - self.model = ARIMA(data, order=param) - self.model_fit = self.model.fit(data) - self.residuals = DataFrame(self.model_fit.resid) - - - def describe_residuals(self) -> DataFrame: - return self.residuals.describe() - - - def plot_residuals(self) -> None: - self.residuals().plot() - - - def cross_validate( - self, - comparision_model: Optional[Union[ - List, - RegressorMixin, - StatsModel - ]] - ) -> None: - ... - - - def predict(self) -> np.float64: - ... diff --git a/quantpy/ml/time_series.py b/quantpy/ml/time_series.py index bb7b310..7936d35 100644 --- a/quantpy/ml/time_series.py +++ b/quantpy/ml/time_series.py @@ -1,26 +1,147 @@ -'''Models.''' - -''' -Ideas: - Regression/Time-series: - - ARIMA - - ARFIMA - - Seasonal Models (SARIMA, Winters) - - Spectral Analysis - - - - - Brownian Motion - - Martingale + Random Walk - - Monte-Carlo - - Stochastic Calculus for Finance (Discrete and Continuous) - - Implied Volatility - - Black Scholes - - Merton - - Markov - - -''' - -import pandas as pd +import numpy as np +from pandas import DataFrame, Series +from typing import Union, Optional, Tuple, List +from sklearn.base import RegressorMixin +from statsmodels.base.models import Model as StatsModel from statsmodels.tsa.arima.model import ARIMA +from arch import arch_model + +from exceptions import ( + ModelNotFittedError, + ModelTypeNotSupportedError, + DataTypeNotSupportedError +) + +class BenchmarkRegressor(): + ''' + Default Regression Model based on ARIMA (Auto-Regressive Integrated Moving + Averages). Aims to provide a basic compute-efficient time-series model to + make predictions. (Aim to beat this model's prediction accuracy) + ''' + def __init__( + self, + data: Union[DataFrame, Series], + param: Tuple[int, int, int] = (5, 2, 0), + fit: bool = True, + seasonal: bool = False, + bias: Optional[float] = None + ) -> None: + self.data = data + self.param = param + self.model = ARIMA(data, order=param) + self.bias = bias if bias else 0 + if fit: + self.model_fit = self.model.fit(data + bias) + self.residuals = DataFrame(self.model_fit.resid) + + + def get_model(self) -> StatsModel: + return self.model + + + def get_summary(self) -> None: + self.model.summary() + + + def get_data(self) -> DataFrame: + return self.data + + + def get_params(self) -> Tuple: + return self.params + + + def fit(self): + self.model_fit = self.model.fit(self.data + self.bias) + self.residuals = DataFrame(self.model_fit.resid) + + + def describe_residuals(self) -> DataFrame: + if not self.residuals: + raise ModelNotFittedError() + return self.residuals.describe() + + + def plot_residuals(self) -> None: + if not self.residuals: + raise ModelNotFittedError() + self.residuals.plot() + + + def cross_validate( + self, + comparision_model: Optional[Union[ + List, + RegressorMixin, + StatsModel + ]] + ) -> None: + '''Validate based on data or compare to other models''' + ... + + + def predict(self, horizon: Union[int, Tuple] = None) -> np.float64: + if not self.model_fit: + raise ModelNotFittedError() + if type(horizon) == int: + return self.model_fit.forecast(steps=horizon)[0] + elif type(horizon) == tuple: + return self.model_fit.predict(start=horizon[0], end=horizon[1]) + else: + return self.model_fit.forecast()[0] + + +class GARCH(): + ''' + Default GARCH (Generalized Auto-Regressive Conditional Heteroskedasticity) + model to find forecasts based on changes of variances in a time-series. + Useful for Volatility. + ''' + def __init__( + self, + data: Union[DataFrame, Series], + p: int = 1, + q: int = 1, + fit: bool = True + ) -> None: + self.data = data + self.p, self.q = p, q + self.model = arch_model(data, mean='Zero', vol='GARCH', p=p, q=q) + if fit: + self.model_fit = self.model.fit() + + + def get_model(self) -> arch_model: + return self.model + + + def get_data(self) -> DataFrame: + return self.data + + + def get_params(self) -> Tuple: + return self.p, self.q + + + def fit(self): + self.model_fit = self.model.fit() + + + def cross_validate( + self, + comparision_model: Optional[Union[ + List, + RegressorMixin, + StatsModel + ]] + ) -> None: + '''Validate based on data or compare to other models''' + ... + + + def predict(self, horizon: Union[DataFrame, Series]) -> Series: + if not self.model_fit: + raise ModelNotFittedError() + return self.model_fit.forecast(horizon=horizon) diff --git a/setup.py b/setup.py index b6b0967..bc9a2b1 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,11 @@ description='A framework for quantitative finance In python', long_description=open('README.md').read(), install_requires=[ + "numpy >= 1.23.5", "pandas >= 0.10.0", "matplotlib >= 1.1.0", + "statsmodels >= 0.14.0", + "arch >= 6.0.1", + "sklearn >= 1.1.0", ], ) From 5319361eb48dabb5953f7d98201017b7a13a2a63 Mon Sep 17 00:00:00 2001 From: Ammar Siddiqui Date: Thu, 25 May 2023 19:22:37 -0400 Subject: [PATCH 4/4] updated sklearn version --- quantpy/ml/exceptions.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/quantpy/ml/exceptions.py b/quantpy/ml/exceptions.py index 55e66eb..d4d9a08 100644 --- a/quantpy/ml/exceptions.py +++ b/quantpy/ml/exceptions.py @@ -5,4 +5,4 @@ class ModelTypeNotSupportedError(Exception): ... class DataTypeNotSupportedError(Exception): - ... \ No newline at end of file + ... diff --git a/setup.py b/setup.py index bc9a2b1..59851f7 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,6 @@ "matplotlib >= 1.1.0", "statsmodels >= 0.14.0", "arch >= 6.0.1", - "sklearn >= 1.1.0", + "scikit-learn >= 1.1.0", ], )