Source code for tensorquantlib.data.market

"""Market data wrappers using yfinance.

All functions require the ``yfinance`` package, which is an optional
dependency installable via ``pip install tensorquantlib[data]``.
"""

from __future__ import annotations

import numpy as np


def _import_yfinance():
    """Lazy import of yfinance with a helpful error message."""
    try:
        import yfinance as yf

        return yf
    except ImportError:
        raise ImportError(
            "yfinance is required for market data functions. "
            "Install it with: pip install tensorquantlib[data]"
        ) from None


[docs] def get_stock_price(ticker: str) -> float: """Get the latest closing price for a ticker. Parameters ---------- ticker : str Stock ticker symbol (e.g. ``'AAPL'``). Returns ------- float Most recent closing price. """ yf = _import_yfinance() t = yf.Ticker(ticker) hist = t.history(period="1d") if hist.empty: raise ValueError(f"No data returned for ticker '{ticker}'") return float(hist["Close"].iloc[-1])
[docs] def get_historical_prices(ticker: str, start: str, end: str) -> dict: """Fetch historical OHLCV data. Parameters ---------- ticker : str Stock ticker symbol. start : str Start date ``'YYYY-MM-DD'``. end : str End date ``'YYYY-MM-DD'``. Returns ------- dict Keys: ``'dates'``, ``'open'``, ``'high'``, ``'low'``, ``'close'``, ``'volume'`` — each a numpy array. """ yf = _import_yfinance() t = yf.Ticker(ticker) hist = t.history(start=start, end=end) if hist.empty: raise ValueError(f"No data returned for ticker '{ticker}'") return { "dates": hist.index.to_numpy(), "open": hist["Open"].to_numpy(), "high": hist["High"].to_numpy(), "low": hist["Low"].to_numpy(), "close": hist["Close"].to_numpy(), "volume": hist["Volume"].to_numpy(), }
[docs] def get_options_chain(ticker: str, expiry: str | None = None) -> dict: """Fetch options chain data. Parameters ---------- ticker : str Stock ticker symbol. expiry : str, optional Expiry date ``'YYYY-MM-DD'``. If *None*, uses the nearest expiry. Returns ------- dict Keys: ``'calls'`` and ``'puts'``, each a dict with numpy arrays for ``'strike'``, ``'lastPrice'``, ``'bid'``, ``'ask'``, ``'impliedVolatility'``, ``'volume'``, ``'openInterest'``. """ yf = _import_yfinance() t = yf.Ticker(ticker) if expiry is None: expiries = t.options if not expiries: raise ValueError(f"No options available for '{ticker}'") expiry = expiries[0] chain = t.option_chain(expiry) def _extract(df): cols = ["strike", "lastPrice", "bid", "ask", "impliedVolatility", "volume", "openInterest"] return {c: df[c].to_numpy() for c in cols if c in df.columns} return {"calls": _extract(chain.calls), "puts": _extract(chain.puts)}
[docs] def historical_volatility(ticker: str, window: int = 252, annualize: bool = True) -> float: """Compute realised historical volatility from daily close prices. Parameters ---------- ticker : str Stock ticker symbol. window : int Number of trading days to look back. annualize : bool If True, return annualised volatility. Returns ------- float Historical volatility. """ yf = _import_yfinance() t = yf.Ticker(ticker) hist = t.history(period=f"{window}d") if len(hist) < 2: raise ValueError(f"Insufficient data for ticker '{ticker}'") prices = hist["Close"].to_numpy() log_returns = np.log(prices[1:] / prices[:-1]) vol = float(np.std(log_returns, ddof=1)) if annualize: vol *= np.sqrt(252) return vol
[docs] def get_risk_free_rate() -> float: """Get approximate risk-free rate from 13-week US Treasury yield. Uses the ``^IRX`` ticker (CBOE 13-week T-Bill) as a proxy. Returns ------- float Annualised risk-free rate (e.g. 0.05 for 5%). """ yf = _import_yfinance() t = yf.Ticker("^IRX") hist = t.history(period="5d") if hist.empty: raise ValueError("Could not fetch Treasury rate data") # ^IRX is quoted as a percentage (e.g. 5.25 means 5.25%) return float(hist["Close"].iloc[-1]) / 100.0