From f64ff510ab4e5086b1108ba0f71e0e07ff9a340f Mon Sep 17 00:00:00 2001 From: Phillip Wenig Date: Mon, 27 Oct 2025 16:38:29 +0100 Subject: [PATCH 1/3] Add tag filter support to gridpool trades stream - Add `tag` parameter to `gridpool_trades()` method for filtering trades by tag - Update `GridpoolTradeFilter` dataclass to include `tag` field - Update equality and hash methods to include tag field - Update `from_pb()` and `to_pb()` methods to handle tag serialization - Bump frequenz-api-electricity-trading dependency to 0.9.0 - Update import path for PaginationParams to v1alpha8 Signed-off-by: Phillip Wenig --- pyproject.toml | 2 +- src/frequenz/client/electricity_trading/_client.py | 5 ++++- src/frequenz/client/electricity_trading/_types.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4787f2e..edde160 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dependencies = [ "frequenz-channels >= 1.6.1, < 2", "frequenz-client-base >= 0.11.0, < 0.12.0", "frequenz-client-common >= 0.1.0, < 0.4.0", - "frequenz-api-electricity-trading >= 0.8.0, < 0.9.0", + "frequenz-api-electricity-trading >= 0.9.0, < 0.10.0", "protobuf >= 6.31.1, < 8", # Do not widen beyond 8! ] dynamic = ["version"] diff --git a/src/frequenz/client/electricity_trading/_client.py b/src/frequenz/client/electricity_trading/_client.py index f2ba444..3b3528f 100644 --- a/src/frequenz/client/electricity_trading/_client.py +++ b/src/frequenz/client/electricity_trading/_client.py @@ -15,7 +15,7 @@ from zoneinfo import ZoneInfo import grpc -from frequenz.api.common.v1.pagination.pagination_params_pb2 import PaginationParams +from frequenz.api.common.v1alpha8.pagination.pagination_params_pb2 import PaginationParams # pylint: disable=no-member from frequenz.api.electricity_trading.v1 import ( @@ -343,6 +343,7 @@ def gridpool_trades_stream( market_side: MarketSide | None = None, delivery_period: DeliveryPeriod | None = None, delivery_area: DeliveryArea | None = None, + tag: str | None = None, ) -> GrpcStreamBroadcaster[ electricity_trading_pb2.ReceiveGridpoolTradesStreamResponse, Trade ]: @@ -356,6 +357,7 @@ def gridpool_trades_stream( market_side: The market side to filter for. delivery_period: The delivery period to filter for. delivery_area: The delivery area to filter for. + tag: The tag to filter for. Returns: The gridpool trades streamer. @@ -371,6 +373,7 @@ def gridpool_trades_stream( side=market_side, delivery_period=delivery_period, delivery_area=delivery_area, + tag=tag, ) stream_key = (gridpool_id, gridpool_trade_filter) diff --git a/src/frequenz/client/electricity_trading/_types.py b/src/frequenz/client/electricity_trading/_types.py index 4c6c264..faabf5b 100644 --- a/src/frequenz/client/electricity_trading/_types.py +++ b/src/frequenz/client/electricity_trading/_types.py @@ -1576,6 +1576,9 @@ class GridpoolTradeFilter: delivery_area: DeliveryArea | None = None """Delivery area to filter for.""" + tag: str | None = None + """Tag associated with the trades to be filtered.""" + def __eq__(self, other: object) -> bool: """ Check if two GridpoolTradeFilter objects are equal. @@ -1594,6 +1597,7 @@ def __eq__(self, other: object) -> bool: and self.side == other.side and self.delivery_period == other.delivery_period and self.delivery_area == other.delivery_area + and self.tag == other.tag ) def __hash__(self) -> int: @@ -1610,6 +1614,7 @@ def __hash__(self) -> int: self.side, self.delivery_period, self.delivery_area, + self.tag, ) ) @@ -1652,6 +1657,11 @@ def from_pb( if gridpool_trade_filter.HasField("delivery_area") else None ), + tag=( + gridpool_trade_filter.tag + if gridpool_trade_filter.HasField("tag") + else None + ), ) def to_pb(self) -> electricity_trading_pb2.GridpoolTradeFilter: @@ -1673,6 +1683,7 @@ def to_pb(self) -> electricity_trading_pb2.GridpoolTradeFilter: self.delivery_period.to_pb() if self.delivery_period else None ), delivery_area=self.delivery_area.to_pb() if self.delivery_area else None, + tag=self.tag if self.tag else None, ) From ad347990c9b001007f44d96ae546dbd3cbb4c7cf Mon Sep 17 00:00:00 2001 From: Phillip Wenig Date: Tue, 28 Oct 2025 12:07:00 +0100 Subject: [PATCH 2/3] Replace delivery_period with delivery_time_filter for flexible time filtering This change updates the filtering mechanism for gridpool orders and trades to use a more flexible `DeliveryTimeFilter` instead of the restrictive `DeliveryPeriod`. The new filter supports: - Time interval filtering with optional start/end times - Multiple delivery duration filters - More granular control over time-based queries Key changes: - Added `Interval` and `DeliveryTimeFilter` types to support the new filtering API - Replaced `delivery_period` parameter with `delivery_time_filter` across all client methods - Updated CLI to construct `DeliveryTimeFilter` from delivery_start parameter - Migrated tests to use the new filtering types - Updated API imports from v1 to v1alpha8 for common types - Removed dependency on frequenz.client.common.pagination in favor of direct protobuf usage This change maintains backward compatibility by keeping the `delivery_period` parameter in the `create_gridpool_order` method while adding the new `delivery_time_filter` parameter. Signed-off-by: Phillip Wenig --- RELEASE_NOTES.md | 24 +- .../client/electricity_trading/_client.py | 57 +++-- .../client/electricity_trading/_types.py | 206 ++++++++++++++++-- .../electricity_trading/cli/etrading.py | 31 ++- tests/test_order_book.py | 6 +- tests/test_types.py | 23 +- 6 files changed, 281 insertions(+), 66 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2d168b9..bd988f3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -2,16 +2,28 @@ ## Summary - +This release adds enhanced filtering capabilities for gridpool orders and trades, with support for tag-based filtering and more flexible time-based queries. -## Upgrading +## New Features - +* **Tag filtering for gridpool trades**: The `gridpool_trades()` method now accepts a `tag` parameter to filter trades by tag. The `GridpoolTradeFilter` dataclass has been updated accordingly. -## New Features +* **Flexible time filtering with `DeliveryTimeFilter`**: Replaced the restrictive `delivery_period` parameter with a more flexible `delivery_time_filter` across gridpool orders and trades methods. The new `DeliveryTimeFilter` supports: + - Time interval filtering with optional start/end times + - Multiple delivery duration filters + - More granular control over time-based queries + +* **New types for time filtering**: Added `Interval` and `DeliveryTimeFilter` types to support the enhanced filtering API. * Support tags in CLI create-order command. -## Bug Fixes +## Breaking Changes + +* The `delivery_period` parameter has been replaced with `delivery_time_filter` in the following methods: + - `list_gridpool_orders()` + - `stream_gridpool_orders()` + - `gridpool_trades()` + + Note: The `create_gridpool_order()` method maintains backward compatibility by keeping both parameters. - +* Updated API imports from v1 to v1alpha8 for common types. diff --git a/src/frequenz/client/electricity_trading/_client.py b/src/frequenz/client/electricity_trading/_client.py index 3b3528f..80743cb 100644 --- a/src/frequenz/client/electricity_trading/_client.py +++ b/src/frequenz/client/electricity_trading/_client.py @@ -15,7 +15,9 @@ from zoneinfo import ZoneInfo import grpc -from frequenz.api.common.v1alpha8.pagination.pagination_params_pb2 import PaginationParams +from frequenz.api.common.v1alpha8.pagination.pagination_params_pb2 import ( + PaginationParams, +) # pylint: disable=no-member from frequenz.api.electricity_trading.v1 import ( @@ -28,13 +30,13 @@ from frequenz.client.base.client import BaseApiClient from frequenz.client.base.exception import ClientNotConnected from frequenz.client.base.streaming import GrpcStreamBroadcaster -from frequenz.client.common.pagination import Params from google.protobuf import field_mask_pb2, struct_pb2 from google.protobuf.timestamp_pb2 import Timestamp from ._types import ( DeliveryArea, DeliveryPeriod, + DeliveryTimeFilter, GridpoolOrderFilter, GridpoolTradeFilter, MarketSide, @@ -277,7 +279,7 @@ def gridpool_orders_stream( order_states: list[OrderState] | None = None, market_side: MarketSide | None = None, delivery_area: DeliveryArea | None = None, - delivery_period: DeliveryPeriod | None = None, + delivery_time_filter: DeliveryTimeFilter | None = None, tag: str | None = None, ) -> GrpcStreamBroadcaster[ electricity_trading_pb2.ReceiveGridpoolOrdersStreamResponse, OrderDetail @@ -290,7 +292,7 @@ def gridpool_orders_stream( order_states: List of order states to filter for. market_side: Market side to filter for. delivery_area: Delivery area to filter for. - delivery_period: Delivery period to filter for. + delivery_time_filter: Delivery time to filter for. tag: Tag to filter for. Returns: @@ -299,13 +301,13 @@ def gridpool_orders_stream( Raises: grpc.RpcError: If an error occurs while streaming the orders. """ - self.validate_params(delivery_period=delivery_period) + self.validate_params(delivery_time_filter=delivery_time_filter) gridpool_order_filter = GridpoolOrderFilter( order_states=order_states, side=market_side, delivery_area=delivery_area, - delivery_period=delivery_period, + delivery_time_filter=delivery_time_filter, tag=tag, ) @@ -341,7 +343,7 @@ def gridpool_trades_stream( trade_states: list[TradeState] | None = None, trade_ids: list[int] | None = None, market_side: MarketSide | None = None, - delivery_period: DeliveryPeriod | None = None, + delivery_time_filter: DeliveryTimeFilter | None = None, delivery_area: DeliveryArea | None = None, tag: str | None = None, ) -> GrpcStreamBroadcaster[ @@ -355,7 +357,7 @@ def gridpool_trades_stream( trade_states: List of trade states to filter for. trade_ids: List of trade IDs to filter for. market_side: The market side to filter for. - delivery_period: The delivery period to filter for. + delivery_time_filter: The delivery time filter of the trade. delivery_area: The delivery area to filter for. tag: The tag to filter for. @@ -365,13 +367,13 @@ def gridpool_trades_stream( Raises: grpc.RpcError: If an error occurs while streaming gridpool trades. """ - self.validate_params(delivery_period=delivery_period) + self.validate_params(delivery_time_filter=delivery_time_filter) gridpool_trade_filter = GridpoolTradeFilter( trade_states=trade_states, trade_ids=trade_ids, side=market_side, - delivery_period=delivery_period, + delivery_time_filter=delivery_time_filter, delivery_area=delivery_area, tag=tag, ) @@ -410,6 +412,7 @@ def validate_params( peak_price_delta: Price | None | _NoValue = NO_VALUE, display_quantity: Power | None | _NoValue = NO_VALUE, delivery_period: DeliveryPeriod | None = None, + delivery_time_filter: DeliveryTimeFilter | None = None, valid_until: datetime | None | _NoValue = NO_VALUE, execution_option: OrderExecutionOption | None | _NoValue = NO_VALUE, order_type: OrderType | None = None, @@ -428,6 +431,7 @@ def validate_params( peak_price_delta: The peak price delta of the order. display_quantity: The display quantity of the order. delivery_period: The delivery period of the order. + delivery_time_filter: The delivery time filter of the order. valid_until: The valid until of the order. execution_option: The execution option of the order. order_type: The order type. @@ -461,6 +465,23 @@ def validate_params( if delivery_period is not None: if delivery_period.start < datetime.now(timezone.utc): raise ValueError("delivery_period must be in the future") + if ( + delivery_time_filter is not None + and delivery_time_filter.time_interval is not None + and delivery_time_filter.time_interval.start_time is not None + ): + if delivery_time_filter.time_interval.start_time < datetime.now( + timezone.utc + ): + raise ValueError("delivery_time_filter must be in the future") + if ( + delivery_time_filter.time_interval.end_time is not None + and delivery_time_filter.time_interval.end_time + < delivery_time_filter.time_interval.start_time + ): + raise ValueError( + "delivery_time_filter end time must be after start time" + ) if not isinstance(valid_until, _NoValue) and valid_until is not None: if ( not isinstance(execution_option, _NoValue) @@ -807,7 +828,7 @@ async def list_gridpool_orders( *, order_states: list[OrderState] | None = None, side: MarketSide | None = None, - delivery_period: DeliveryPeriod | None = None, + delivery_time_filter: DeliveryTimeFilter | None = None, delivery_area: DeliveryArea | None = None, tag: str | None = None, page_size: int | None = None, @@ -820,7 +841,7 @@ async def list_gridpool_orders( gridpool_id: The Gridpool to retrieve the orders for. order_states: List of order states to filter by. side: The side of the market to filter by. - delivery_period: The delivery period to filter by. + delivery_time_filter: The delivery time filter of the order. delivery_area: The delivery area to filter by. tag: The tag to filter by. page_size: The number of orders to return per page. @@ -835,7 +856,7 @@ async def list_gridpool_orders( gridpool_order_filter = GridpoolOrderFilter( order_states=order_states, side=side, - delivery_period=delivery_period, + delivery_time_filter=delivery_time_filter, delivery_area=delivery_area, tag=tag, ) @@ -844,7 +865,7 @@ async def list_gridpool_orders( gridpool_id=gridpool_id, filter=gridpool_order_filter.to_pb(), pagination_params=( - Params(page_size=page_size, page_token="").to_proto() + PaginationParams(page_size=page_size, page_token="") if page_size else None ), @@ -884,7 +905,7 @@ async def list_gridpool_trades( trade_states: list[TradeState] | None = None, trade_ids: list[int] | None = None, market_side: MarketSide | None = None, - delivery_period: DeliveryPeriod | None = None, + delivery_time_filter: DeliveryTimeFilter | None = None, delivery_area: DeliveryArea | None = None, page_size: int | None = None, timeout: timedelta | None = None, @@ -897,7 +918,7 @@ async def list_gridpool_trades( trade_states: List of trade states to filter by. trade_ids: List of trade IDs to filter by. market_side: The side of the market to filter by. - delivery_period: The delivery period to filter by. + delivery_time_filter: The delivery time filter of the order. delivery_area: The delivery area to filter by. page_size: The number of trades to return per page. timeout: Timeout duration, defaults to None. @@ -912,7 +933,7 @@ async def list_gridpool_trades( trade_states=trade_states, trade_ids=trade_ids, side=market_side, - delivery_period=delivery_period, + delivery_time_filter=delivery_time_filter, delivery_area=delivery_area, ) @@ -920,7 +941,7 @@ async def list_gridpool_trades( gridpool_id=gridpool_id, filter=gridpool_trade_filter.to_pb(), pagination_params=( - Params(page_size=page_size, page_token="").to_proto() + PaginationParams(page_size=page_size, page_token="") if page_size else None ), diff --git a/src/frequenz/client/electricity_trading/_types.py b/src/frequenz/client/electricity_trading/_types.py index faabf5b..5fe1e42 100644 --- a/src/frequenz/client/electricity_trading/_types.py +++ b/src/frequenz/client/electricity_trading/_types.py @@ -16,9 +16,9 @@ from typing import Callable, Concatenate, ParamSpec, Self, TypeVar # pylint: disable=no-member -from frequenz.api.common.v1.grid import delivery_area_pb2, delivery_duration_pb2 -from frequenz.api.common.v1.market import power_pb2, price_pb2 -from frequenz.api.common.v1.types import decimal_pb2 +from frequenz.api.common.v1alpha8.grid import delivery_area_pb2, delivery_duration_pb2 +from frequenz.api.common.v1alpha8.market import power_pb2, price_pb2 +from frequenz.api.common.v1alpha8.types import decimal_pb2, interval_pb2 from frequenz.api.electricity_trading.v1 import electricity_trading_pb2 from google.protobuf import json_format, struct_pb2, timestamp_pb2 @@ -489,6 +489,92 @@ def to_pb(self) -> delivery_duration_pb2.DeliveryPeriod: ) +@dataclass(frozen=True) +class Interval: + """ + Represents a time interval filter. + + The interval includes the start time and excludes the end time. + This follows the convention used in ISO 8601 for time intervals, + Pandas slicing, and Python slicing: [start_time, end_time). + + * If `start_time` is omitted, the interval is + considered unbounded at the start. + * If `end_time` is omitted, the interval is + considered unbounded at the end. + """ + + start_time: datetime | None = None + """The beginning of the interval (inclusive) + + Must be a UTC timestamp. + """ + + end_time: datetime | None = None + """The end of the interval (exclusive) + + Must be a UTC timestamp. + """ + + def __eq__(self, other: object) -> bool: + """Check if two Interval objects are equal. + + Args: + other: The object to compare with. + + Returns: + True if the two objects are equal, False otherwise. + """ + if not isinstance(other, Interval): + return NotImplemented + return self.start_time == other.start_time and self.end_time == other.end_time + + def __hash__(self) -> int: + """Hash the Interval object. + + Returns: + Hash of the Interval object. + """ + return hash((self.start_time, self.end_time)) + + @classmethod + @from_pb + def from_pb(cls, interval: interval_pb2.Interval) -> Self: + """Convert a protobuf Interval to Interval object. + + Args: + interval: The protobuf Interval to convert. + + Returns: + The Interval object. + """ + return cls( + start_time=interval.start_time.ToDatetime(tzinfo=timezone.utc), + end_time=interval.end_time.ToDatetime(tzinfo=timezone.utc), + ) + + def to_pb(self) -> interval_pb2.Interval: + """Convert an Interval object to protobuf Interval. + + Returns: + The protobuf Interval. + """ + start_time = None + end_time = None + + if self.start_time is not None: + start_time = timestamp_pb2.Timestamp() + start_time.FromDatetime(self.start_time) + + if self.end_time is not None: + end_time = timestamp_pb2.Timestamp() + end_time.FromDatetime(self.end_time) + return interval_pb2.Interval( + start_time=start_time, + end_time=end_time, + ) + + # From electricity trading api @@ -1432,6 +1518,86 @@ def to_pb(self) -> electricity_trading_pb2.PublicTrade: ) +@dataclass(frozen=True) +class DeliveryTimeFilter: + """Parameters for filtering Gridpool orders by delivery time.""" + + time_interval: Interval | None = None + """Time window for matching delivery period start times.""" + + duration_filters: list[DeliveryDuration] | None = None + """List of allowed delivery durations.""" + + def __eq__(self, other: object) -> bool: + """Check if two DeliveryTimeFilter objects are equal. + + Args: + other: The object to compare with. + + Returns: + True if the two objects are equal, False otherwise. + """ + if not isinstance(other, DeliveryTimeFilter): + return NotImplemented + return ( + self.time_interval == other.time_interval + and self.duration_filters == other.duration_filters + ) + + def __hash__(self) -> int: + """Hash the DeliveryTimeFilter object.""" + return hash( + ( + self.time_interval, + tuple(self.duration_filters) if self.duration_filters else None, + ) + ) + + @classmethod + @from_pb + def from_pb( + cls, delivery_time_filter: electricity_trading_pb2.DeliveryTimeFilter + ) -> Self: + """Convert a protobuf DeliveryTimeFilter to DeliveryTimeFilter object. + + Args: + delivery_time_filter: The protobuf DeliveryTimeFilter to convert. + + Returns: + The DeliveryTimeFilter object. + """ + return cls( + time_interval=( + Interval.from_pb(delivery_time_filter.time_interval) + if delivery_time_filter.HasField("time_interval") + else None + ), + duration_filters=( + [ + DeliveryDuration.from_pb(duration) + for duration in delivery_time_filter.duration_filters + ] + if delivery_time_filter.duration_filters + else None + ), + ) + + def to_pb(self) -> electricity_trading_pb2.DeliveryTimeFilter: + """Convert a DeliveryTimeFilter object to protobuf DeliveryTimeFilter. + + Returns: + The protobuf DeliveryTimeFilter. + """ + return electricity_trading_pb2.DeliveryTimeFilter( + time_interval=self.time_interval.to_pb() if self.time_interval else None, + duration_filters=( + [duration.to_pb() for duration in self.duration_filters] + if self.duration_filters + else None + ), + ) + + @dataclass(frozen=True) class GridpoolOrderFilter: """Parameters for filtering Gridpool orders.""" @@ -1442,7 +1608,7 @@ class GridpoolOrderFilter: side: MarketSide | None = None """Market side to filter for.""" - delivery_period: DeliveryPeriod | None = None + delivery_time_filter: DeliveryTimeFilter | None = None """Delivery period to filter for.""" delivery_area: DeliveryArea | None = None @@ -1466,7 +1632,7 @@ def __eq__(self, other: object) -> bool: return ( self.order_states == other.order_states and self.side == other.side - and self.delivery_period == other.delivery_period + and self.delivery_time_filter == other.delivery_time_filter and self.delivery_area == other.delivery_area and self.tag == other.tag ) @@ -1482,7 +1648,7 @@ def __hash__(self) -> int: ( tuple(self.order_states) if self.order_states is not None else None, self.side, - self.delivery_period, + self.delivery_time_filter, self.delivery_area, self.tag, ) @@ -1512,9 +1678,9 @@ def from_pb( if gridpool_order_filter.HasField("side") else None ), - delivery_period=( - DeliveryPeriod.from_pb(gridpool_order_filter.delivery_period) - if gridpool_order_filter.HasField("delivery_period") + delivery_time_filter=( + DeliveryTimeFilter.from_pb(gridpool_order_filter.delivery_time_filter) + if gridpool_order_filter.HasField("delivery_time_filter") else None ), delivery_area=( @@ -1549,8 +1715,8 @@ def to_pb(self) -> electricity_trading_pb2.GridpoolOrderFilter: if self.side else None ), - delivery_period=( - self.delivery_period.to_pb() if self.delivery_period else None + delivery_time_filter=( + self.delivery_time_filter.to_pb() if self.delivery_time_filter else None ), delivery_area=self.delivery_area.to_pb() if self.delivery_area else None, tag=self.tag if self.tag else None, @@ -1570,8 +1736,8 @@ class GridpoolTradeFilter: side: MarketSide | None = None """Market side to filter for.""" - delivery_period: DeliveryPeriod | None = None - """Delivery period to filter for.""" + delivery_time_filter: DeliveryTimeFilter | None = None + """Delivery time to filter for.""" delivery_area: DeliveryArea | None = None """Delivery area to filter for.""" @@ -1595,7 +1761,7 @@ def __eq__(self, other: object) -> bool: self.trade_states == other.trade_states and self.trade_ids == other.trade_ids and self.side == other.side - and self.delivery_period == other.delivery_period + and self.delivery_time_filter == other.delivery_time_filter and self.delivery_area == other.delivery_area and self.tag == other.tag ) @@ -1612,7 +1778,7 @@ def __hash__(self) -> int: tuple(self.trade_states) if self.trade_states is not None else None, tuple(self.trade_ids) if self.trade_ids is not None else None, self.side, - self.delivery_period, + self.delivery_time_filter, self.delivery_area, self.tag, ) @@ -1647,9 +1813,9 @@ def from_pb( if gridpool_trade_filter.HasField("side") else None ), - delivery_period=( - DeliveryPeriod.from_pb(gridpool_trade_filter.delivery_period) - if gridpool_trade_filter.HasField("delivery_period") + delivery_time_filter=( + DeliveryTimeFilter.from_pb(gridpool_trade_filter.delivery_time_filter) + if gridpool_trade_filter.HasField("delivery_time_filter") else None ), delivery_area=( @@ -1679,8 +1845,8 @@ def to_pb(self) -> electricity_trading_pb2.GridpoolTradeFilter: ), trade_ids=self.trade_ids if self.trade_ids else None, side=MarketSide.to_pb(self.side) if self.side else None, - delivery_period=( - self.delivery_period.to_pb() if self.delivery_period else None + delivery_time_filter=( + self.delivery_time_filter.to_pb() if self.delivery_time_filter else None ), delivery_area=self.delivery_area.to_pb() if self.delivery_area else None, tag=self.tag if self.tag else None, diff --git a/src/frequenz/client/electricity_trading/cli/etrading.py b/src/frequenz/client/electricity_trading/cli/etrading.py index 726acbd..144b130 100644 --- a/src/frequenz/client/electricity_trading/cli/etrading.py +++ b/src/frequenz/client/electricity_trading/cli/etrading.py @@ -24,6 +24,7 @@ PublicTrade, Trade, ) +from frequenz.client.electricity_trading._types import DeliveryTimeFilter, Interval def check_delivery_start( @@ -146,15 +147,18 @@ async def list_gridpool_trades( print_trade_header() - delivery_period = None + delivery_time_filter = None # If delivery period is selected, list historical trades also if delivery_start is not None: check_delivery_start(delivery_start) - delivery_period = DeliveryPeriod( - start=delivery_start, - duration=timedelta(minutes=15), + delivery_time_filter = DeliveryTimeFilter( + time_interval=Interval( + start_time=delivery_start, + end_time=delivery_start + timedelta(minutes=15), + ), + duration_filters=[], ) - lst = client.list_gridpool_trades(gid, delivery_period=delivery_period) + lst = client.list_gridpool_trades(gid, delivery_time_filter=delivery_time_filter) async for trade in lst: print_trade(trade) @@ -163,7 +167,7 @@ async def list_gridpool_trades( return stream = client.gridpool_trades_stream( - gid, delivery_period=delivery_period + gid, delivery_time_filter=delivery_time_filter ).new_receiver() async for trade in stream: print_trade(trade) @@ -197,15 +201,18 @@ async def list_gridpool_orders( print_order_header() - delivery_period = None + delivery_time_filter = None # If delivery period is selected, list historical orders also if delivery_start is not None: check_delivery_start(delivery_start) - delivery_period = DeliveryPeriod( - start=delivery_start, - duration=timedelta(minutes=15), + delivery_time_filter = DeliveryTimeFilter( + time_interval=Interval( + start_time=delivery_start, + end_time=delivery_start + timedelta(minutes=15), + ), + duration_filters=[], ) - lst = client.list_gridpool_orders(gid, delivery_period=delivery_period) + lst = client.list_gridpool_orders(gid, delivery_time_filter=delivery_time_filter) async for order in reverse_iterator(lst): print_order(order) @@ -214,7 +221,7 @@ async def list_gridpool_orders( return stream = client.gridpool_orders_stream( - gid, delivery_period=delivery_period + gid, delivery_time_filter=delivery_time_filter ).new_receiver() async for order in stream: print_order(order) diff --git a/tests/test_order_book.py b/tests/test_order_book.py index a8e5306..abf412f 100644 --- a/tests/test_order_book.py +++ b/tests/test_order_book.py @@ -11,9 +11,9 @@ import grpc import pytest -from frequenz.api.common.v1.grid import delivery_area_pb2, delivery_duration_pb2 -from frequenz.api.common.v1.market import power_pb2, price_pb2 -from frequenz.api.common.v1.types import decimal_pb2 +from frequenz.api.common.v1alpha8.grid import delivery_area_pb2, delivery_duration_pb2 +from frequenz.api.common.v1alpha8.market import power_pb2, price_pb2 +from frequenz.api.common.v1alpha8.types import decimal_pb2 from frequenz.api.electricity_trading.v1 import ( electricity_trading_pb2, electricity_trading_pb2_grpc, diff --git a/tests/test_types.py b/tests/test_types.py index 8a84201..09cd8fd 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -11,9 +11,9 @@ from deepdiff import DeepDiff # pylint: disable=no-member -from frequenz.api.common.v1.grid import delivery_area_pb2, delivery_duration_pb2 -from frequenz.api.common.v1.market import power_pb2, price_pb2 -from frequenz.api.common.v1.types import decimal_pb2 +from frequenz.api.common.v1alpha8.grid import delivery_area_pb2, delivery_duration_pb2 +from frequenz.api.common.v1alpha8.market import power_pb2, price_pb2 +from frequenz.api.common.v1alpha8.types import decimal_pb2, interval_pb2 from frequenz.api.electricity_trading.v1 import electricity_trading_pb2 from google.protobuf import timestamp_pb2 @@ -43,6 +43,7 @@ TradeState, UpdateOrder, ) +from frequenz.client.electricity_trading._types import DeliveryTimeFilter, Interval T = TypeVar("T") @@ -227,7 +228,12 @@ GRIDPOOL_ORDER_FILTER = GridpoolOrderFilter( order_states=[OrderState.ACTIVE, OrderState.CANCELED], side=MarketSide.BUY, - delivery_period=DeliveryPeriod(start=START_TIME, duration=timedelta(minutes=15)), + delivery_time_filter=DeliveryTimeFilter( + time_interval=Interval( + start_time=START_TIME, end_time=START_TIME + timedelta(minutes=15) + ), + duration_filters=[DeliveryDuration.MINUTES_15], + ), delivery_area=DeliveryArea(code="XYZ", code_type=EnergyMarketCodeType.EUROPE_EIC), tag="test", ) @@ -237,9 +243,12 @@ electricity_trading_pb2.OrderState.ORDER_STATE_CANCELED, ], side=electricity_trading_pb2.MarketSide.MARKET_SIDE_BUY, - delivery_period=delivery_duration_pb2.DeliveryPeriod( - start=START_TIME_PB, - duration=delivery_duration_pb2.DeliveryDuration.DELIVERY_DURATION_15, + delivery_time_filter=electricity_trading_pb2.DeliveryTimeFilter( + time_interval=interval_pb2.Interval( + start_time=START_TIME_PB, + end_time=timestamp_pb2.Timestamp(seconds=START_TIME_PB.seconds + 15 * 60), + ), + duration_filters=[delivery_duration_pb2.DeliveryDuration.DELIVERY_DURATION_15], ), delivery_area=delivery_area_pb2.DeliveryArea( code="XYZ", From 5913665aa712bff18f4b201f5ee7614108a4d1a2 Mon Sep 17 00:00:00 2001 From: Phillip Wenig Date: Wed, 29 Oct 2025 10:25:04 +0100 Subject: [PATCH 3/3] Bump minimum frequenz-api-common version to 0.8.1 Signed-off-by: Phillip Wenig --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index edde160..4827338 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ dependencies = [ "click >= 8.1.8, < 9", # Stick to a version without a polluting `tests` package: https://github.com/EnergieID/entsoe-py/pull/447 "entsoe-py >= 0.6.16, < 0.7.1", - "frequenz-api-common >= 0.6.5, < 0.9.0", + "frequenz-api-common >= 0.8.1, < 0.9.0", "grpcio >= 1.72.1, < 2", "frequenz-channels >= 1.6.1, < 2", "frequenz-client-base >= 0.11.0, < 0.12.0",