Coverage for src/tinycta/config.py: 100%

15 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-09-15 05:23 +0000

1"""Configuration model for the Basanos engine.""" 

2 

3from pydantic import BaseModel, Field, ValidationInfo, field_validator 

4 

5 

6class Config(BaseModel): 

7 """Configuration for correlation-aware position optimization (Basanos engine). 

8 

9 Example: 

10 >>> from pydantic import ValidationError 

11 >>> from tinycta.config import Config 

12 >>> cfg = Config(vola=32, corr=64, clip=4.2, shrink=0.5) 

13 >>> cfg.vola, cfg.corr, cfg.clip, cfg.shrink 

14 (32, 64, 4.2, 0.5) 

15 

16 The model is frozen, so a validated config cannot drift after construction: 

17 

18 >>> try: 

19 ... cfg.vola = 16 

20 ... except ValidationError: 

21 ... print("frozen") 

22 frozen 

23 

24 ``corr`` must not be shorter than ``vola`` — a correlation window below the 

25 volatility window is numerically unstable: 

26 

27 >>> try: 

28 ... Config(vola=64, corr=32, clip=4.2, shrink=0.5) 

29 ... except ValidationError: 

30 ... print("corr must be >= vola") 

31 corr must be >= vola 

32 

33 Windows are strictly positive, ``shrink`` lies in ``[0, 1]``, and unknown 

34 keys are rejected rather than silently ignored: 

35 

36 >>> for bad in ({"vola": 0}, {"shrink": 1.5}, {"typo": 1}): 

37 ... kwargs = {"vola": 32, "corr": 64, "clip": 4.2, "shrink": 0.5} | bad 

38 ... try: 

39 ... Config(**kwargs) 

40 ... except ValidationError: 

41 ... print("rejected", sorted(bad)) 

42 rejected ['vola'] 

43 rejected ['shrink'] 

44 rejected ['typo'] 

45 """ 

46 

47 vola: int = Field(..., gt=0) 

48 corr: int = Field(..., gt=0) 

49 clip: float = Field(..., gt=0.0) 

50 shrink: float = Field(..., ge=0.0, le=1.0) 

51 

52 model_config = {"frozen": True, "extra": "forbid"} 

53 

54 @field_validator("corr") 

55 @classmethod # pragma: no mutate - pydantic field_validator behaves identically without classmethod 

56 def corr_greater_than_vola(cls, v: int, info: ValidationInfo) -> int: 

57 """Enforce corr >= vola for numerical stability.""" 

58 vola = info.data.get("vola") if hasattr(info, "data") else None 

59 if vola is not None and v < vola: 

60 msg = f"corr ({v}) must be >= vola ({vola}) for numerical stability" 

61 raise ValueError(msg) 

62 return v