International Securities Identification Number - ISIN Calculation Methodology

ISIN Calculation Methodology

The procedure for calculating ISIN check digits is similar to the "Modulus 10 Double Add Double" technique used in CUSIPs. To calculate the check digit, first convert any letters to numbers by adding their ordinal position in the alphabet to 9, such that A = 10 and M = 22. Starting with the right most digit, every other digit is multiplied by two. (For CUSIP check digits, these two steps are reversed.) The resulting string of digits (numbers greater than 9 becoming two separate digits) are added up. Subtract this sum from the smallest number ending with zero that is greater than or equal to it: this gives the check digit, which is also known as the ten's complement of the sum modulo 10. That is, the resulting sum, including the check-digit, is a multiple of 10.

ISINs are slowly being introduced worldwide. At present, trading, clearing and settlement systems in many countries have adopted ISINs as a secondary measure of identifying securities. Additionally, some of those countries, mainly in Europe, have moved to using ISINs as their primary means of identifying securities.

Conversion table for characters is :

A = 10 F = 15 K = 20 P = 25 U = 30 Z = 35
B = 11 G = 16 L = 21 Q = 26 V = 31
C = 12 H = 17 M = 22 R = 27 W = 32
D = 13 I = 18 N = 23 S = 28 X = 33
E = 14 J = 19 O = 24 T = 29 Y = 34

In other words; Take the ASCII code for the capital letter and subtract 55

C function for validating an ISINCode:

int isIsinValid(const char *isin) { int d1, d2, sum, multiply, i; if (!isin || strlen(isin) != 12 || !isdigit(isin)) return 0; for (sum = 0, multiply = 1, i = 10; i > -1; --i) { switch (i) { case 0: case 1: if (isupper(isin)) d1 = isin - 'A' + 10; else return 0; break; default: if (isupper(isin)) d1 = isin - 'A' + 10; else if (isdigit(isin)) d1 = isin - '0'; else return 0; break; } if (d1 < 10) { d1 *= (multiply ? 2 : 1); multiply = !multiply; } else { d2 = d1 / 10; d1 %= 10; d1 *= (multiply ? 2 : 1); d2 *= (multiply ? 1 : 2); sum += (d2 % 10) + (d2 / 10); } sum += (d1 % 10) + (d1 / 10); } sum %= 10; sum = 10 - sum; sum %= 10; if (sum != isin - '0') return 0; return 1; }

Fortran function for validating an ISINCode:

* * Checks whether an ISIN is valid * LOGICAL FUNCTION IS_ISIN(ISIN) CHARACTER*13 ISIN INTEGER I INTEGER NEWSUM, OLDSUM INTEGER D1 INTEGER D2 LOGICAL MULTIPLY LOGICAL IS_DIGIT LOGICAL IS_UPPER IF (LEN_TRIM(ISIN) .NE. 12) THEN IS_ISIN = .FALSE. RETURN ENDIF IF (IS_DIGIT(ISIN(12:12)) .EQV. .FALSE.) THEN IS_ISIN = .FALSE. RETURN ENDIF NEWSUM = 0 MULTIPLY = .TRUE. DO I = 11, 1, -1 IF (I .EQ. 0 .OR. I .EQ. 1) THEN IF (IS_UPPER(ISIN(I:I))) THEN D1 = IACHAR(ISIN(I:I)) - IACHAR('A') + 10 ELSE IS_ISIN = .FALSE. RETURN ENDIF ELSE IF (IS_UPPER(ISIN(I:I))) THEN D1 = IACHAR(ISIN(I:I)) - IACHAR('A') + 10 ELSE IF (IS_DIGIT(ISIN(I:I))) THEN D1 = IACHAR(ISIN(I:I)) - IACHAR('0') ELSE IS_ISIN = .FALSE. RETURN ENDIF ENDIF IF (D1 .LT. 10) THEN IF (MULTIPLY) THEN D1 = D1 * 2 ENDIF MULTIPLY = .NOT. MULTIPLY ELSE D2 = D1 / 10 D1 = MOD(D1, 10) IF (MULTIPLY) THEN D1 = D1 * 2 ELSE D2 = D2 * 2 ENDIF NEWSUM = NEWSUM + MOD(D2, 10) + (D2 / 10) ENDIF NEWSUM = NEWSUM + MOD(D1, 10) + (D1 / 10) ENDDO NEWSUM = MOD(NEWSUM, 10) NEWSUM = 10 - NEWSUM NEWSUM = MOD(NEWSUM, 10) OLDSUM = IACHAR(ISIN(12:12)) - IACHAR('0') IF (OLDSUM .NE. NEWSUM) THEN IS_ISIN = .FALSE. RETURN ENDIF IS_ISIN = .TRUE. RETURN END * * Checks whether a character is a digit * LOGICAL FUNCTION IS_DIGIT(C) CHARACTER*1 C CHARACTER*10 DIGIT INTEGER INDX DIGIT = '0123456789' INDX = INDEX(DIGIT, C) IF (INDX .NE. 0) THEN IS_DIGIT = .TRUE. ELSE IS_DIGIT = .FALSE. ENDIF RETURN END * * Checks whether a character is an uppercase letter * LOGICAL FUNCTION IS_UPPER(C) CHARACTER*1 C CHARACTER*26 UPPER INTEGER INDX UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' INDX = INDEX(UPPER, C) IF (INDX .NE. 0) THEN IS_UPPER = .TRUE. ELSE IS_UPPER = .FALSE. ENDIF RETURN END

