javascripttypescriptfinance

Validate an ISIN number in Typescript


I'm looking for a function in typescript/js that validates an International Securities Identification Number (ISIN) number

ie

validateISIN("FR0014001NN8") // true
validateISIN("FR0014001NN7") // false

Solution

  • Inspire from https://rosettacode.org/wiki/Validate_International_Securities_Identification_Number and How to validate a International Securities Identification Number (ISIN) number

    /**
     * Regex to only validate structure
     * -A two-letter country code, drawn from a list (ISO 6166) prepared by the International Organization for Standardization (ISO). This code is assigned according to the location of a company's head office. A special code, 'XS'. is used for international securities cleared through pan-European clearing systems like Euroclear and CEDEL. Depository receipt ISIN usage is unique in that the country code for the security is that of the receipt issuer, not that of the underlying security.
     * - A nine-digit numeric identifier, called the National Securities Identifying Number (NSIN), and assigned by each country's or region's . If a national number is composed of less than nine digits, it is padded with leading zeros to become a NSIN. The numeric identifier has no intrinsic meaning it is essentially a serial number.
     * - A single check-digit. The digit is calculated based upon the preceding 11 characters/digits and uses a sum modulo 10 algorithm and helps ensure against counterfeit numbers.
     * @link https://www.isin.org/isin/
     */
    const regexRule =
        /^(?<countryCode>EU|XS|AD|AE|AF|AG|AI|AL|AM|AO|AQ|AR|AS|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BJ|BL|BM|BN|BO|BQ|BR|BS|BT|BV|BW|BY|BZ|CA|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|CR|CU|CV|CW|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EE|EG|EH|ER|ES|ET|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|IO|IQ|IR|IS|IT|JE|JM|JO|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MF|MG|MH|MK|ML|MM|MN|MO|MP|MQ|MR|MS|MT|MU|MV|MW|MX|MY|MZ|NA|NC|NE|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|SS|ST|SV|SX|SY|SZ|TC|TD|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TR|TT|TV|TW|TZ|UA|UG|UM|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|YE|YT|ZA|ZM|ZW)(?<NISIN>[0-9A-Z]{9})(?<checkDigit>[0-9]{1})$/;
    
    
    /**
     * Validate if an ISIN is well formed
     * @param ISIN International Securities Identification Number of a 12-digit alphanumeric code
     * @returns true if good ISIN
     * @link https://www.isin.org/isin/
     * @example
     *  ```ts
     * // OAT 2072
     *  validateISIN("FR0014001NN8") // true
     *  validateISIN("FR0014001NN7") // false
     * ```
     */
    export function validateISIN(isin: string): boolean {
        // ISIN format is not respected
        if (isin.length !== 12 || !regexRule.test(isin)) {
            return false;
        }
    
        const convertChar = (char: string) =>
            char.match(/[A-Z]/) ? (char.charCodeAt(0) - 55).toString() : char;
    
        const digits = isin
            .split("")
            .map(convertChar)
            .join("");
    
        let sum = 0;
        let alternate = false;
        for (let i = digits.length - 1; i >= 0; i--) {
            let n = parseInt(digits.charAt(i), 10);
            if (alternate) {
                n *= 2;
                if (n > 9) n -= 9;
            }
            sum += n;
            alternate = !alternate;
        }
        return sum % 10 === 0;
    }
    
    const testisin = [
        "IE00BFMXXD54",
        "IE00BK5BQT80",
        "IE00BFMXYP42",
        "IE00BG47KH54",
        "IE00BFZXGZ54",
        "IE00BYVTMS52",
        "IE000XZSV718",
        "IE00BYYW2V44",
        "IE00BFY0GT14",
        "IE000BZ1HVL2",
        "LU0908500753",
        "IE00B4K48X80",
        "DE0005933956",
        "IE0002XZSHO1",
        "IE000ONQ3X90",
        "IE00BJ0KDQ92",
        "LU0290358497",
        "LU0490618542",
        "LU2196472984",
        "FR0014001NN7",
        "FR0014001NN8",
    ];
    
    testisin.map((x) => {
        console.log(validateISIN(x));
    });