Spaces:
Build error
Build error
Download models/base_model.py from 3VVM/MYTHOSLIVE: direct link, hf CLI and curl.
- Browser
- Download file 4.58 kB
-
https://huggingface.co/spaces/3VVM/MYTHOSLIVE/resolve/main/models/base_model.py
- Command line
-
hf download hf://spaces/3VVM/MYTHOSLIVE/models/base_model.py
-
curl -L -o base_model.py https://huggingface.co/spaces/3VVM/MYTHOSLIVE/resolve/main/models/base_model.py
4.58 kB
| import numpy as np | |
| import pandas as pd | |
| from abc import ABC, abstractmethod | |
| from dataclasses import dataclass, field | |
| from typing import Any, Dict, List, Optional, Union | |
| def validate_history_and_horizon(history, horizon: int, model_name: str) -> None: | |
| if horizon < 1: | |
| raise ValueError(f'{model_name}: horizon must be >= 1, got {horizon}.') | |
| values = np.asarray(pd.Series(history).astype(float), dtype=float) | |
| if not np.all(np.isfinite(values)): | |
| raise ValueError(f'{model_name}: price history contains NaN/inf. This usually means a data glitch left a missing or malformed candle -- re-fetch the history and try again.') | |
| class Signal: | |
| """Unified prediction contract shared by every model in the project. | |
| This is the single interface the backtester and the live engine consume, so | |
| that price-forecasting models (ARIMA, Auto-ARIMA, ARIMA-GARCH, Moirai, | |
| TimesFM) and the MAYTHOS decision engine are driven through exactly one code | |
| path. See MERGE_NOTES.md (Decision 1). | |
| Attributes: | |
| direction: 'up' or 'down' -- the predicted move of the next close. | |
| confidence: model confidence in [0, 1]. | |
| predicted_close: the forecast price for the final horizon step, or None | |
| for models (like MAYTHOS) that emit a directional decision rather | |
| than a price level. | |
| horizon: number of steps ahead this signal describes. | |
| meta: model-specific diagnostic fields (market state, execution | |
| suitability, etc.). Empty for plain forecasters. | |
| """ | |
| direction: str | |
| confidence: float | |
| predicted_close: Optional[float] = None | |
| horizon: int = 1 | |
| meta: Dict[str, Any] = field(default_factory=dict) | |
| class BaseModel(ABC): | |
| """Root of the model hierarchy. Every model produces a :class:`Signal`.""" | |
| name = 'base' | |
| def predict_signal(self, window: pd.DataFrame, horizon: int = 1, features: pd.DataFrame = None) -> Signal: | |
| raise NotImplementedError | |
| def _confidence_from_forecast(history: np.ndarray, predicted_close: float) -> float: | |
| """Map a numeric forecast to a [0, 1] confidence for the unified Signal. | |
| The size of the predicted move is compared against the recent realised | |
| volatility (standard deviation of first differences). A move of two standard | |
| deviations or more saturates confidence at 1.0. This is a documented, | |
| deterministic heuristic so that forecast-only models still populate the same | |
| confidence field MAYTHOS reports natively. See MERGE_NOTES.md (Decision 1). | |
| """ | |
| arr = np.asarray(history, dtype=float) | |
| current = float(arr[-1]) | |
| move = abs(float(predicted_close) - current) | |
| diffs = np.diff(arr) | |
| scale = float(np.std(diffs)) if diffs.size else 0.0 | |
| if scale <= 0.0: | |
| return 1.0 if move > 0.0 else 0.0 | |
| return float(min(1.0, move / (2.0 * scale))) | |
| class BaseForecastModel(BaseModel): | |
| """Base class for models that forecast a price path. | |
| Subclasses implement :meth:`predict` (a list of future closes). The concrete | |
| :meth:`predict_signal` here turns that path into the unified Signal, so every | |
| forecaster automatically speaks the same contract as MAYTHOS without any | |
| adapter or bridge layer. | |
| """ | |
| name = 'base' | |
| def predict(self, history: pd.Series, horizon: int = 1, features: pd.DataFrame = None) -> list: | |
| raise NotImplementedError | |
| def _history_series(window: Union[pd.DataFrame, pd.Series, Any]) -> pd.Series: | |
| if isinstance(window, pd.DataFrame): | |
| if 'Close' not in window.columns: | |
| raise ValueError("forecast window DataFrame must contain a 'Close' column.") | |
| return window['Close'] | |
| return pd.Series(window) | |
| def predict_signal(self, window: pd.DataFrame, horizon: int = 1, features: pd.DataFrame = None) -> Signal: | |
| history = self._history_series(window) | |
| forecast: List[float] = list(self.predict(history, horizon=horizon, features=features)) | |
| if len(forecast) < 1: | |
| raise ValueError(f'{self.name}: predict() returned an empty forecast.') | |
| predicted_close = float(forecast[-1]) | |
| current_close = float(pd.Series(history).astype(float).iloc[-1]) | |
| direction = 'up' if predicted_close > current_close else 'down' | |
| confidence = _confidence_from_forecast(pd.Series(history).astype(float).to_numpy(), predicted_close) | |
| return Signal(direction=direction, confidence=confidence, predicted_close=predicted_close, horizon=horizon, meta={}) | |