Excel VBA Function for validating an ISINCode:

Public Function ISINCODE(ByVal sISINCode As String) As Boolean 'Jelle-Jeroen Lamkamp 28 Apr 2008 Dim i As Integer: Dim iTotalScore As Integer Dim s As String: Dim sDigits As String sISINCode = UCase(Trim(sISINCode)) If Len(sISINCode) <> 12 Then Exit Function If MID(sISINCode,1,1) < "A" Or MID(sISINCode,1,1) > "Z" Then Exit Function If MID(sISINCode,2,1) < "A" Or MID(sISINCode,2,1) > "Z" Then Exit Function sDigits = "" For i = 1 To 11 s = Mid(sISINCode, i, 1) If s >= "0" And s <= "9" Then sDigits = sDigits & s ElseIf s >= "A" And s <= "Z" Then sDigits = sDigits & CStr(Asc(s) - 55) Else Exit Function End If Next i sDigits = StrReverse(sDigits) iTotalScore = 0 For i = 1 To Len(sDigits) iTotalScore = iTotalScore + CInt(Mid(sDigits, i, 1)) If i Mod 2 = 1 Then iTotalScore = iTotalScore + CInt(Mid(sDigits, i, 1)) If CInt(Mid(sDigits, i, 1)) > 4 Then iTotalScore = iTotalScore - 9 End If End If Next i If (10 - (iTotalScore Mod 10)) Mod 10 = CInt(Mid(sISINCode, 12, 1)) Then ISINCODE = True End Function

TSQL code for validating an ISINCode:

-- ================================================ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: Pang Chong Peng -- Create date: 20/7/2010 -- Description: CheckSum for ISIN code -- ============================================= CREATE FUNCTION . ( @ISINCode AS NVARCHAR(20)) RETURNS BIT AS BEGIN DECLARE @i AS INT; DECLARE @iTotalScore AS int; DECLARE @s AS INT; DECLARE @sDigit AS VARCHAR(22); /* Edit 101004 csouto: Needs to be 22 characters long so it can validate Isin Codes for 'Lotes PadrĂ£o' */ SELECT @ISINCode = UPPER(@ISINCode); IF LEN (@ISINCode) != 12 RETURN 0; IF ASCII(SUBSTRING(@ISINCode, 1, 1)) < ASCII('A') OR ASCII(SUBSTRING(@ISINCode, 1, 1)) > ASCII('Z') RETURN 0; IF ASCII(SUBSTRING(@ISINCode, 2, 1)) < ASCII('A') OR ASCII(SUBSTRING(@ISINCode, 2, 1)) > ASCII('Z') RETURN 0; IF (ISNUMERIC(SUBSTRING(@ISINCode, 12, 1)) = 0) -- Check that the checksum is numeric RETURN 0; SELECT @sDigit = ''; SELECT @i = 1; WHILE (@i <= 11) BEGIN SELECT @s = ASCII(SUBSTRING(@ISINCode, @i, 1)) IF @s >= ASCII('0') AND @s <= ASCII('9') SELECT @sDigit = @sDigit + SUBSTRING(@ISINCode, @i, 1); ELSE IF @s >= ASCII('A') AND @s <= ASCII('Z') SELECT @sDigit = @sDigit + CONVERT(VARCHAR(2), @s - 55); ELSE BREAK; SELECT @i = @i + 1; END SELECT @sDigit = REVERSE(@sDigit); SELECT @iTotalScore = 0; SELECT @i = 1; WHILE (@i <= LEN(@sDigit)) BEGIN SELECT @iTotalScore = @iTotalScore + CONVERT(INT, SUBSTRING(@sDigit, @i, 1)) IF @i%2 = 1 BEGIN SELECT @iTotalScore = @iTotalScore + CONVERT(INT, SUBSTRING(@sDigit, @i, 1)) IF CONVERT(INT, (SUBSTRING(@sDigit, @i, 1))) > 4 BEGIN SELECT @iTotalScore = @iTotalScore - 9; END END SELECT @i = @i + 1; END IF (10 - (@iTotalScore%10))%10 = CONVERT (INT,(SUBSTRING(@ISINCode, 12, 1))) RETURN 1; RETURN 0; END

