phase B (1/4): CSV parser + InstrumentMap (T212 shortcode → Yahoo ticker)

First two slices of the multi-user roadmap (Phase B). Validates the
core onboarding mechanic against the user's real T212 export before
paying any auth/tenancy tax.

CSV parser (app/services/csv_import.py):
  - Header-name matched (survives T212 reordering columns between
    exports), tolerant of UTF-8 BOM, dash/N/A/empty markers, thousand-
    separator commas, blank rows, zero-quantity stubs, missing Total row.
  - Returns ParsedPie(name, positions, invested, value, result) with
    derived avg_price + current_price per share in account currency.
  - 14 tests covering happy path on the real CSV + 13 edge cases.

InstrumentMap (migration 0006 + app/services/instrument_map.py):
  - Catalogue table mapping T212 ticker → Yahoo ticker, populated by
    sync_from_t212() against the dev's read-only API key. Manual rows
    (manual=True) are protected from auto-overwrite.
  - Pure t212_ticker_to_yahoo() handles both suffix forms: single
    trailing exchange letter (l/a/p/d/m/s/...) and country code (US,
    DE, FR, IT, CA, ...). All 13 of the user's holdings + 15 case-
    coverage tests pass.
  - Live sync against T212 ingests 17,050 instruments (~2.2% unmappable
    on exotic exchanges; can extend the suffix map later).
  - resolve_slice() picks the right listing per shortName using a
    UK-friendly currency preference (GBX > GBP > EUR > USD). Resolved
    correctly for all 13 of the user's positions, including TTE on
    Paris vs the NYSE dual-listing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Giorgio Gilestro 2026-05-16 10:53:08 +01:00
parent 6dac8a2c7f
commit 16e9f5f0cc
7 changed files with 840 additions and 0 deletions

15
tests/fixtures/t212_pie_export.csv vendored Normal file
View file

@ -0,0 +1,15 @@
"Slice","Name","Invested value","Value","Result","Owned quantity","Dividends gained","Dividends cash","Dividends reinvested"
"SGLN","iShares Physical Gold",2325,2324.3,-0.7,"35.12084592","N/A","N/A","N/A"
"IGLS","iShares UK Gilts 0-5yr (Dist)",2092.5,2089.84,-2.66,"16.59397303","N/A","N/A","N/A"
"VEUR","Vanguard FTSE Developed Europe (Dist)",1511.25,1507.96,-3.29,"36.59200968","N/A","N/A","N/A"
"HMCH","HSBC MSCI China (Dist)",1162.5,1160.88,-1.62,"197.68022163","N/A","N/A","N/A"
"INRG","iShares Global Clean Energy Transition (Dist)",1162.5,1170.95,8.45,"125.20193861","N/A","N/A","N/A"
"VFEM","Vanguard FTSE Emerging Markets (Dist)",581.25,581.11,-0.14,"9.55610357","N/A","N/A","N/A"
"VJPN","Vanguard FTSE Japan (Dist)",581.25,582.61,1.36,"15.48657829","N/A","N/A","N/A"
"BA","BAE Systems",578.34,563.12,-15.22,"30.43093922","N/A","N/A","N/A"
"TTE","TotalEnergies",346.83,349.06,2.23,"5.08932089","N/A","N/A","N/A"
"NATP","Future of Defence UCITS ETF (Acc)",348.75,347.1,-1.65,"23.59926918","N/A","N/A","N/A"
"EQNR","Equinor",348.23,358.52,10.29,"12.14586234","N/A","N/A","N/A"
"SHEL","Shell",347.01,350.47,3.46,"10.97091368","N/A","N/A","N/A"
"BP","BP",231.34,233.41,2.07,"42.26932212","N/A","N/A","N/A"
"Total","Defensive Ex-US 2026",11616.75,11619.33,2.58,"-","0","0","0"
1 Slice Name Invested value Value Result Owned quantity Dividends gained Dividends cash Dividends reinvested
2 SGLN iShares Physical Gold 2325 2324.3 -0.7 35.12084592 N/A N/A N/A
3 IGLS iShares UK Gilts 0-5yr (Dist) 2092.5 2089.84 -2.66 16.59397303 N/A N/A N/A
4 VEUR Vanguard FTSE Developed Europe (Dist) 1511.25 1507.96 -3.29 36.59200968 N/A N/A N/A
5 HMCH HSBC MSCI China (Dist) 1162.5 1160.88 -1.62 197.68022163 N/A N/A N/A
6 INRG iShares Global Clean Energy Transition (Dist) 1162.5 1170.95 8.45 125.20193861 N/A N/A N/A
7 VFEM Vanguard FTSE Emerging Markets (Dist) 581.25 581.11 -0.14 9.55610357 N/A N/A N/A
8 VJPN Vanguard FTSE Japan (Dist) 581.25 582.61 1.36 15.48657829 N/A N/A N/A
9 BA BAE Systems 578.34 563.12 -15.22 30.43093922 N/A N/A N/A
10 TTE TotalEnergies 346.83 349.06 2.23 5.08932089 N/A N/A N/A
11 NATP Future of Defence UCITS ETF (Acc) 348.75 347.1 -1.65 23.59926918 N/A N/A N/A
12 EQNR Equinor 348.23 358.52 10.29 12.14586234 N/A N/A N/A
13 SHEL Shell 347.01 350.47 3.46 10.97091368 N/A N/A N/A
14 BP BP 231.34 233.41 2.07 42.26932212 N/A N/A N/A
15 Total Defensive Ex-US 2026 11616.75 11619.33 2.58 - 0 0 0