Coverage for agentlib_flexquant/data_structures/market.py: 100%
32 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
1"""
2Market specification data models for flexibility offer acceptance strategies.
4Defines Pydantic models for configuring different market behaviors including
5random acceptance, single offer acceptance, and custom strategies with
6associated parameters and validation.
7"""
8from typing import Literal, Union
10import pydantic
12from agentlib_flexquant.data_structures.globals import FlexibilityDirections, COLLOCATION, CONSTANT
15class RandomOptions(pydantic.BaseModel):
16 """Configuration options for random market behavior."""
18 type: Literal["random"]
19 random_seed: int = pydantic.Field(
20 name="random_seed",
21 default=None,
22 description="Random seed for reproducing experiments",
23 )
25 pos_neg_rate: float = pydantic.Field(
26 name="pos_neg_rate",
27 default=0,
28 description="Determines the likelihood positive and the negative flexibility."
29 "A higher rate means that more positive offers will be accepted.",
30 le=1,
31 ge=0,
32 )
34 offer_acceptance_rate: float = pydantic.Field(
35 name="offer_acceptance_rate",
36 default=0.5,
37 description="Determines the likelihood of an accepted offer",
38 le=1,
39 ge=0,
40 )
43class SingleOptions(pydantic.BaseModel):
44 """Configuration options for single offer acceptance market behavior."""
46 type: Literal["single"]
47 offer_acceptance_time: float = pydantic.Field(
48 description="After this time, the first available flex offer is accepted"
49 )
50 direction: FlexibilityDirections = pydantic.Field(
51 default="positive", description="Direction of the flexibility"
52 )
55class CustomOptions(pydantic.BaseModel):
56 """Configuration options for custom market behavior with flexible parameters."""
58 type: Literal["custom"]
60 model_config = pydantic.ConfigDict(extra="allow")
63class MarketSpecifications(pydantic.BaseModel):
64 """Base specification for flexibility market behavior and parameters."""
66 type: str = pydantic.Field(default=None, description="Name of market type")
68 cooldown: int = pydantic.Field(
69 name="cooldown",
70 default=6,
71 description="cooldown time (no timesteps) after a provision",
72 )
74 minimum_average_flex: float = pydantic.Field(
75 name="minimum_average_flex",
76 default=0,
77 unit="W",
78 description="minimum average of an accepted offer",
79 )
81 options: Union[RandomOptions, SingleOptions, CustomOptions] = pydantic.Field(
82 ...,
83 description="Market options, changes depending on 'type'",
84 discriminator="type",
85 )
87 accepted_offer_sample_points: Literal[COLLOCATION, CONSTANT] = pydantic.Field(
88 default='collocation',
89 description="Method defining how to send the accepted flexibility power back"
90 "to the baseline mpc so that the system can deliver it. "
91 "This is relevant for collocation, as the power profile is only "
92 "defined at the collocation points. If you choose constant here, "
93 "the values are averaged and set for the whole time step."
94 "Set to constant if the power only depends on control or if "
95 "system has low inertial. Otherwise, use collocation.",
96 )
98 # Root validator to automatically populate the options.type from the top-level type
99 @pydantic.model_validator(mode="before")
100 @classmethod
101 def set_options_type(cls, values):
102 """Automatically set the options type field from the top-level market type."""
103 market_type = values.get("type")
104 options = values.get("options", {})
106 # Ensure the options dict contains the correct 'type' field
107 if isinstance(options, dict) and "type" not in options:
108 options["type"] = market_type
109 values["options"] = options
111 return values
114class RandomMarket(MarketSpecifications):
115 """Market specification for random flexibility offer acceptance behavior."""
117 type: str = "random"