summaryrefslogtreecommitdiff
path: root/src/teradata/stock.py
diff options
context:
space:
mode:
authorMikka Petterson <m.petterson@student.maastrichtuniversity.nl>2026-10-14 07:45:20 +0200
committerMikka Petterson <m.petterson@student.maastrichtuniversity.nl>2026-10-14 07:45:20 +0200
commit0bcc5be35b6a99109bd04925c22890347c9d6e88 (patch)
treefdd88728ad1747268b0a02aba0de08a3af6a52b2 /src/teradata/stock.py
Initial commitHEADmain
Diffstat (limited to 'src/teradata/stock.py')
-rw-r--r--src/teradata/stock.py62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/teradata/stock.py b/src/teradata/stock.py
new file mode 100644
index 0000000..58d34b4
--- /dev/null
+++ b/src/teradata/stock.py
@@ -0,0 +1,62 @@
+lazy from typing import Self
+
+from attrs import frozen
+lazy import yfinance
+lazy from pandas import DataFrame
+
+from .cache import persistent
+
+
+@frozen
+class Tickers:
+ prices: DataFrame
+
+ @property
+ def normalized(self: Self) -> DataFrame:
+ """Indexed to 100 at t_0."""
+ return (self.prices / self.prices.iloc[0]) * 100
+
+ @property
+ def cumulative_returns(self: Self) -> DataFrame:
+ """Percentage gain/loss since t_0."""
+ return ((self.prices / self.prices.iloc[0]) - 1) * 100
+
+
+@frozen
+class ValuationSnapshot:
+ ticker: str
+ ev_to_sales: float | None = None
+ revenue_growth_yoy: float | None = None
+ ev_to_fcf: float | None = None
+ trailing_pe: float | None = None
+ forward_pe: float | None = None
+
+
+@persistent
+def get_stock_data(tickers: list[str], start: str) -> DataFrame:
+ data = yfinance.download(tickers, start=start)
+ if data is None:
+ raise ValueError(f"Yahoo Finance data for {tickers} from {start} is None")
+
+ return data
+
+
+@persistent
+def get_valuation_snapshot(ticker: str) -> ValuationSnapshot:
+ y_ticker = yfinance.Ticker(ticker)
+
+ info = y_ticker.info
+ ev = info.get("enterpriseValue")
+ fcf = info.get("freeCashflow")
+ ev_fcf = (ev / fcf) if (ev and fcf and fcf > 0) else None
+
+ return ValuationSnapshot(
+ ticker=ticker,
+ ev_to_sales=info.get("enterpriseToRevenue"),
+ revenue_growth_yoy=(
+ info.get("revenueGrowth", 0.0) * 100
+ if info.get("revenueGrowth") is not None
+ else None
+ ),
+ ev_to_fcf=ev_fcf,
+ )