Converting CUSIP-6, CUSIP-8 and CUSIP-9 to ISIN in PHP

When working with securities data, you often have to convert between security identifier schemes. Sometimes you get ISINs, other times you get CUSIPs (and other times, CIKs, but that’s another story). The result is that you need to be able to convert between these schemes. There are pseudo-code algorithms for converting a CUSIP-9 to an ISIN, but I couldn’t find any in PHP, and I also wanted to be able to convert a CUSIP-6 or CUSIP-8 to an ISIN.

But first, here’s an ISIN primer. For the PHP checksum code, skip on ahead.

The difference between a CUSIP-6 and a CUSIP-8 is the addition of a stock or security issue identifier. By default, this is usually ’10’ for common stock, but if more than one stock series has been issued by a company, it could also be ’50’ for ADR shares, ’90’ for call share options, or ’95’ for put options, among others. See this article for more information. Wikipedia also does a good job of explaining the issue numbers.

The 9th digit in a CUSIP-9 is a checksum digit, derived using the same calculation as is used to convert a CUSIP-9 to an ISIN. So you can use the same checksum algorithm for both the conversion from CUSIP-6/8 to CUSIP-9 as the one used to convert from CUSIP-9 to ISIN. The ISIN is completed by pre-pending the company’s two-letter country code to the CUSIP-9:

ANATOMY OF CUSIP-6, CUSIP-8, CUSIP-9, AND ISIN

Do note, however, that this works most reliably for US and Canadian companies. For companies that are based in other countries, don’t count on the results being 100% accurate. Some countries don’t systematically use CUSIPs, so you might generate a valid but fictitious ISIN. It’s always safest to double-check your results!

This is the basic checksum calculation code:

$cusip8 = "037833100"; // AAPL
$sum = 0;
for ($count = 1; $count <= 8; $count++) {
    $char = substr($cusip8, ($count - 1), 1);
    if (ctype_digit($char)) {
        // if character is numeric, get character's numeric value
        $value = intval($char);
    } elseif (ctype_alpha($char)) {
        // if character is alphabetic, get character's ordinal position in alphabet
        $position = ord(strtoupper($char)) - ord('A') + 1;
        $value = $position + 9;
    } elseif ($char == "*") {
        $value = 36;
    } elseif ($char == "@") {
        $value = 37;
    } elseif ($char == "#") {
        $value = 38;
    }
    // Is this character position even?
    if ($count % 2 == 0) {
        $value *= 2;
    }
    // calculate the checksum digit
    $sum += floor($value / 10 ) + ( $value % 10 );
}
// append checksum digit to CUSIP8
$result = $cusip8 . ((10 - ($sum%10))%10);
echo "The CUSIP-9 for " . $cusip8 . " is : " . $result;

Here’s the converter in action. Enter any CUSIP-6, CUSIP-8 or CUSIP-9, and select a country from the dropdown. To test, for USA, you can use 037833100, 458140 or 459200101. For Canada, you can use 878742204 or 67077M. For Germany, you can use 000BASF11:

Leave a Reply

Your email address will not be published. Required fields are marked *