SEDOL Validation in Python
Format checks and check digit algorithms catch typos, but they cannot tell you whether a SEDOL identifies a live security. Here's how to validate SEDOLs properly in Python with a single API call.
In this guide
1. What is a SEDOL?
A SEDOL (Stock Exchange Daily Official List) is a 7-character alphanumeric identifier assigned by the London Stock Exchange Group (LSEG) to securities. Introduced in 1979, SEDOLs are the primary identifier in the UK financial infrastructure — used by settlement systems, regulatory filings, and data vendors alike.
CREST (the UK and Irish central securities depository, operated by Euroclear) references SEDOLs in settlement instructions. The FCA requires SEDOLs in MiFIR transaction reports alongside ISINs. The SEDOL Masterfile — the authoritative source maintained by LSEG — contains over 100 million securities from exchanges worldwide.
Despite its UK origins, SEDOL is widely used in global financial data pipelines, particularly for European and international equities processed through UK-based custodians and prime brokers.
2. SEDOL anatomy
Every SEDOL is exactly 7 characters: 6 alphanumeric base characters followed by a 1-digit check digit.
| Part | Positions | Length | Description |
|---|---|---|---|
| Base code | 1 – 6 | 6 | Alphanumeric identifier assigned by LSEG (digits 0–9 and consonants B–Z in modern codes) |
| Check digit | 7 | 1 | Single digit (0–9) computed using a weighted modulo-10 algorithm |
Some well-known examples:
| SEDOL | Base (1–6) | Check (7) | Security |
|---|---|---|---|
| 0798059 | 079805 | 9 | BP PLC |
| 0540528 | 054052 | 8 | HSBC Holdings PLC |
| 0718875 | 071887 | 5 | Rio Tinto PLC |
3. The check digit algorithm
The SEDOL check digit uses a weighted modulo-10 algorithm with fixed position weights [1, 3, 1, 7, 3, 9]. Character values: digits 0–9 map to 0–9, letters A–Z map to 10–35 (A=10, B=11, … Z=35).
Steps:
- Convert each of the first 6 characters to its numeric value.
- Multiply each value by the corresponding weight from
[1, 3, 1, 7, 3, 9]. - Sum all 6 products to get
S. - Check digit =
(10 - S % 10) % 10.
Here is what a naive Python implementation looks like:
# sedol_check.py — naive implementation (format + check digit only) import re WEIGHTS = [1, 3, 1, 7, 3, 9] SEDOL_RE = re.compile(r'^[A-Z0-9]{6}[0-9]$') def char_value(ch: str) -> int: """Return numeric value of a SEDOL character. Digits 0-9 → 0-9, letters A-Z → 10-35. """ if ch.isdigit(): return int(ch) if ch.isalpha(): return ord(ch) - ord('A') + 10 raise ValueError(f"Invalid SEDOL character: {ch!r}") def compute_check_digit(base6: str) -> int: """Compute the SEDOL check digit for the first 6 characters.""" total = sum(char_value(base6[i]) * WEIGHTS[i] for i in range(6)) return (10 - total % 10) % 10 def validate_sedol(sedol: str) -> dict: sedol = sedol.replace(' ', '').upper() if len(sedol) != 7 or not SEDOL_RE.match(sedol): return {'valid': False, 'reason': 'format'} expected = compute_check_digit(sedol[:6]) actual = int(sedol[6]) if expected != actual: return {'valid': False, 'reason': 'check_digit'} return { 'valid': True, 'sedol': sedol, 'check_digit': sedol[6], } # ── Examples ────────────────────────────────────────────────────────────────── print(validate_sedol('0798059')) # valid — BP PLC print(validate_sedol('0540528')) # valid — HSBC Holdings print(validate_sedol('0798051')) # invalid check digit print(validate_sedol('07980')) # invalid format
4. Why manual validation is not enough
No free public database
The SEDOL Masterfile is a commercial product — there is no freely downloadable list of all valid SEDOLs. Maintaining your own lookup table is impractical; an API backed by OpenFIGI is the standard alternative for most applications.
Delistings and corporate actions
A structurally valid SEDOL may refer to a company that was acquired, merged, or delisted years ago. A correct check digit cannot distinguish an active BP PLC share from a retired SEDOL that was once assigned to a now-defunct fund.
Legacy codes with vowels
LSEG stopped using vowels in new SEDOLs in 2004, but millions of older codes with vowels remain valid and in active use. A validator that rejects vowels incorrectly flags valid legacy identifiers.
5. The right solution: one API call
The IsValid SEDOL API combines format validation, check digit verification, and live OpenFIGI enrichment in a single GET /v0/sedol request.
Get your free API key at isvalid.dev.
Full parameter reference and response schema: SEDOL Validation API docs →
6. Python code example
Using the isvalid-sdk package or the requests library directly.
# sedol_validator.py import os from isvalid_sdk import IsValid iv = IsValid(api_key=os.environ["ISVALID_API_KEY"]) # ── Example usage ───────────────────────────────────────────────────────────── result = iv.sedol("0798059") # BP PLC if not result["valid"]: print("Invalid SEDOL: failed format or check digit") else: print(f"SEDOL : {result['sedol']}") print(f"Check digit : {result['checkDigit']}") if result.get("found"): print(f"Name : {result.get('name')}") print(f"Ticker : {result.get('ticker')}") print(f"Exchange : {result.get('exchCode')}") print(f"FIGI : {result.get('figi')}") print(f"Sector : {result.get('marketSector')}")
Expected output for 0798059:
SEDOL : 0798059 Check digit : 9 Name : BP PLC Ticker : BP/ Exchange : LN FIGI : BBG000BT4FC2 Sector : Equity
In a Django or FastAPI view:
# views.py (Django) / router.py (FastAPI) from fastapi import APIRouter, HTTPException import requests, os router = APIRouter() API_KEY = os.environ["ISVALID_API_KEY"] @router.get("/securities/validate-sedol") def validate_sedol_endpoint(sedol: str): if not sedol: raise HTTPException(status_code=400, detail="Missing sedol parameter") try: resp = requests.get( "https://api.isvalid.dev/v0/sedol", params={"value": sedol}, headers={"Authorization": f"Bearer {API_KEY}"}, timeout=10, ) resp.raise_for_status() result = resp.json() except requests.RequestException: raise HTTPException(status_code=502, detail="SEDOL validation service unavailable") if not result["valid"]: raise HTTPException(status_code=400, detail=f"Invalid SEDOL: {sedol}") return { "sedol": result["sedol"], "checkDigit": result["checkDigit"], "found": result.get("found"), "name": result.get("name"), "ticker": result.get("ticker"), "exchCode": result.get("exchCode"), "figi": result.get("figi"), }
7. cURL example
Validate a SEDOL from the command line:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/sedol?value=0798059"
HSBC Holdings:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/sedol?value=0540528"
Invalid check digit:
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.isvalid.dev/v0/sedol?value=0798051"
8. Understanding the response
Response for a valid SEDOL found in OpenFIGI:
{ "valid": true, "sedol": "0798059", "checkDigit": "9", "found": true, "dataSource": "openfigi", "name": "BP PLC", "ticker": "BP/", "exchCode": "LN", "securityType": "Common Stock", "marketSector": "Equity", "figi": "BBG000BT4FC2", "compositeFIGI": "BBG000BT4FC2" }
Response for an invalid SEDOL:
{ "valid": false }
| Field | Type | Description |
|---|---|---|
| valid | boolean | Format + check digit validation result |
| sedol | string | Normalised (uppercased) SEDOL |
| checkDigit | string | The 7th character (always a digit 0–9) |
| found | boolean | null | true — found in OpenFIGI; false — not found; null — OpenFIGI unavailable |
| name | string | null | Full instrument name |
| ticker | string | null | Exchange ticker symbol |
| exchCode | string | null | Bloomberg exchange code (e.g. LN for London) |
| securityType | string | null | Security type (e.g. Common Stock) |
| marketSector | string | null | Market sector (e.g. Equity) |
| figi | string | null | Financial Instrument Global Identifier |
| compositeFIGI | string | null | Composite FIGI across all exchanges |
9. Edge cases to handle
found: null vs. found: false
found: false means OpenFIGI responded but did not recognise the SEDOL. found: null means the lookup failed (timeout, rate limit). In the null case, the SEDOL is still structurally valid — treat it as inconclusive and retry.
10. Summary
| What | Detail |
|---|---|
| Format | 7 characters: 6 alphanumeric + 1 check digit |
| Check algorithm | Weighted sum with weights [1,3,1,7,3,9], modulo 10 |
| Issuing authority | LSEG (London Stock Exchange Group) |
| Coverage | UK, Ireland, and globally traded instruments |
| Enrichment source | OpenFIGI (Bloomberg) via ID_SEDOL |
| API endpoint | GET /v0/sedol?value=0798059 |
- ISIN validation — ISINs embed SEDOLs for GB-prefixed codes
- CUSIP validation — the North American equivalent
- SEDOL Validation in Node.js