ISO 6166
L'ISO 6166 relative aux instruments financiers - ISIN (International Securities Identification Number) est une norme datant de 2001 qui identifie internationalement les valeurs mobilières. Elle est utilisée pour identifier les actions, les obligations, les bons, les warrants et les trackers. Par commodité, et même si ce ne sont pas des titres, les indices boursiers sont également dotés d'un ISIN.
Sommaire |
Historique [modifier]
En 1981, l'idée d'une unification du marché européen a été mise en avant[1].
En 1989 le « groupe des 30 » recommande l'adoption du code ISIN comme standard international pour les titres financiers.
En 1990, l'Association of National Numbering Agencies (ANNA) est formée dans le but de maintenir et implémenter ce standard. L'Organisation internationale de normalisation (ISO) désigne l'ANNA comme l'autorité en la matière avec une plateforme commune à tous : l'International Central Securities Depository (ICSD)[2]. Clearstream Banking Luxembourg (CBL) et Euroclear Bank (EB) sont considérés comme des ICSD en Europe.
En 1994, à l'initiative de l'ANNA, le Global ISIN Access Mechanism (GIAM) est développé pour lier tous les National Numbering Agencies (NNA) sur le réseau électronique. Les NNA ont chacun leurs registres centraux (CSD) et sont responsables de la délivrance des ISINs dans leur pays. Dans les pays où il n'y a pas de NNA, trois agences de substitution ont été désignées. Exemple : le NNA du Luxembourg est CBL (ex Cedel). À cette époque, GIAM-1 tournait sous le SGBD Paradox et utilisait MQSeries pour l'envoi de messages[3].
En fin d'année 1997, les membres de l'ANNA ont décidé de changer pour un modèle basé sur l'Internet capable de gérer à la fois les ISIN, la CFI, SWIFT et le STP : GIAM-2 était né[4].
En 2000, l'EB, la CBL et la Depository Trust & Clearing Corporation (DTCC) établissent sur la base du EPIM: l'European Pre-issuance Messaging System (EPIM), un système de messagerie STP qui gère entre autres chose la distribution des ISINs. L'International Capital Market Association (ex IPMA) a défini les champs obligatoires et les valeurs par défaut des messages EPIM.
En France, c'est le 30 juin 2003 que le code ISIN a remplacé le code SICOVAM pour identifier les principaux instruments financiers, dans un souci de faciliter les échanges trans-frontaliers et la normalisation au niveau international des marchés financiers[5].
En février 2005, on comptait 2,85 millions d'ISIN représentant 2,16 millions de titres. Le temps d'allocation et de distribution des ISINs a été réduit de plus de deux heures à moins de deux minutes[6].
En 2006, la Banque de France lance le projet NORIA, qui permet aux banques françaises d'immatriculer électroniquement les titres de créance négociables dont elles sont domiciliataires[7].
Composition [modifier]
| composition du code ISIN | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | |
| code du pays |
NSIN | clé de contrôle |
||||||||||
L'ISIN est composé de 12 caractères alphanumériques, les deux premiers servant à identifier le pays de cotation de la valeur selon la norme ISO 3166-1.
Toutefois, les titres immatriculés par les ICSD Clearstream et Euroclear Bank ont pour préfixe les lettres 'XS'.
NSIN [modifier]
Le NSIN est assigné par le NNA (national numbering agency) de chaque pays :
- En Allemagne, le NNA est la société WM Datenservice et le NSIN est le (de)WKN.
- Au Royaume-Uni, le NNA est le London Stock Exchange et le NSIN est le SEDOL.
- En Amérique du Nord, c'est le CUSIP qui est utilisé comme NSIN.
- En France, c'est Euronext qui attribue les NSIN (pour les titres antérieurs à l'adoption de cette norme, le code SICOVAM est utilisé comme NSIN).
Exemples [modifier]
| Table de conversion des lettres en chiffres | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 | |||||
- France Telecom : FR0000133308 (FR + SICOVAM 13330 + 8)
- Indice CAC 40 : FR0003500008 (FR + SICOVAM 350000 + 8)
- Microsoft : US5949181045
Calcul de validité [modifier]
Note : Dans le déroulement de la vérification, les nombres obtenus à certaines étapes sont traités à l'étape suivante comme une suite de chiffre les composants (exemple : 34 devient 3 et 4)
- Convertir toutes les lettres en nombres via la table de conversion (voir plus haut) excepté pour la clé qui servira de vérification à la fin de la vérification.
- Pour chaque chiffre, doublez sa valeur si sa position est une valeur impaire en partant de la droite.
- Faire la somme de tous les chiffres
- Soustraire cette somme de la dizaine supérieure (ou égale) la plus proche pour obtenir la clé. Par conséquence, si la somme précédemment obtenue est une dizaine, la clé vaudra zéro.
- Comparez la valeur obtenue à la clé.
Démonstration [modifier]
Le code utilisé sera le suivant : FR0003500008
Etape 1 :
F R 0 0 0 3 5 0 0 0 0 (+ 8 : clé)
15 27 0 0 0 3 5 0 0 0 0
Etape 2 : le traitement se fait sur des chiffres
1 5 2 7 0 0 0 3 5 0 0 0 0
I P I P I P I P I P I P I : position en partant de la droite (P = Pair, I = Impair)
2 1 2 1 2 1 2 1 2 1 2 1 2 : coefficient multiplicateur
2 5 4 7 0 0 0 3 10 0 0 0 0 : resultat
Etape 3 :
2 + 5 + 4 + 7 + 0 + 0 + 0 + 3 + (1 + 0)+ 0 + 0 + 0 + 0 = 22
Etape 4 et 5 : 30 - 22 = 8 (valeur de la clé)
Fonction VBA pour Excel pour vérifier un code ISIN :
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
Code TSQL pour vérifier un code ISIN :
-- ================================================ 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 [dbo].[fn_IsISINValid] ( @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
Code JavaScript pour vérifier un ISIN :
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)); }
Code Java code pour valider un code ISIN :
private static final Pattern ISIN_PATTERN = Pattern.compile("[A-Z]{2}([A-Z0-9]){9}[0-9]"); public static boolean checkIsinCode(String isin) { if (isin == null) { return false; } if (!ISIN_PATTERN.matcher(isin).matches()) { return false; } StringBuffer digits = new StringBuffer(); 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)); if (i % 2 == 0) { digit *= 2; } sum += digit / 10; sum += digit % 10; } int checkDigit = Character.digit(isin.charAt(11)); int tensComplement = (sum % 10 == 0) ? 0 : ((sum / 10) + 1) * 10 - sum; return checkDigit == tensComplement; }
Code C# pour valider un code ISIN :
using System; using System.Text.RegularExpressions; namespace ISIN { public static class ISINChecker { public static bool CheckIsinCode(string isin) { Regex ISIN_PATTERN = new Regex(@"[A-Z]{2}([A-Z0-9]){9}[0-9]"); if (isin == null) { return false; } if (!ISIN_PATTERN.IsMatch(isin)) { return false; } int[] digits = new int[22]; int index = 0; for (int i = 0; i < 11; i++) { char c = isin[i]; if (c >= '0' && c <= '9') { digits[index++] = c - '0'; } else if (c >= 'A' && c <= 'Z') { int n = c - 'A' + 10; int tens = n / 10; if (tens != 0) { digits[index++] = tens; } digits[index++] = 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[index - 1 - i]; if (i % 2 == 0) { digit *= 2; } sum += digit / 10; sum += digit % 10; } int checkDigit = isin[11] - '0'; int tensComplement = (sum % 10 == 0) ? 0 : ((sum / 10) + 1) * 10 - sum; return checkDigit == tensComplement; } } }
Code Python pour valider un code ISIN
import re def checkISIN(value): value = value.strip().upper() m = re.match('^([A-Z][A-Z])([A-Z0-9]{9}\d)$', value) if not m: return False sum_digits_str = ''.join(str(int(c, 36)) for c in value[:11]) 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[11] == unicode(check_digit) if __name__ == "__main__": for i in [ 'US0378331005', 'AU0000XVGZA3', 'GB0002634946']: print i, checkISIN(i)
Code SAS pour valider un code ISIN :
/* 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;
Code PHP pour valider un code ISIN :
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; for($i=0; $i<strlen($isinConvertion); ++$i) $sum .= (($i % 2) ? 1 : 2)*$isinConvertion[$i]; for($i=0; $i<strlen($sum); ++$i) $sumFinal += $sum[$i]; if ($sumFinal % 10){ $cleVerif = ((int)($sumFinal/10) + 1)*10-$sumFinal; } else { $cleVerif = 0; } if ($cle == $cleVerif) { return true; } else { return false; } } else { return false; } }
Immatriculation d'un ISIN et admission chez un dépositaire central [modifier]
A quelques exceptions près, notamment les États-Unis et la Suisse, le NNA d'un pays est son dépositaire central. En France, l'affectation d'un code ISIN à un titre (son immatriculation) est la fonction de l'Agence Française de Codification (AFC), un service d'Euroclear France. Toutes les actions cotées en bourse sont nécessairement inscrites en Euroclear France, et par conséquent dotées d'un code ISIN. En revanche, les fonds communs de placement ne font pas nécessairement l'objet d'une demande d'admission chez un dépositaire, notamment les fonds dédiés, conçus pour un souscripteur unique, un investisseur institutionnel ; le fonds ne reçoit alors pas de code ISIN. De même, certains titres de taux, quelquefois émis spécifiquement pour un investisseur unique, n'ont pas besoin d'être admis chez un dépositaire central en l'absence de perspective d'un marché secondaire.
Quant aux titres de créance négociable (TCN), la Banque de France a systématisé la procédure d'immatriculation avec son système NORIA. C'est le domiciliataire qui assure le rôle de NNA. Mais de façon générale, les titres du marché interbancaire, dont la durée est très courte (en France, 1 jour suffit pour un certificat de dépôt) et qui ne font pas l'objet de négociations sur un marché secondaire, n'ont pas besoin d'être admis chez le dépositaire central, et donc de recevoir un code ISIN.
Si l'identification d'un titre par un code ISIN est une condition nécessaire pour le rendre livrable entre les affiliés d'un dépositaire central, c'est-à-dire pour le rendre négociable entre clients domiciliés dans deux établissements bancaires différents, elle ne le garantit pas : si, en France, tous les TCN ont un code ISIN, un petit nombre seulement est admis chez Euroclear France.
Notes et références [modifier]
- (en) Reciprocity and the Unification of the European Banking Market, Douglas Croham, Group of Thirty, New York and London
- (fr) Papier de proposition d'ANNA sur ISO 6166 / ISIN
- (en) GIAM Annual Report 1998
- (en) COORDINATED PORTFOLIO INVESTMENT SURVEY GUIDE, Fonds monétaire international, May 10 - 2002 , Second Edition, Appendix VII: International Securities Identification Number (ISIN) Code System, p161-163
- (fr) Page concernant le code ISIN sur Euronext
- (en) IPMA - INTERNATIONAL PRIMARY MARKET ASSOCIATION - Secretary General - CESAME Barrier 8 final report 4 March
- [PDF] Identification des Titres de Créances Négociables par le code ISIN dans le projet NORIA, sur le site de la Banque de France. Consulté le 27 juillet 2012