from __future__ import annotations import yaml import numpy as np from typing import Dict from pydantic import BaseModel, Field, field_validator class UserParams(BaseModel): lambda_mean: float = Field(gt=0) lambda_std: float = Field(gt=0) mu_mean: float mu_std: float = Field(gt=0) sigma_mean: float = Field(gt=0) sigma_std: float = Field(gt=0) class UPILimits(BaseModel): max_txn_amount: float = Field(gt=0) daily_limit: float = Field(gt=0) class RiskModel(BaseModel): weights: Dict[str, float] @field_validator("weights") @classmethod def check_weights(cls, v): if not v: raise ValueError("weights cannot be empty") return v class Config(BaseModel): num_users: int = Field(gt=0) simulation_days: int = Field(gt=0) fraud_ratio: float = Field(ge=0, le=1) benchmark_mode: str = "standard" user_params: UserParams upi_limits: UPILimits risk_model: RiskModel random_seed: int @property def simulation_seconds(self) -> int: return self.simulation_days * 24 * 60 * 60 def load_config(path: str) -> Config: with open(path, "r") as f: raw = yaml.safe_load(f) config = Config(**raw) np.random.seed(config.random_seed) return config