Skip to content

Commit 88f1a10

Browse files
Add client example to client.electricity_trading.__main__
Signed-off-by: camille-bouvy-frequenz <[email protected]>
1 parent 59b0434 commit 88f1a10

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Examples usage of the Electricity Trading API."""
5+
6+
import argparse
7+
import asyncio
8+
import enum
9+
from datetime import datetime, timedelta, timezone
10+
from decimal import Decimal
11+
from typing import Any, Type, TypeVar
12+
13+
from frequenz.client.electricity_trading import (
14+
Client,
15+
Currency,
16+
DeliveryArea,
17+
DeliveryPeriod,
18+
EnergyMarketCodeType,
19+
MarketSide,
20+
OrderType,
21+
Power,
22+
Price,
23+
)
24+
25+
T = TypeVar("T", bound=enum.Enum)
26+
27+
# Default delivery duration for orders.
28+
# This is a constant as it is the only duration currently supported by the API.
29+
DELIVERY_DURATION = timedelta(minutes=15)
30+
31+
# Default energy market code type.
32+
ENERGY_MARKET_CODE_TYPE = EnergyMarketCodeType.EUROPE_EIC
33+
34+
# Maximum number of public trades to receive when testing streaming.
35+
MAX_NR_OF_PUBLIC_TRADES = 5
36+
37+
38+
def main() -> None:
39+
"""Parse arguments and run the client."""
40+
parser = argparse.ArgumentParser()
41+
parser.add_argument(
42+
"--url",
43+
type=str,
44+
help="URL of the Electricity Trading service. Default is the testing environment.",
45+
default="grpc://electricity-trading-testing.api.frequenz.com:443?ssl=true",
46+
)
47+
parser.add_argument(
48+
"--api_key",
49+
type=str,
50+
help="API key for the Electricity Trading service",
51+
required=True,
52+
)
53+
parser.add_argument(
54+
"--gridpool_id",
55+
type=int,
56+
help="Gridpool ID",
57+
required=True,
58+
)
59+
60+
# Optional arguments for various request parameters
61+
parser.add_argument(
62+
"--price",
63+
type=Decimal,
64+
help="Price of the order. Default is 50.",
65+
required=False,
66+
default=Decimal("50.0"),
67+
)
68+
parser.add_argument(
69+
"--quantity",
70+
type=Decimal,
71+
help="Quantity of the order. Default is 0.1.",
72+
required=False,
73+
default=Decimal("0.1"),
74+
)
75+
parser.add_argument(
76+
"--delivery_area_code",
77+
type=str,
78+
help="Delivery area code of the order (in EIC format). Default is TenneT.",
79+
required=False,
80+
default="10YDE-EON------1", # TenneT
81+
)
82+
parser.add_argument(
83+
"--currency",
84+
type=Currency,
85+
help="Currency of the order. Default is EUR.",
86+
required=False,
87+
default=Currency.EUR,
88+
)
89+
parser.add_argument(
90+
"--order_type",
91+
type=OrderType,
92+
help="Type of order (specifies how the order is to be executed in the market). "
93+
"Default is LIMIT.",
94+
required=False,
95+
default=OrderType.LIMIT,
96+
)
97+
parser.add_argument(
98+
"--side",
99+
type=str,
100+
help="Side of the order (BUY or SELL). Default is BUY.",
101+
required=False,
102+
default="BUY",
103+
)
104+
parser.add_argument(
105+
"--delivery_start",
106+
type=datetime.fromisoformat,
107+
help="Start of the delivery period in YYYY-MM-DDTHH:MM:SS format. "
108+
"Default is tomorrow at 12:00.",
109+
required=False,
110+
default=(datetime.now(timezone.utc) + timedelta(days=1)).replace(
111+
hour=12, minute=0, second=0, microsecond=0
112+
),
113+
)
114+
115+
args = parser.parse_args()
116+
117+
# Run the example
118+
asyncio.run(run(args))
119+
120+
121+
def parse_enum(enum_type: Type[T], value: str) -> T:
122+
"""
123+
Parse enum types in argparse.
124+
125+
Args:
126+
enum_type: The enum class to parse the value for.
127+
value: The string value to parse.
128+
129+
Returns:
130+
The corresponding enum member.
131+
132+
Raises:
133+
argparse.ArgumentTypeError: If the value is not a valid enum member.
134+
"""
135+
if isinstance(value, enum_type):
136+
# If the value is already an enum member, return it.
137+
return value
138+
try:
139+
return enum_type[value.upper()]
140+
except KeyError as exc:
141+
raise argparse.ArgumentTypeError(
142+
f"Invalid value: {value}. Must be one of {', '.join(enum_type.__members__.keys())}"
143+
) from exc
144+
145+
146+
def convert_args_to_order_params(args: argparse.Namespace) -> dict[str, Any]:
147+
"""Convert command line arguments to order parameters.
148+
149+
Args:
150+
args: The command line arguments.
151+
152+
Returns:
153+
A dictionary of order parameters.
154+
"""
155+
order_params: dict[str, Any] = {}
156+
if args.price and args.currency:
157+
currency = parse_enum(Currency, args.currency)
158+
order_params["price"] = Price(amount=args.price, currency=currency)
159+
if args.quantity:
160+
order_params["quantity"] = Power(mw=args.quantity)
161+
if args.delivery_area_code:
162+
order_params["delivery_area"] = DeliveryArea(
163+
code=args.delivery_area_code, code_type=ENERGY_MARKET_CODE_TYPE
164+
)
165+
if args.delivery_start:
166+
order_params["delivery_period"] = DeliveryPeriod(
167+
start=args.delivery_start, duration=DELIVERY_DURATION
168+
)
169+
if args.order_type:
170+
order_params["order_type"] = parse_enum(OrderType, args.order_type)
171+
if args.side:
172+
order_params["side"] = parse_enum(MarketSide, args.side)
173+
return order_params
174+
175+
176+
async def run(args: argparse.Namespace) -> None:
177+
"""Run the Electricity Trading client."""
178+
order_params = convert_args_to_order_params(args)
179+
client = Client(server_url=args.url, auth_key=args.api_key)
180+
181+
# Create an order
182+
order = await client.create_gridpool_order(
183+
gridpool_id=args.gridpool_id,
184+
delivery_area=order_params["delivery_area"],
185+
delivery_period=order_params["delivery_period"],
186+
side=order_params["side"],
187+
price=order_params["price"],
188+
quantity=order_params["quantity"],
189+
order_type=order_params["order_type"],
190+
)
191+
print(f"Created order: {order}\n")
192+
193+
# List all orders, filtered by delivery period
194+
async for order in client.list_gridpool_orders(
195+
gridpool_id=args.gridpool_id,
196+
delivery_period=order_params["delivery_period"],
197+
):
198+
print(f"Order: {order}\n")
199+
200+
# Stream public trades & stop after 5 trades
201+
stream_public_trades = await client.stream_public_trades()
202+
for _ in range(MAX_NR_OF_PUBLIC_TRADES):
203+
public_trade = await anext(stream_public_trades)
204+
print(f"Received public trade: {public_trade}\n")
205+
206+
207+
if __name__ == "__main__":
208+
main()

0 commit comments

Comments
 (0)