Coverage for src/stable_yield_lab/core/models.py: 100%
29 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-04 20:38 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-04 20:38 +0000
1"""Immutable data models used throughout StableYieldLab."""
3from __future__ import annotations
5from dataclasses import asdict, dataclass
6from datetime import UTC, datetime
7from typing import Any
9import pandas as pd
12@dataclass(frozen=True)
13class Pool:
14 """Snapshot description of a yield-bearing pool."""
16 name: str
17 chain: str
18 stablecoin: str
19 tvl_usd: float
20 base_apy: float # decimal fraction, e.g. 0.08 for 8%
21 reward_apy: float = 0.0 # optional extra rewards (auto-compounded by meta protocols)
22 is_auto: bool = True # True if fully automated (no manual boosts/claims)
23 source: str = "custom"
24 risk_score: float = 2.0 # 1=low, 3=high (subjective / model-derived)
25 timestamp: float = 0.0 # unix epoch; 0 means unknown
27 def to_dict(self) -> dict[str, Any]:
28 """Serialise the pool to a dictionary suitable for DataFrame creation."""
30 data = asdict(self)
31 # for readability in CSV outputs
32 data["timestamp_iso"] = (
33 datetime.fromtimestamp(self.timestamp or 0, tz=UTC).isoformat()
34 if self.timestamp
35 else ""
36 )
37 return data
40@dataclass(frozen=True)
41class PoolReturn:
42 """Periodic return observation for a given pool."""
44 name: str
45 timestamp: pd.Timestamp
46 period_return: float
48 def to_dict(self) -> dict[str, Any]:
49 return {
50 "name": self.name,
51 "timestamp": self.timestamp,
52 "period_return": self.period_return,
53 }
56__all__ = ["Pool", "PoolReturn"]