broker-sync/tests/providers/test_finance_mysql.py
Viktor Barzin a190875f63 Add finance_mysql provider + CLI for historical backfill
finance.position (171 rows, 2020-06-07 to 2025-12-19) is the only source
of InvestEngine + Schwab trade history pre-dating the broker-sync project.
This provider reads it once and pushes every row into the correct WF
account (.L tickers → IE ISA, others → Schwab).

Dedup: external_id = 'finance-mysql:position:<PK>' — idempotent on re-run.
Auth: aiomysql as MySQL root (user-authorized) against the standalone
mysql:8.4 in-cluster service.

New CLI: broker-sync finance-mysql-import
New tests: 5 unit tests covering route, symbol normalise, BUY/SELL
detection.

poetry run pytest -q   →  114 passed, 1 skipped
poetry run mypy        →  clean (aiomysql shielded with type: ignore)
poetry run ruff check  →  clean
2026-04-17 22:38:21 +00:00

66 lines
2.1 KiB
Python

from __future__ import annotations
from datetime import UTC, datetime
from decimal import Decimal
from broker_sync.models import AccountType, ActivityType
from broker_sync.providers.finance_mysql import _normalise_symbol, _route, _row_to_activity
def test_lse_ticker_routes_to_investengine() -> None:
acct, t, ccy = _route("VUAG.L")
assert acct == "invest-engine-primary"
assert t is AccountType.ISA
assert ccy == "GBP"
def test_us_ticker_routes_to_schwab() -> None:
assert _route("META") == ("schwab-workplace", AccountType.GIA, "USD")
assert _route("FLME_US_EQ") == ("schwab-workplace", AccountType.GIA, "USD")
def test_normalise_symbol() -> None:
assert _normalise_symbol("VUAG.L") == "VUAG"
assert _normalise_symbol("VUSA.L") == "VUSA"
assert _normalise_symbol("META") == "META"
assert _normalise_symbol("FLME_US_EQ") == "FLME"
assert _normalise_symbol("FOO_EQ") == "FOO"
def test_row_to_buy_activity() -> None:
row = {
"id": "123456",
"ticker": "VUAG.L",
"buy_price": 85.5,
"num_shares": 10.0,
"currency": "GBP",
"buy_date": datetime(2022, 3, 15, 10, 30),
"account_id": 1,
}
a = _row_to_activity(row)
assert a.external_id == "finance-mysql:position:123456"
assert a.account_id == "invest-engine-primary"
assert a.account_type is AccountType.ISA
assert a.activity_type is ActivityType.BUY
assert a.symbol == "VUAG" # .L stripped
assert a.quantity == Decimal("10.0")
assert a.unit_price == Decimal("85.5")
assert a.currency == "GBP"
assert a.date == datetime(2022, 3, 15, 10, 30, tzinfo=UTC)
def test_row_to_sell_when_qty_negative() -> None:
row = {
"id": "x",
"ticker": "META",
"buy_price": 450.0,
"num_shares": -2.5, # sell
"currency": "USD",
"buy_date": datetime(2024, 8, 5),
"account_id": 1,
}
a = _row_to_activity(row)
assert a.activity_type is ActivityType.SELL
assert a.quantity == Decimal("2.5") # absolute
assert a.account_id == "schwab-workplace"
assert a.symbol == "META"