JavaScript code for validating an ISINCode:

function checkISINCODE(sISINCode){ var i, iTotalScore, s, sDigits; if( sISINCode.length != 12){ return false; } if( sISINCode.charCodeAt(0) < "A".charCodeAt(0) || sISINCode.charCodeAt(0) > "Z".charCodeAt(0) ){ return false; } if( sISINCode.charCodeAt(1) < "A".charCodeAt(0) || sISINCode.charCodeAt(1) > "Z".charCodeAt(0) ){ return false; } sDigits = ""; for(var i = 0; i < 11; i++){ sDigits += parseInt(sISINCode.charAt(i), 36); } var sDigits = sDigits.split("").reverse.join(""); var iTotalScore = 0; for(var i = 0; i< sDigits.length; i++){ iTotalScore += parseInt(sDigits.charAt(i)); if (i % 2 == 0){ iTotalScore += parseInt(sDigits.charAt(i)); if ( parseInt(sDigits.charAt(i)) > 4 ){ iTotalScore -= 9; } } } return (10 - (iTotalScore % 10)) % 10 == parseInt(sISINCode.charAt(11)); }

Java code for validating an ISINCode:

private static final Pattern ISIN_PATTERN = Pattern.compile("{2}{9}"); public static boolean checkIsinCode(final String isin) { if (isin == null) { return false; } if (!ISIN_PATTERN.matcher(isin).matches) { return false; } StringBuilder digits = new StringBuilder; for (int i = 0; i < 11; ++i) { digits.append(Character.digit(isin.charAt(i), 36)); } digits.reverse; int sum = 0; for (int i = 0; i < digits.length; ++i) { int digit = Character.digit(digits.charAt(i), 36); if (i % 2 == 0) { digit *= 2; } sum += digit / 10; sum += digit % 10; } int checkDigit = Character.digit(isin.charAt(11), 36); int tensComplement = (sum % 10 == 0) ? 0 : ((sum / 10) + 1) * 10 - sum; return checkDigit == tensComplement; }

C# Code for validating an ISINCode:

