summaryrefslogtreecommitdiffstats
path: root/openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py
diff options
context:
space:
mode:
Diffstat (limited to 'openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py')
-rw-r--r--openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py363
1 files changed, 12 insertions, 351 deletions
diff --git a/openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py b/openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py
index a381da937cb..bede1e9ac84 100644
--- a/openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py
+++ b/openbb_platform/extensions/quantitative/openbb_quantitative/quantitative_router.py
@@ -2,32 +2,37 @@
from typing import List, Literal
-import numpy as np
import pandas as pd
from openbb_core.app.model.obbject import OBBject
from openbb_core.app.router import Router
from openbb_core.app.utils import (
basemodel_to_df,
- df_to_basemodel,
get_target_column,
get_target_columns,
)
from openbb_core.provider.abstract.data import Data
-from pydantic import NonNegativeFloat, PositiveInt
-from .helpers import get_fama_raw, validate_window
+from openbb_quantitative.performance.performance_router import (
+ router as performance_router,
+)
+from openbb_quantitative.rolling.rolling_router import router as rolling_router
+from openbb_quantitative.stats.stats_router import router as stats_router
+
+from .helpers import get_fama_raw
from .models import (
ADFTestModel,
CAPMModel,
KPSSTestModel,
NormalityModel,
- OmegaModel,
SummaryModel,
TestModel,
UnitRootModel,
)
router = Router(prefix="")
+router.include_router(rolling_router)
+router.include_router(stats_router)
+router.include_router(performance_router)
@router.command(
@@ -137,120 +142,7 @@ def capm(data: List[Data], target: str) -> OBBject[CAPMModel]:
return OBBject(results=results)
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.omega_ratio(data=stock_data, target='close')",
- ],
-)
-def omega_ratio(
- data: List[Data],
- target: str,
- threshold_start: float = 0.0,
- threshold_end: float = 1.5,
-) -> OBBject[List[OmegaModel]]:
- """Calculate the Omega Ratio.
-
- The Omega Ratio is a sophisticated metric that goes beyond traditional performance measures by considering the
- probability of achieving returns above a given threshold. It offers a more nuanced view of risk and reward,
- focusing on the likelihood of success rather than just average outcomes.
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- threshold_start : float, optional
- Start threshold, by default 0.0
- threshold_end : float, optional
- End threshold, by default 1.5
-
- Returns
- -------
- OBBject[List[OmegaModel]]
- Omega ratios.
- """
- df = basemodel_to_df(data)
- series_target = get_target_column(df, target)
-
- epsilon = 1e-6 # to avoid division by zero
-
- def get_omega_ratio(df_target: pd.Series, threshold: float) -> float:
- """Get omega ratio."""
- daily_threshold = (threshold + 1) ** np.sqrt(1 / 252) - 1
- excess = df_target - daily_threshold
- numerator = excess[excess > 0].sum()
- denominator = -excess[excess < 0].sum() + epsilon
-
- return numerator / denominator
-
- threshold = np.linspace(threshold_start, threshold_end, 50)
- results = []
- for i in threshold:
- omega_ = get_omega_ratio(series_target, i)
- results.append(OmegaModel(threshold=i, omega=omega_))
-
- return OBBject(results=results)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.kurtosis(data=stock_data, target='close', window=252)",
- ],
-)
-def kurtosis(
- data: List[Data], target: str, window: PositiveInt = 21, index: str = "date"
-) -> OBBject[List[Data]]:
- """Get the rolling Kurtosis.
-
- Kurtosis provides insights into the shape of the data's distribution, particularly the heaviness of its tails.
- Kurtosis is a statistical measure that reveals whether the data points tend to cluster around the mean or if
- outliers are more common than a normal distribution would suggest. A higher kurtosis indicates more data points are
- found in the tails, suggesting potential volatility or risk.
- This analysis is crucial for understanding the underlying characteristics of your data, helping to anticipate
- extreme events or anomalies over a specified window of time.
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- window : PositiveInt
- Window size.
- index : str, optional
- Index column name, by default "date"
-
- Returns
- -------
- OBBject[List[Data]]
- Kurtosis.
- """
- import pandas_ta as ta # pylint: disable=import-outside-toplevel # type: ignore
-
- df = basemodel_to_df(data, index=index)
- series_target = get_target_column(df, target)
- validate_window(series_target, window)
- results = (
- ta.kurtosis(close=series_target, length=window).dropna().reset_index(drop=False)
- )
- results = df_to_basemodel(results)
-
- return OBBject(results=results)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.unitroot_test(data=stock_data, target='close')",
- 'obb.quantitative.unitroot_test(data=stock_data, target="close", fuller_reg="ct", kpss_reg="ct")',
- ],
-)
+@router.command(methods=["POST"])
def unitroot_test(
data: List[Data],
target: str,
@@ -309,238 +201,7 @@ def unitroot_test(
return OBBject(results=unitroot_summary)
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.sharpe_ratio(data=stock_data, target='close')",
- "obb.quantitative.sharpe_ratio(data=stock_data, target='close', rfr=0.01, window=126)",
- ],
-)
-def sharpe_ratio(
- data: List[Data],
- target: str,
- rfr: float = 0.0,
- window: PositiveInt = 252,
- index: str = "date",
-) -> OBBject[List[Data]]:
- """Get Rolling Sharpe Ratio.
-
- This function calculates the Sharpe Ratio, a metric used to assess the return of an investment compared to its risk.
- By factoring in the risk-free rate, it helps you understand how much extra return you're getting for the extra
- volatility that you endure by holding a riskier asset. The Sharpe Ratio is essential for investors looking to
- compare the efficiency of different investments, providing a clear picture of potential rewards in relation to their
- risks over a specified period. Ideal for gauging the effectiveness of investment strategies, it offers insights into
- optimizing your portfolio for maximum return on risk.
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- rfr : float, optional
- Risk-free rate, by default 0.0
- window : PositiveInt, optional
- Window size, by default 252
- index : str, optional
-
- Returns
- -------
- OBBject[List[Data]]
- Sharpe ratio.
- """
- df = basemodel_to_df(data, index=index)
- series_target = get_target_column(df, target)
- validate_window(series_target, window)
- series_target.name = f"sharpe_{window}"
- returns = series_target.pct_change().dropna().rolling(window).sum()
- std = series_target.rolling(window).std() / np.sqrt(window)
- results = ((returns - rfr) / std).dropna().reset_index(drop=False)
-
- results = df_to_basemodel(results)
-
- return OBBject(results=results)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.sortino_ratio(data=stock_data, target='close')",
- "obb.quantitative.sortino_ratio(data=stock_data, target='close', target_return=0.01, window=126, adjusted=True)",
- ],
-)
-def sortino_ratio(
- data: List[Data],
- target: str,
- target_return: float = 0.0,
- window: PositiveInt = 252,
- adjusted: bool = False,
- index: str = "date",
-) -> OBBject[List[Data]]:
- """Get rolling Sortino Ratio.
-
- The Sortino Ratio enhances the evaluation of investment returns by distinguishing harmful volatility
- from total volatility. Unlike other metrics that treat all volatility as risk, this command specifically assesses
- the volatility of negative returns relative to a target or desired return.
- It's particularly useful for investors who are more concerned with downside risk than with overall volatility.
- By calculating the Sortino Ratio, investors can better understand the risk-adjusted return of their investments,
- focusing on the likelihood and impact of negative returns.
- This approach offers a more nuanced tool for portfolio optimization, especially in strategies aiming
- to minimize the downside.
-
- For method & terminology see:
- http://www.redrockcapital.com/Sortino__A__Sharper__Ratio_Red_Rock_Capital.pdf
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- target_return : float, optional
- Target return, by default 0.0
- window : PositiveInt, optional
- Window size, by default 252
- adjusted : bool, optional
- Adjust sortino ratio to compare it to sharpe ratio, by default False
- index:str
- Index column for input data
- Returns
- -------
- OBBject[List[Data]]
- Sortino ratio.
- """
- df = basemodel_to_df(data, index=index)
- series_target = get_target_column(df, target)
- validate_window(series_target, window)
- returns = series_target.pct_change().dropna().rolling(window).sum()
- downside_deviation = returns.rolling(window).apply(
- lambda x: (x.values[x.values < 0]).std() / np.sqrt(252) * 100
- )
- results = (
- ((returns - target_return) / downside_deviation)
- .dropna()
- .reset_index(drop=False)
- )
-
- if adjusted:
- results = results / np.sqrt(2)
-
- results_ = df_to_basemodel(results)
-
- return OBBject(results=results_)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.skewness(data=stock_data, target='close', window=252)",
- ],
-)
-def skewness(
- data: List[Data], target: str, window: PositiveInt = 21, index: str = "date"
-) -> OBBject[List[Data]]:
- """Get Rolling Skewness.
-
- Skewness is a statistical measure that reveals the degree of asymmetry of a distribution around its mean.
- Positive skewness indicates a distribution with an extended tail to the right, while negative skewness shows a tail
- that stretches left. Understanding skewness can provide insights into potential biases in data and help anticipate
- the nature of future data points. It's particularly useful for identifying the likelihood of extreme outcomes in
- financial returns, enabling more informed decision-making based on the distribution's shape over a specified period.
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- window : PositiveInt
- Window size.
- index : str, optional
- Index column name, by default "date"
- Returns
- -------
- OBBject[List[Data]]
- Skewness.
- """
- import pandas_ta as ta # pylint: disable=import-outside-toplevel # type: ignore
-
- df = basemodel_to_df(data, index=index)
- series_target = get_target_column(df, target)
- validate_window(series_target, window)
- results = (
- ta.skew(close=series_target, length=window).dropna().reset_index(drop=False)
- )
- results = df_to_basemodel(results)
-
- return OBBject(results=results)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- 'obb.quantitative.quantile(data=stock_data, target="close", window=252, quantile_pct=0.25)',
- "obb.quantitative.quantile(data=stock_data, target='close', window=252, quantile_pct=0.75)",
- ],
-)
-def quantile(
- data: List[Data],
- target: str,
- window: PositiveInt = 21,
- quantile_pct: NonNegativeFloat = 0.5,
- index: str = "date",
-) -> OBBject[List[Data]]:
- """Get Rolling Quantile.
-
- Quantile is a statistical measure that identifies the value below which a given percentage of observations in a
- group of data falls. By setting the quantile percentage, you can determine any point in the distribution, not just
- the median. Whether you're interested in the median, quartiles, or any other position within your data's range,
- this tool offers a precise way to understand the distribution's characteristics.
- It's especially useful for identifying outliers, understanding dispersion, and setting thresholds for
- decision-making based on the distribution of data over a specified period.
-
- Parameters
- ----------
- data : List[Data]
- Time series data.
- target : str
- Target column name.
- window : PositiveInt
- Window size.
- quantile_pct : NonNegativeFloat, optional
- Quantile to get
- Returns
- -------
- OBBject[List[Data]]
- Quantile.
- """
- import pandas_ta as ta # pylint: disable=import-outside-toplevel # type: ignore
-
- df = basemodel_to_df(data, index=index)
- series_target = get_target_column(df, target)
- validate_window(series_target, window)
- df_median = ta.median(close=series_target, length=window).to_frame()
- df_quantile = ta.quantile(series_target, length=window, q=quantile_pct).to_frame()
- results = (
- pd.concat([df_median, df_quantile], axis=1).dropna().reset_index(drop=False)
- )
-
- results_ = df_to_basemodel(results)
-
- return OBBject(results=results_)
-
-
-@router.command(
- methods=["POST"],
- examples=[
- "stock_data = obb.equity.price.historical(symbol='TSLA', start_date='2023-01-01', provider='fmp').to_df()",
- "obb.quantitative.volatility(data=stock_data, target='close')",
- ],
-)
+@router.command(methods=["POST"])
def summary(data: List[Data], target: str) -> OBBject[SummaryModel]:
"""Get Summary Statistics.