Add Trading212 ticker normalisation
Context
-------
Phase 1 kickoff: Trading212 tags every ticker with `_EQ`, sometimes
preceded by a lowercase exchange letter ("l" = LSE) or `_US`. Raw
symbols like `VUAGl_EQ` are an implementation detail that would leak
into Wealthfolio and diverge from other providers (InvestEngine and
Schwab emit `VUAG` / `META`). The canonical form has to match across
providers so portfolio aggregation lines up.
Unlike the finance/ reference code, we do NOT restrict to a
SUPPORTED_TICKERS allowlist here — Wealthfolio is the source of truth,
everything gets imported, and the user decides what to track.
This change
-----------
- broker_sync/providers/trading212.py: pure `_normalise_ticker`
helper backed by a single regex that peels `(_US)?[a-z]?_EQ`. No
lookup tables — the rule covers all observed shapes.
- tests/providers/test_trading212_ticker.py: parametrised cases for
every mapping called out in the Phase 1 plan plus pass-through of
already-canonical symbols.
Test plan
---------
## Automated
- poetry run pytest -q → 41 passed in 0.46s
- poetry run mypy broker_sync tests → Success: no issues found in 22 source files
- poetry run ruff check . → All checks passed!
## Manual Verification
Not applicable — pure function, no external side effects.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0eb6feefa8
commit
73b03b227e
3 changed files with 42 additions and 0 deletions
15
broker_sync/providers/trading212.py
Normal file
15
broker_sync/providers/trading212.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
_SUFFIX_RE = re.compile(r"(?:_US)?(?:[a-z])?_EQ$")
|
||||
|
||||
|
||||
def _normalise_ticker(raw: str) -> str:
|
||||
"""Strip T212's exchange-suffix decoration from a ticker.
|
||||
|
||||
T212 tags every ticker with `_EQ`, optionally preceded by a lowercase
|
||||
letter ("l" for LSE) or `_US` for a US listing. Peel those off so the
|
||||
symbol matches what Schwab / InvestEngine emit.
|
||||
"""
|
||||
return _SUFFIX_RE.sub("", raw)
|
||||
0
tests/providers/__init__.py
Normal file
0
tests/providers/__init__.py
Normal file
27
tests/providers/test_trading212_ticker.py
Normal file
27
tests/providers/test_trading212_ticker.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from broker_sync.providers.trading212 import _normalise_ticker
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("raw", "expected"),
|
||||
[
|
||||
# T212 LSE suffix: lowercase "l" before _EQ means London listing.
|
||||
("VUAGl_EQ", "VUAG"),
|
||||
("VUSAl_EQ", "VUSA"),
|
||||
("VWRPl_EQ", "VWRP"),
|
||||
("METAl_EQ", "META"),
|
||||
# T212 US suffix: _US_EQ means US listing. Strip the whole suffix.
|
||||
("META_US_EQ", "META"),
|
||||
("AAPL_US_EQ", "AAPL"),
|
||||
# Plain _EQ suffix with no exchange letter.
|
||||
("FOO_EQ", "FOO"),
|
||||
# Already canonical — passes through.
|
||||
("VUAG", "VUAG"),
|
||||
("META", "META"),
|
||||
],
|
||||
)
|
||||
def test_normalise_ticker(raw: str, expected: str) -> None:
|
||||
assert _normalise_ticker(raw) == expected
|
||||
Loading…
Add table
Add a link
Reference in a new issue