using System; using System.Text.RegularExpressions; namespace ISIN { public static class ISINChecker { public static bool CheckIsinCode(string isin) { Regex ISIN_PATTERN = new Regex(@"{2}{9}"); if (isin == null) { return false; } if (!ISIN_PATTERN.IsMatch(isin)) { return false; } int digits = new int; int index = 0; for (int i = 0; i < 11; i++) { char c = isin; if (c >= '0' && c <= '9') { digits = c - '0'; } else if (c >= 'A' && c <= 'Z') { int n = c - 'A' + 10; int tens = n / 10; if (tens != 0) { digits = tens; } digits = n % 10; } else { // Not a digit or upper-case letter. return false; } } int sum = 0; for (int i = 0; i < index; i++) { int digit = digits; if (i % 2 == 0) { digit *= 2; } sum += digit / 10; sum += digit % 10; } int checkDigit = isin - '0'; int tensComplement = (sum % 10 == 0) ? 0 : ((sum / 10) + 1) * 10 - sum; return checkDigit == tensComplement; } } }

Python code for validating ISIN codes

import re def checkISIN(value): value = value.strip.upper m = re.match('^({9}\d)$', value) if not m: return False sum_digits_str = ''.join(str(int(c, 36)) for c in value) total_sum = 0 parity = len(sum_digits_str) % 2 for n, c in enumerate(sum_digits_str): a = int(c) if n % 2 != parity: a = a * 2 total_sum += a / 10 total_sum += a % 10 check_digit = (10 - (total_sum % 10)) % 10 return value == unicode(check_digit) if __name__ == "__main__": for i in [ 'US0378331005', 'AU0000XVGZA3', 'GB0002634946']: print i, checkISIN(i)

SAS code for validating ISIN codes

/* Aitor Olasagasti Alonso 2011-04-19 */ /* SAS 8.2 and SAS 9.X compatible */ data trueIsin; set isinTable; length allCode $24; ilegal = 0; if length(isin) ^= 12 then delete; lastNum = substr(isin, 12, 1); code = rank(lastNum); if not (code >= 48 and code =< 57) then delete; do i = 1 to 11; code = rank(substr(isin, i, 1)); if code <48 or (code > 57 and code < 65) or code > 90 then ilegal = 1; if (i = 1 or i = 2) and (code < 65 or code > 90) then ilegal = 1; if code >= 65 and code =< 90 then do; code = code-55; allCode = compress(allCode) || compress(put(code, best.)); end; else do; allCode = compress(allCode) || substr(isin, i, 1); end; end; if ilegal then delete; suma = 0; rAllCode = reverse(trim(allCode)); rlength = length(rAllCode); do i = 1 to rlength; numb = input(substr(rAllCode, i, 1), best.); if mod(i, 2) then do; numb = numb * 2; if numb / 10 >= 1 then do; suma = suma + mod(numb, 10) + 1; end; else do; suma = suma + (numb); end; end; else do; suma = suma + numb; end; end; modSum = mod(suma, 10); total = mod(10 - modSum, 10); if total ^= input(lastNum, best.) then delete; run;

PHP Code for validating an ISINCode:

function isIsin($isin) { if (strlen(trim($isin))) { $cle = substr($isin, -1); $isinLeft = substr($isin, 0, strlen($isin)-1); $letter2number = array('A'=>10, 'B'=>11, 'C'=>12, 'D'=>13, 'E'=>14, 'F'=>15, 'G'=>16, 'H'=>17, 'I'=>18, 'J'=>19, 'K'=>20, 'L'=>21, 'M'=>22, 'N'=>23, 'O'=>24, 'P'=>25, 'Q'=>26, 'R'=>27, 'S'=>28, 'T'=>29, 'U'=>30, 'V'=>31, 'W'=>32, 'X'=>33, 'Y'=>34, 'Z'=>35); $isinConvertion = strtr($isinLeft, $letter2number); $sum = ''; $sumFinal = 0; $offset = (strlen($isinConvertion) + 1) % 2; $isinConvertionLen = strlen($isinConvertion); for($i=0; $i < $isinConvertionLen; ++$i) $sum .= ((($i + $offset) % 2) ? 1 : 2) * $isinConvertion; $sumLen = strlen($sum); for($i=0; $i < $sumLen; ++$i) $sumFinal += $sum; if ($sumFinal % 10){ $cleVerif = ((int)($sumFinal/10) + 1) * 10 - $sumFinal; } else { $cleVerif = 0; } if ($cle == $cleVerif) { return true; } else { return false; } } else { return false; } }

UNIX shell script for validating a list of ISIN Codes:

#!/bin/bash # GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu) # # created by: Erik Klamer # date: 26/06/2012 # usage: save code in script and run with argument # pointing to file containing list of ISIN codes cat $1|while read ISIN ; do {2}{10} ]] || continue unset CALC unset REVCALC SUM=0 for i in {0..10} ; do CHAR=${ISIN:$i:1} ]] && VALUE=$(expr $(printf "%d\n" "'${CHAR}") - 55) ]] && VALUE=${CHAR} CALC=${CALC}${VALUE} done REVCALC=$(echo ${CALC}|rev) for (( i = 0; i < ${#REVCALC}; i++ )) ; do if ] ; then MCHAR=$(expr ${REVCALC:$i:1} \* 2) ] && MCHAR=$(expr ${MCHAR:0:1} + ${MCHAR:1:1}) else MCHAR=${REVCALC:$i:1} fi SUM=$(expr ${SUM} + ${MCHAR}) done MOD=$(expr 10 - ${SUM:${#SUM}-1:1}) ] && MOD=0 ] && echo ${ISIN} done

Read more about this topic:  International Securities Identification Number

Famous quotes containing the words calculation and/or methodology:

    “To my thinking” boomed the Professor, begging the question as usual, “the greatest triumph of the human mind was the calculation of Neptune from the observed vagaries of the orbit of Uranus.”
    “And yours,” said the P.B.
    Samuel Beckett (1906–1989)

    One might get the impression that I recommend a new methodology which replaces induction by counterinduction and uses a multiplicity of theories, metaphysical views, fairy tales, instead of the customary pair theory/observation. This impression would certainly be mistaken. My intention is not to replace one set of general rules by another such set: my intention is rather to convince the reader that all methodologies, even the most obvious ones, have their limits.
    Paul Feyerabend (1924–1994)