mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 20:42:26 +00:00
* refactor quantitative for v5 * add factors endpoint and add a few charts --------- Co-authored-by: deeleeramone <>
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
"""Helper functions for the quantitative extension."""
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from pandas import DataFrame, Series
|
|
|
|
_FAMA_FRENCH_FACTORS_URL = (
|
|
"https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/"
|
|
"F-F_Research_Data_Factors_CSV.zip"
|
|
)
|
|
|
|
|
|
def get_fama_raw(start_date: str, end_date: str) -> "DataFrame":
|
|
"""Download the Fama-French research factors for a date range.
|
|
|
|
Returns a DataFrame indexed by date with the excess market return ('mkt_rf'),
|
|
size ('smb'), value ('hml'), and risk-free ('rf') factors as decimal fractions.
|
|
"""
|
|
from io import BytesIO
|
|
from urllib.request import urlopen
|
|
from zipfile import ZipFile
|
|
|
|
from pandas import read_csv, to_datetime, to_numeric
|
|
|
|
with (
|
|
urlopen(_FAMA_FRENCH_FACTORS_URL) as response, # noqa: S310
|
|
ZipFile(BytesIO(response.read())) as archive,
|
|
archive.open("F-F_Research_Data_Factors.csv") as handle,
|
|
):
|
|
df = read_csv(
|
|
handle,
|
|
header=0,
|
|
names=["date", "mkt_rf", "smb", "hml", "rf"],
|
|
skiprows=3,
|
|
)
|
|
|
|
df = df[df["date"].apply(lambda value: len(str(value).strip()) == 6)]
|
|
df["date"] = to_datetime(df["date"].astype(str) + "01", format="%Y%m%d")
|
|
for column in ("mkt_rf", "smb", "hml", "rf"):
|
|
df[column] = to_numeric(df[column], downcast="float") / 100
|
|
df = df.set_index("date")
|
|
|
|
if to_datetime(start_date) > df.index.max():
|
|
raise ValueError(
|
|
f"Start date '{start_date}' is after the last available Fama-French"
|
|
f" observation '{df.index.max().date()}'."
|
|
)
|
|
|
|
return df.loc[start_date:end_date]
|
|
|
|
|
|
def validate_window(input_data: "Series | DataFrame", window: int) -> None:
|
|
"""Raise a ValueError when the rolling window exceeds the data length."""
|
|
if window > len(input_data):
|
|
raise ValueError(
|
|
f"Window '{window}' is larger than the data length '{len(input_data)}'."
|
|
)
|