Source code for finance_risk.cross_asset

from __future__ import annotations

from typing import Any

import numpy as np
from pydantic import BaseModel, ConfigDict

from . import finance_risk as _native

__all__ = ["CointegrationSpread", "cointegration_spread", "rolling_correlation", "transfer_entropy"]


[docs] class CointegrationSpread(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True) hedge_ratio: float intercept: float spread: np.ndarray
def _vector(values: Any) -> np.ndarray: if hasattr(values, "to_numpy"): arr = values.to_numpy() else: arr = np.asarray(values) arr = np.asarray(arr, dtype=float).reshape(-1) if arr.size == 0: raise ValueError("values must not be empty") return arr
[docs] def rolling_correlation(x: Any, y: Any, *, window: int) -> np.ndarray: """Rolling Pearson correlation with leading ``nan`` values before the first full window.""" left = _vector(x) right = _vector(y) if left.shape != right.shape: raise ValueError("x and y must have the same length") return np.asarray(_native.rolling_correlation(left.tolist(), right.tolist(), window), dtype=float)
[docs] def cointegration_spread(y: Any, x: Any) -> CointegrationSpread: """OLS hedge ratio and demeaned residual spread for a two-asset pair.""" dependent = _vector(y) independent = _vector(x) if dependent.shape != independent.shape: raise ValueError("x and y must have the same length") hedge_ratio, intercept, spread = _native.cointegration_spread(dependent.tolist(), independent.tolist()) return CointegrationSpread(hedge_ratio=float(hedge_ratio), intercept=float(intercept), spread=np.asarray(spread, dtype=float))
[docs] def transfer_entropy(source: Any, target: Any, *, bins: int = 3, lag: int = 1) -> float: """Discrete transfer entropy ``source[t-lag] -> target[t]`` in nats.""" src = _vector(source) tgt = _vector(target) if src.shape != tgt.shape: raise ValueError("source and target must have the same length") return float(_native.transfer_entropy(src.tolist(), tgt.tolist(), bins, lag))