Coverage for src/finbot/backtest/experiment.py: 96%

41 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-21 17:12 +0000

1from dataclasses import dataclass, field 

2from datetime import datetime 

3from typing import Any 

4from uuid import UUID 

5 

6from finbot.backtest.models import BacktestResult 

7 

8 

9@dataclass(frozen=True) 

10class ExperimentConfig: 

11 strategy: str 

12 symbols: tuple[str, ...] 

13 start: datetime 

14 end: datetime 

15 dataset: str 

16 initial_cash: float 

17 allocation: float = 0.999 

18 fee_rate: float = 0.0 

19 slippage_rate: float = 0.0 

20 strategy_params: dict[str, Any] = field(default_factory=dict) 

21 

22 def __post_init__(self) -> None: 

23 if not self.strategy: 23 ↛ 24line 23 didn't jump to line 24 because the condition on line 23 was never true

24 raise ValueError("strategy must not be empty") 

25 if not self.symbols: 

26 raise ValueError("symbols must not be empty") 

27 if self.start >= self.end: 

28 raise ValueError("start must be before end") 

29 if self.initial_cash <= 0: 

30 raise ValueError("initial_cash must be greater than 0") 

31 if not 0 < self.allocation <= 1: 

32 raise ValueError("allocation must be greater than 0 and at most 1") 

33 if self.fee_rate < 0: 

34 raise ValueError("fee_rate must not be negative") 

35 if self.slippage_rate < 0: 

36 raise ValueError("slippage_rate must not be negative") 

37 

38 

39@dataclass(frozen=True) 

40class ExperimentMetadata: 

41 run_id: UUID 

42 created_at: datetime 

43 config: ExperimentConfig 

44 

45 

46@dataclass(frozen=True) 

47class ExperimentRun: 

48 metadata: ExperimentMetadata 

49 result: BacktestResult