SPB Git

spb/wp41_uqo

Public
4.8 KB · 99 lines python
1"""Ridge / elastic-net and LightGBM baselines on hand-crafted origin features (identical information set).2Targets: (i) cumulative H-minute return (location), (ii) log realised variance over H (scale). Predictive3distribution: Student-t with location from the mean model (ridge/LGBM), scale from exp(log-variance model) and nu4from the kurtosis of standardised training residuals (clipped to [2.5, 50])."""5from __future__ import annotations67import numpy as np89from ..data.windows import SymbolGrid, N_DAY10from .naive import _hist_returns1112FEATURE_NAMES = ["log_rv30", "log_rv390", "log_rv5d", "ret30", "ret390", "ret_day", "overnight", "relvol30",13                 "range30", "minute_frac", "time_to_close", "weekday", "early_close", "log_sigma", "skew390", "kurt390",14                 "sign_last", "ret5", "rv_ratio_30_390"]151617def origin_features(g: SymbolGrid, s: int, m: int, sigma: float) -> np.ndarray | None:18    r, sl = _hist_returns(g, s, m, 6)19    if len(r) < 60:20        return None21    r30, r390, r5 = r[-30:], r[-390:], r[-5:]22    lc_today = g.flat_lc[s * N_DAY: s * N_DAY + m + 1]23    ok = ~np.isnan(lc_today)24    ret_day = float(lc_today[ok][-1] - lc_today[ok][0]) if ok.sum() >= 2 else 0.025    gap = g.gap[s]; gap = 0.0 if np.isnan(gap) else float(gap)26    base = g.flat_base[s * N_DAY + max(0, m - 29): s * N_DAY + m + 1]; mk = g.flat_mask[s * N_DAY + max(0, m - 29): s * N_DAY + m + 1]27    seas = g.flat_seas[s * N_DAY + max(0, m - 29): s * N_DAY + m + 1]28    rel = base[mk, 4] - seas[mk]; rel = rel[~np.isnan(rel)]29    relvol30 = float(rel.mean()) if len(rel) else 0.030    rng30 = float((base[mk, 1] - base[mk, 2]).mean()) if mk.any() else 0.031    sd390 = r390.std() + 1e-1232    f = [np.log(np.mean(r30 ** 2) + 1e-12), np.log(np.mean(r390 ** 2) + 1e-12), np.log(np.mean(r ** 2) + 1e-12),33         r30.sum() / sigma, r390.sum() / sigma, ret_day / sigma, gap / sigma, relvol30, rng30 / sigma, m / 389.0,34         (g.n_slots[s] - 1 - m) / 389.0, g.weekday[s] / 4.0, float(g.early[s]), np.log(sigma),35         float(np.mean(((r390 - r390.mean()) / sd390) ** 3)), float(np.mean(((r390 - r390.mean()) / sd390) ** 4)),36         float(np.sign(r[-1])), r5.sum() / sigma, np.log((np.mean(r30 ** 2) + 1e-12) / (np.mean(r390 ** 2) + 1e-12))]37    return np.array(f, dtype=np.float64)383940class _TwoPart:41    """Common fit/predict for location + log-variance models with Student-t assembly."""4243    def __init__(self, name: str):44        self.name = name45        self.loc: dict[int, object] = {}; self.lv: dict[int, object] = {}; self.nu: dict[int, float] = {}46        self.scaler = None4748    def _new(self):49        raise NotImplementedError5051    def fit(self, X: np.ndarray, cum: np.ndarray, rv: np.ndarray, sigma: np.ndarray, H: int, Xv=None, cumv=None, rvv=None, sigv=None) -> None:52        y_loc = cum / sigma53        y_lv = np.log(rv / sigma ** 2 + 1e-9)54        self.loc[H] = self._new().fit(X, y_loc)55        self.lv[H] = self._new().fit(X, y_lv)56        var = np.exp(self.lv[H].predict(X)) * sigma ** 257        z = (cum - self.loc[H].predict(X) * sigma) / np.sqrt(var)58        k = float(np.mean(z ** 4) / np.mean(z ** 2) ** 2)59        self.nu[H] = float(np.clip(4 + 6 / max(k - 3, 0.12), 2.5, 50))6061    def predict_batch(self, X: np.ndarray, sigma: np.ndarray, H: int) -> dict:62        mu = self.loc[H].predict(X) * sigma63        var = np.exp(self.lv[H].predict(X)) * sigma ** 264        nu = self.nu[H]65        return {"mu": mu, "scale": np.sqrt(var * (nu - 2) / nu), "nu": np.full(len(X), nu), "var": var}666768class RidgeBaseline(_TwoPart):69    def __init__(self, alpha: float = 1.0):70        super().__init__("ridge"); self.alpha = alpha7172    def _new(self):73        from sklearn.linear_model import Ridge74        from sklearn.pipeline import make_pipeline75        from sklearn.preprocessing import StandardScaler76        return make_pipeline(StandardScaler(), Ridge(alpha=self.alpha))777879class ElasticNetBaseline(_TwoPart):80    def __init__(self, alpha: float = 1e-3, l1_ratio: float = 0.5):81        super().__init__("elastic_net"); self.alpha, self.l1 = alpha, l1_ratio8283    def _new(self):84        from sklearn.linear_model import ElasticNet85        from sklearn.pipeline import make_pipeline86        from sklearn.preprocessing import StandardScaler87        return make_pipeline(StandardScaler(), ElasticNet(alpha=self.alpha, l1_ratio=self.l1, max_iter=5000))888990class LightGBMBaseline(_TwoPart):91    def __init__(self, n_estimators: int = 400, learning_rate: float = 0.03, num_leaves: int = 31, seed: int = 0):92        super().__init__("lightgbm"); self.kw = dict(n_estimators=n_estimators, learning_rate=learning_rate,93                                                     num_leaves=num_leaves, subsample=0.8, subsample_freq=1,94                                                     colsample_bytree=0.8, random_state=seed, verbose=-1, n_jobs=8)9596    def _new(self):97        import lightgbm as lgb98        return lgb.LGBMRegressor(**self.kw)99
Files · main
Menu

Theme