Skip to content

Commit 72fa1dc

Browse files
authored
Add utils module with quantity quantization helper (#105)
This helper supports users to create quantities that conform to the API expectations.
2 parents cace663 + 1ccf5e6 commit 72fa1dc

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010

1111
## New Features
1212

13-
* Use decorator for `from_pb` methods to ensure an error message with protobuf data is logged in case there are conversion problems.
13+
* Add helper function to support creating quantities that conform to the API expectations.
1414

1515
<!-- Here goes the main new features and examples or instructions on how to use them -->
1616

1717
## Bug Fixes
1818

19-
* Deal correctly with cancelled orders with no price or quantity
20-
2119
<!-- Here goes notable bug fixes that are worth a special mention or explanation -->

src/frequenz/client/electricity_trading/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ async def stream_trades():
212212
TradeState,
213213
UpdateOrder,
214214
)
215+
from ._utils import quantize_quantity
215216

216217
__all__ = [
217218
"Client",
@@ -243,4 +244,5 @@ async def stream_trades():
243244
"MIN_QUANTITY_MW",
244245
"PRECISION_DECIMAL_QUANTITY",
245246
"PRECISION_DECIMAL_PRICE",
247+
"quantize_quantity",
246248
]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Utility functions for the electricity trading API client."""
5+
6+
from decimal import Decimal
7+
8+
from ._client import PRECISION_DECIMAL_QUANTITY
9+
10+
11+
def quantize_quantity(value: Decimal | float) -> Decimal:
12+
"""Convert a decimal to a quantity with the correct precision for the API.
13+
14+
Simply rounds the value to the correct precision using HALF_EVEN rounding.
15+
16+
Args:
17+
value: The value to convert in float or Decimal.
18+
19+
Returns:
20+
The quantity with the correct precision as a Decimal.
21+
"""
22+
dec = Decimal(str(value)) if isinstance(value, float) else value
23+
quantity_step = Decimal(f"1e-{PRECISION_DECIMAL_QUANTITY}")
24+
quantized = Decimal(dec).quantize(quantity_step, rounding="ROUND_HALF_EVEN")
25+
return quantized

tests/test_utils.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# License: MIT
2+
# Copyright © 2023 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Tests for helper utilities module."""
5+
6+
from decimal import Decimal
7+
8+
from frequenz.client.electricity_trading import quantize_quantity
9+
10+
11+
def test_quantize_quantity() -> None:
12+
"""Test the quantize_quantity function."""
13+
14+
def test(inp: str, out: str) -> None:
15+
# check for float
16+
resf = quantize_quantity(float(inp))
17+
# ... and decimal
18+
resd = quantize_quantity(Decimal(inp))
19+
20+
# check correct type
21+
assert isinstance(resf, Decimal)
22+
assert isinstance(resd, Decimal)
23+
24+
# check correct value
25+
assert resf == resd == Decimal(out)
26+
27+
# check negative
28+
resn = quantize_quantity(-float(inp))
29+
assert isinstance(resn, Decimal)
30+
assert resn == Decimal(out) * -1
31+
32+
test("0.0", "0")
33+
test("0.01", "0")
34+
test("0.05", "0") # round down in ROUND_HALF_EVEN mode
35+
test("0.051", "0.1")
36+
test("0.1", "0.1")
37+
test("0.15", "0.2") # round up in ROUND_HALF_EVEN mode
38+
test("0.5", "0.5")
39+
test("1", "1")
40+
test("99.89", "99.9")

0 commit comments

Comments
 (0)