33
44"""CLI tool to interact with the trading API."""
55
6+ from collections import deque
67from datetime import datetime , timedelta , timezone
78from decimal import Decimal
89from enum import Enum
10+ from typing import AsyncIterator
911
1012from frequenz .client .electricity_trading import (
1113 Client ,
@@ -84,6 +86,9 @@ async def list_orders(
8486 for the 15 minute delivery period starting at delivery_start.
8587 If no delivery_start is provided, stream new orders for any delivery period.
8688
89+ Note that retrieved sort order for listed orders (starting from the newest)
90+ is reversed in chunks trying to bring more recent orders to the bottom.
91+
8792 Args:
8893 url: URL of the trading API.
8994 key: API key.
@@ -104,7 +109,7 @@ async def list_orders(
104109 )
105110 lst = client .list_gridpool_orders (gid , delivery_period = delivery_period )
106111
107- async for order in lst :
112+ async for order in reverse_iterator ( lst ) :
108113 print_order (order )
109114
110115 if delivery_start and delivery_start <= datetime .now (timezone .utc ):
@@ -282,3 +287,27 @@ def print_order(order: OrderDetail) -> None:
282287 order .state_detail .state ,
283288 ]
284289 print ("," .join (v .name if isinstance (v , Enum ) else str (v ) for v in values ))
290+
291+
292+ async def reverse_iterator (
293+ iterator : AsyncIterator [OrderDetail ], chunk_size : int = 100_000
294+ ) -> AsyncIterator [OrderDetail ]:
295+ """Reverse an async iterator in chunks to avoid loading all elements into memory.
296+
297+ Args:
298+ iterator: Async iterator to reverse.
299+ chunk_size: Size of the buffer to store elements.
300+
301+ Yields:
302+ Elements of the iterator in reverse order.
303+ """
304+ buffer : deque [OrderDetail ] = deque (maxlen = chunk_size )
305+ async for item in iterator :
306+ buffer .append (item )
307+ if len (buffer ) == chunk_size :
308+ for item in reversed (buffer ):
309+ yield item
310+ buffer .clear ()
311+ if buffer :
312+ for item in reversed (buffer ):
313+ yield item
0 commit comments