broker-sync/tests
Viktor Barzin 7d2c1199a9 Add Trading212Provider core fetch
Context
-------
The Provider protocol is satisfied. This commit adds the first cut of
the concrete Trading212 implementation: one page of fills, mapped to
canonical Activities. Pagination, retries, and checkpointing on
resume are deliberately deferred to the next commit so this one stays
focused on the raw shape translation.

Design decisions
----------------
- One provider instance serves every T212 wrapper (ISA + Invest). T212
  exposes one API key per wrapper, so the caller hands over a list of
  (Account, api_key) pairs. `accounts()` returns only the Accounts —
  the keys never escape the provider.
- Auth: literal `Authorization: <api_key>`, NOT `Bearer <api_key>`.
  T212 quietly returns 401 for Bearer-prefixed keys. The test locks
  that in.
- Sell detection: T212 signs quantity (negative means closing a long
  or opening a short). We flip on the sign and store `abs(quantity)`,
  matching the Wealthfolio BUY/SELL convention.
- Null fills (cancelled orders) are silently dropped at parse time
  rather than surfacing to the caller.
- `external_id = t212:fill:<fill.id>` — the fill ID is stable per
  T212 docs and survives order cancellation/modification semantics.
- Ticker normalisation runs on ingress so downstream dedup + Wealthfolio
  see `VUAG` even though T212 reports `VUAGl_EQ`.
- `since` / `before` filter on `filledAt`. `before` is half-open
  (`< before`) so CronJobs can chain adjacent windows without
  double-counting the boundary.

Explicitly NOT in this change:
- Pagination (nextPagePath walk)
- 429 / 5xx retry
- Dividend / deposit endpoints (deferred — Phase 1.1, filed as
  beads follow-up if needed)

This change
-----------
- broker_sync/providers/trading212.py: `Trading212Provider` class +
  `Trading212Error` / `Trading212AuthError` exception hierarchy.
  `_item_to_activity` is pure and returns Optional so cancelled
  fills short-circuit without raising.
- tests/providers/test_trading212.py: MockTransport-driven tests for
  auth header shape, fill→Activity mapping (buy + sell sign flip),
  null-fill skip, since-filter, and both error types.

Test plan
---------
## Automated
- poetry run pytest -q  →  61 passed in 0.60s
- poetry run mypy broker_sync tests  →  Success: no issues found in 27 source files
- poetry run ruff check .  →  All checks passed!

## Manual Verification
Deferred to the CLI wiring commit — the live endpoint is 6 calls/min
and the full-volume dry run belongs with the env-driven command, not
the unit-level commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:34:03 +00:00
..
fixtures Add ECB FX fetcher + cache population 2026-04-17 19:32:23 +00:00
providers Add Trading212Provider core fetch 2026-04-17 19:34:03 +00:00
sinks Add WealthfolioSink with CSV import + cookie reuse 2026-04-17 19:22:34 +00:00
__init__.py Initial scaffold + canonical Activity model 2026-04-17 19:16:11 +00:00
test_cli.py Add typer CLI + production Dockerfile 2026-04-17 19:23:54 +00:00
test_dedup.py Add SyncRecordStore for authoritative dedup 2026-04-17 19:17:12 +00:00
test_fx.py Add FxCache and convert_to_gbp core 2026-04-17 19:18:41 +00:00
test_fx_ecb.py Add ECB FX fetcher + cache population 2026-04-17 19:32:23 +00:00
test_models.py Initial scaffold + canonical Activity model 2026-04-17 19:16:11 +00:00
test_normaliser.py Add Provider protocol and normaliser 2026-04-17 19:20:12 +00:00