Skip to content

Commit

Permalink
Convert between CUSIPs and ISINs (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
wtn authored Sep 19, 2024
1 parent c9d5183 commit bc69332
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ isin.valid? # => true
isin.valid_format? # => true
isin.restore! # => 'US5949181045'
isin.calculate_check_digit # => 5
isin.to_cusip # => #<SecId::CUSIP>
```

### SecId::CUSIP full example
Expand All @@ -137,6 +138,7 @@ cusip.valid? # => true
cusip.valid_format? # => true
cusip.restore! # => '594918104'
cusip.calculate_check_digit # => 4
cusip.to_isin('US') # => #<SecId::ISIN>
```

### SecId::SEDOL full example
Expand Down
9 changes: 9 additions & 0 deletions lib/sec_id/cusip.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ def calculate_check_digit
raise InvalidFormatError, "CUSIP '#{full_number}' is invalid and check-digit cannot be calculated!"
end

def to_isin(country_code)
ISIN::CGS_COUNTRY_CODES.include?(country_code) \
or raise(InvalidFormatError, "'#{country_code}' is not a CGS country code!")
restore!
isin = ISIN.new(country_code + full_number)
isin.restore!
isin
end

private

# https://en.wikipedia.org/wiki/Luhn_algorithm
Expand Down
15 changes: 15 additions & 0 deletions lib/sec_id/isin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ def calculate_check_digit
raise InvalidFormatError, "ISIN '#{full_number}' is invalid and check-digit cannot be calculated!"
end

CGS_COUNTRY_CODES = %w[
US CA KY BM VI VG UM TT SR GS SX VC MF LC KN BL PR PH PW
MP FM YT MH HT GY GU GD DM CW BQ BZ BS AW AG AI AS AN
].freeze

# CUSIP Global Services
def cgs?
CGS_COUNTRY_CODES.include?(country_code)
end

def to_cusip
cgs? or raise(InvalidFormatError, "'#{country_code}' is not a CGS country code!")
CUSIP.new(nsin)
end

private

# https://en.wikipedia.org/wiki/Luhn_algorithm
Expand Down
18 changes: 18 additions & 0 deletions spec/sec_id/cusip_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,24 @@
end
end

describe '#to_isin' do
context 'when CGS country code' do
let(:cusip_number) { '02153X108' }

it 'returns an ISIN' do
expect(cusip.to_isin('VI')).to be_a(SecId::ISIN)
end
end

context 'when non-CGS country code' do
let(:cusip_number) { '00B296YR7' }

it 'raises an error' do
expect { cusip.to_isin('IE') }.to raise_error(SecId::InvalidFormatError)
end
end
end

describe '.restore!' do
context 'when CUSIP is incorrect' do
it 'raises an error' do
Expand Down
20 changes: 20 additions & 0 deletions spec/sec_id/isin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@
end
end

describe '#to_cusip' do
context 'when CGS country code' do
let(:isin_number) { 'VI02153X1080' }

it 'returns a CUSIP' do
expect(isin.cgs?).to be(true)
expect(isin.to_cusip).to be_a(SecId::CUSIP)
end
end

context 'when non-CGS country code' do
let(:isin_number) { 'IE00B296YR77' }

it 'raises an error' do
expect(isin.cgs?).to be(false)
expect { isin.to_cusip }.to raise_error(SecId::InvalidFormatError)
end
end
end

describe '.valid?' do
context 'when ISIN is incorrect' do
it 'returns false' do
Expand Down

0 comments on commit bc69332

Please sign in to comment.