Skip to content

feat: add EXAA exchange adapter#19

Merged
tommed merged 2 commits intomainfrom
feat/exaa-exchange-adapter
Mar 26, 2026
Merged

feat: add EXAA exchange adapter#19
tommed merged 2 commits intomainfrom
feat/exaa-exchange-adapter

Conversation

@tommed
Copy link
Contributor

@tommed tommed commented Mar 26, 2026

Summary

  • Adds nexa_bidkit.exaa — a market adapter that converts internal bid objects into EXAA Trading API order submission payloads, following the same architectural patterns as nexa_bidkit.nordpool
  • Adds reference/exaa.md domain reference document for EXAA API order model
  • Documents the EXAA module in README

Design notes

Key differences from Nord Pool:

Aspect Nord Pool EXAA
Volume sign SELL=positive, BUY=negative BUY=positive, SELL=negative
Grouping Per-bid payloads Account-centric (accountID)
Product IDs Dynamic resolver per MTU+zone Resolver per MTU; blocks by DeliveryPeriod
Auction ID In request body URL path only — not in payload
Linked/exclusive blocks Supported Not supported — raises ValueError
typeOfOrder N/A LINEAR or STEP, per product-type container
fillOrKill N/A Derived from bid.is_indivisible for blocks

Supported bid types:

  • SimpleBid with HOURLY MTU → hourlyProducts container
  • SimpleBid with QUARTER_HOURLY MTU → 15minProducts container
  • BlockBidblockProducts container (requires block_product_resolver)
  • LinkedBlockBid / ExclusiveGroupBidValueError

Convenience helpers standard_hourly_product_id() and standard_quarter_hourly_product_id() generate the canonical EXAA product IDs (hEXA01hEXA24, qEXA01_1qEXA24_4) directly from MTU start times.

Test plan

  • 57 tests in tests/test_exaa.py — all passing
  • exaa.py at 100% coverage
  • mypy src — no issues
  • ruff check src tests — no issues

🤖 Generated with Claude Code

tommed and others added 2 commits March 26, 2026 16:01
Implements nexa_bidkit.exaa — a market adapter that converts internal bid
objects into EXAA Trading API order submission payloads, consistent with
the existing Nord Pool adapter pattern.

Key differences from Nord Pool:
- Account-centric grouping: all bids submitted under a single accountID
- Volume sign convention is reversed: positive = buy, negative = sell
- typeOfOrder (STEP/LINEAR) applies at the product-type container level
- No linked block bids or exclusive groups (raises ValueError)
- No auction ID in the request body (it goes in the URL path)
- fillOrKill derived from bid.is_indivisible for block products

Public API:
- ExaaOrderType enum (STEP, LINEAR)
- Pydantic models: PriceVolumePair, ExaaProduct, ExaaProductTypeContainer,
  ExaaAccountOrder, ExaaUnits, ExaaOrderRequest
- Type aliases: ProductIdResolver, BlockProductResolver
- bidding_zone_to_control_area() — AT/DE-LU/NL only
- standard_hourly_product_id() / standard_quarter_hourly_product_id()
- simple_bid_to_exaa_product(), block_bid_to_exaa_product()
- order_book_to_exaa() — dispatches SimpleBids and BlockBids to the
  correct product type containers

Also adds reference/exaa.md domain reference and README documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apply ruff line-length formatting to exaa.py and test_exaa.py, fix
trailing newline in checks.md, and update executed notebook outputs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Mar 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@tommed tommed merged commit 4c302a5 into main Mar 26, 2026
2 checks passed
@tommed tommed deleted the feat/exaa-exchange-adapter branch March 26, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant