frb-participants 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 71f48b2e53492e20f33c820b865c895acc8ba3d4
4
+ data.tar.gz: af0778c9625cb332e59ebe2492ec5fb5e9412bea
5
+ SHA512:
6
+ metadata.gz: 8dd47c9b145874e7bf750e0685f7f335cfa7b06f69d4852d5113bbfbf63f47901f29d4a96e80aab7afe3fa5d88f5baf0f273e571fe3967d96a153ca4a01b28de
7
+ data.tar.gz: a3f6961d75c1ce7128d5f3eb2d2ec5167e97de73301ceac1071a367a339050386b4bb3b6e3bc5bdc291d7e91ed08c2f4c5a8befda97f2a496100f1c62ada914f
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.3.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'slither', git: 'https://github.com/ryanwood/slither'
4
+
5
+ # Specify your gem's dependencies in frb-participants.gemspec
6
+ gemspec
@@ -0,0 +1,84 @@
1
+ GIT
2
+ remote: https://github.com/ryanwood/slither
3
+ revision: 268fde22ebb756b154abdd3fa1e9f7fc7badf035
4
+ specs:
5
+ slither (0.99.5)
6
+
7
+ PATH
8
+ remote: .
9
+ specs:
10
+ frb-participants (0.1.0)
11
+ activesupport (>= 4)
12
+
13
+ GEM
14
+ remote: https://rubygems.org/
15
+ specs:
16
+ activesupport (5.0.2)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (~> 0.7)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ coderay (1.1.1)
22
+ concurrent-ruby (1.0.5)
23
+ diff-lcs (1.3)
24
+ domain_name (0.5.20170223)
25
+ unf (>= 0.0.5, < 1.0.0)
26
+ http-cookie (1.0.3)
27
+ domain_name (~> 0.5)
28
+ i18n (0.8.1)
29
+ method_source (0.8.2)
30
+ mime-types (3.1)
31
+ mime-types-data (~> 3.2015)
32
+ mime-types-data (3.2016.0521)
33
+ minitest (5.10.1)
34
+ neatjson (0.8.3)
35
+ netrc (0.11.0)
36
+ pry (0.10.3)
37
+ coderay (~> 1.1.0)
38
+ method_source (~> 0.8.1)
39
+ slop (~> 3.4)
40
+ rake (10.5.0)
41
+ rest-client (2.0.1)
42
+ http-cookie (>= 1.0.2, < 2.0)
43
+ mime-types (>= 1.16, < 4.0)
44
+ netrc (~> 0.8)
45
+ rspec (3.5.0)
46
+ rspec-core (~> 3.5.0)
47
+ rspec-expectations (~> 3.5.0)
48
+ rspec-mocks (~> 3.5.0)
49
+ rspec-core (3.5.4)
50
+ rspec-support (~> 3.5.0)
51
+ rspec-expectations (3.5.0)
52
+ diff-lcs (>= 1.2.0, < 2.0)
53
+ rspec-support (~> 3.5.0)
54
+ rspec-its (1.2.0)
55
+ rspec-core (>= 3.0.0)
56
+ rspec-expectations (>= 3.0.0)
57
+ rspec-mocks (3.5.0)
58
+ diff-lcs (>= 1.2.0, < 2.0)
59
+ rspec-support (~> 3.5.0)
60
+ rspec-support (3.5.0)
61
+ slop (3.6.0)
62
+ thread_safe (0.3.6)
63
+ tzinfo (1.2.3)
64
+ thread_safe (~> 0.1)
65
+ unf (0.1.4)
66
+ unf_ext
67
+ unf_ext (0.0.7.2)
68
+
69
+ PLATFORMS
70
+ ruby
71
+
72
+ DEPENDENCIES
73
+ bundler (~> 1.13)
74
+ frb-participants!
75
+ neatjson (~> 0.8)
76
+ pry (~> 0.10)
77
+ rake (~> 10.0)
78
+ rest-client (~> 2.0)
79
+ rspec (~> 3.0)
80
+ rspec-its (~> 1.2)
81
+ slither!
82
+
83
+ BUNDLED WITH
84
+ 1.14.3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Wealthsimple
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # frb-participants [![CircleCI](https://circleci.com/gh/wealthsimple/frb-participants.svg?style=svg)](https://circleci.com/gh/wealthsimple/frb-participants) [![](https://img.shields.io/gem/v/frb-participants.svg)](https://rubygems.org/gems/frb-participants)
2
+
3
+ Provides data from the The Federal Reserve Banks' Fedwire & FedACH participants in JSON format, mapping routing number to associated bank name and branch info.
4
+
5
+ For more details, see [Federal Reserve Bank Services: Download E-Payments Routing Directories](https://www.frbservices.org/EPaymentsDirectory/download.html)
6
+
7
+ ## Rubygem:
8
+
9
+ ```ruby
10
+ gem 'frb-participants', git: 'https://github.com/wealthsimple/frb-participants'
11
+ ```
12
+
13
+ You can do basic queries of data:
14
+
15
+ ```ruby
16
+ FrbParticipants::FedachParticipant.find_by_routing_number("322170016")
17
+ => #<OpenStruct
18
+ type=:ach,
19
+ customer_name="BANK OF AMERICA, N.A. - ARIZONA",
20
+ known_normalized_name="Bank of America",
21
+ best_attempt_normalized_name="Bank Of America, N.A. - Arizona"
22
+ office_type="main",
23
+ servicing_frb_number="121000374",
24
+ record_type_code="1",
25
+ revision_date="121503",
26
+ new_routing_number=nil,
27
+ address="VA2-430-01-01",
28
+ city="RICHMOND",
29
+ state="VA",
30
+ zip="23261",
31
+ zip_extension="7025",
32
+ telephone="8004460135">
33
+ ```
34
+
35
+ ```ruby
36
+ FrbParticipants::FedwireParticipant.find_by_routing_number("325182946")
37
+ => #<OpenStruct
38
+ type=:wire,
39
+ telegraphic_name="UMPQUA BANK WA",
40
+ customer_name="UMPQUA BANK",
41
+ known_normalized_name=nil,
42
+ best_attempt_normalized_name="Umpqua Bank",
43
+ state="OR",
44
+ city="HILLSBORO",
45
+ funds_transfer_eligible=true,
46
+ settlement_only=false,
47
+ securities_transfer_eligible=false,
48
+ revision_date="20160526">
49
+ ```
50
+
51
+ Important! If you are using this on a production service, it is recommended that you preload the data in an initializer:
52
+
53
+ ```ruby
54
+ require 'frb-participants'
55
+ FrbParticipants::Data.preload!
56
+ ```
57
+
58
+ ## Normalized data:
59
+
60
+ **[fedwire-participants.json](https://github.com/wealthsimple/frb-participants/blob/master/data/fedwire-participants.json)**
61
+
62
+ ```json
63
+ {
64
+ "325182836":{
65
+ "telegraphic_name":"LOWER VALLEY CU WA",
66
+ "customer_name":"LOWER VALLEY CREDIT UNION",
67
+ "state":"WA",
68
+ "city":"SUNNYSIDE",
69
+ "funds_transfer_eligible":true,
70
+ "settlement_only":false,
71
+ "securities_transfer_eligible":true,
72
+ "revision_date":"20120702"
73
+ },
74
+ "325182946":{
75
+ "telegraphic_name":"UMPQUA BANK WA",
76
+ "customer_name":"UMPQUA BANK",
77
+ "state":"OR",
78
+ "city":"HILLSBORO",
79
+ "funds_transfer_eligible":true,
80
+ "settlement_only":false,
81
+ "securities_transfer_eligible":false,
82
+ "revision_date":null
83
+ },
84
+ ...
85
+ }
86
+ ```
87
+
88
+ **[fedach-participants.json](https://github.com/wealthsimple/frb-participants/blob/master/data/fedach-participants.json)**
89
+
90
+ ```json
91
+ {
92
+ "011000015":{
93
+ "office_type":"main",
94
+ "servicing_frb_number":"011000015",
95
+ "record_type_code":"0",
96
+ "revision_date":"122415",
97
+ "new_routing_number":null,
98
+ "customer_name":"FEDERAL RESERVE BANK",
99
+ "address":"1000 PEACHTREE ST N.E.",
100
+ "city":"ATLANTA",
101
+ "state":"GA",
102
+ "zip":"30309",
103
+ "zip_extension":"4470",
104
+ "telephone":"8773722457"
105
+ },
106
+ ...
107
+ }
108
+ ```
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "frb-participants"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start
@@ -0,0 +1,67 @@
1
+ require "active_support/all"
2
+ require "slither"
3
+ require "pp"
4
+ require "json"
5
+ require "neatjson"
6
+ require "yaml"
7
+
8
+ # Format is defined at:
9
+ # https://www.frbservices.org/EPaymentsDirectory/achFormat.html
10
+ Slither.define :fedach_participants, by_bytes: false do |definition|
11
+ definition.body do |body|
12
+ body.trap { true }
13
+ # The institution's routing number
14
+ body.column :routing_number, 9, type: :string
15
+ # Main office or branch O=main B=branch
16
+ body.column :office_type, 1, type: :string
17
+ # Servicing Fed's main office routing number
18
+ body.column :servicing_frb_number, 9, type: :string
19
+ # The code indicating the ABA number to be used to route or send ACH items to the RFI
20
+ # 0 = Institution is a Federal Reserve Bank
21
+ # 1 = Send items to customer routing number
22
+ # 2 = Send items to customer using new routing number field
23
+ body.column :record_type_code, 1, type: :string
24
+ # Date of last change to CRF information (MMDDYY)
25
+ body.column :revision_date, 6, type: :string
26
+ # Institution's new routing number resulting from a merger or renumber
27
+ body.column :new_routing_number, 9, type: :string
28
+ # Commonly used abbreviated name
29
+ body.column :customer_name, 36, type: :string
30
+ # Delivery address
31
+ body.column :address, 36, type: :string
32
+ # City name in the delivery address
33
+ body.column :city, 20, type: :string
34
+ # State code of the state in the delivery address
35
+ body.column :state, 2, type: :string
36
+ # Zipcode in the delivery address
37
+ body.column :zip, 5, type: :string
38
+ # Zipcode extension in the delivery address
39
+ body.column :zip_extension, 4, type: :string
40
+ # CRF contact telephone number
41
+ body.column :telephone, 10, type: :string
42
+ # Code is based on the customers receiver code
43
+ # 1=Receives Gov/Comm
44
+ # body.column :institution_status, 1, type: :string
45
+ # 1=Current view
46
+ # body.column :data_view, 1, type: :string
47
+ end
48
+ end
49
+
50
+ parsed = Slither.parse("./vendor/FedACHdir.txt", :fedach_participants)[:body]
51
+
52
+ # Normalize fields where possible
53
+ parsed.map do |line|
54
+ line[:new_routing_number] = nil if line[:new_routing_number] == "000000000"
55
+ line[:zip_extension] = nil if line[:zip_extension] == "0000"
56
+ line[:office_type] = {"O" => "main", "B" => "branch"}[line[:office_type]]
57
+ line
58
+ end
59
+
60
+ # Participants keyed by routing number.
61
+ participants = {}
62
+ parsed.each do |line|
63
+ participants[line[:routing_number]] = line.except(:routing_number)
64
+ end
65
+
66
+ File.write("./data/fedach-participants.json", JSON.neat_generate(participants, wrap: 200, after_comma: 1))
67
+ File.write("./data/fedach-participants.yml", participants.to_yaml)
@@ -0,0 +1,43 @@
1
+ require "active_support/all"
2
+ require "slither"
3
+ require "pp"
4
+ require "json"
5
+ require "neatjson"
6
+ require "yaml"
7
+
8
+ # Format is defined at:
9
+ # https://www.frbservices.org/EPaymentsDirectory/fedwireFormat.html
10
+ Slither.define :fedwire_participants, by_bytes: false do |definition|
11
+ definition.body do |body|
12
+ body.trap { true }
13
+ body.column :routing_number, 9, type: :string
14
+ body.column :telegraphic_name, 18, type: :string
15
+ body.column :customer_name, 36, type: :string
16
+ body.column :state, 2, type: :string
17
+ body.column :city, 25, type: :string
18
+ body.column :funds_transfer_eligible, 1, type: :string
19
+ body.column :settlement_only, 1, type: :string
20
+ body.column :securities_transfer_eligible, 1, type: :string
21
+ body.column :revision_date, 8, type: :string
22
+ end
23
+ end
24
+
25
+ parsed = Slither.parse("./vendor/fpddir.txt", :fedwire_participants)[:body]
26
+
27
+ # Convert boolean fields from string => boolean
28
+ parsed.map do |line|
29
+ line[:funds_transfer_eligible] = line[:funds_transfer_eligible] == "Y"
30
+ line[:settlement_only] = line[:settlement_only] == "S"
31
+ line[:securities_transfer_eligible] = line[:securities_transfer_eligible] == "Y"
32
+ line[:revision_date] = line[:revision_date].presence
33
+ line
34
+ end
35
+
36
+ # Participants keyed by routing number.
37
+ participants = {}
38
+ parsed.each do |line|
39
+ participants[line[:routing_number]] = line.except(:routing_number)
40
+ end
41
+
42
+ File.write("./data/fedwire-participants.json", JSON.neat_generate(participants, wrap: 200, after_comma: 1))
43
+ File.write("./data/fedwire-participants.yml", participants.to_yaml)
@@ -0,0 +1,47 @@
1
+ require "active_support/all"
2
+ require "pp"
3
+ require "json"
4
+ require "neatjson"
5
+ require "yaml"
6
+ require "rest-client"
7
+
8
+ participants = YAML.load_file("./data/fedwire-participants.yml")
9
+ names = participants.map do |_, data|
10
+ data[:customer_name]
11
+ end.uniq.sort
12
+
13
+ # Institutions keyed by fedwire name.
14
+ institutions = {}
15
+
16
+ # Remove excess. Examples:
17
+ # KANSAS STATE BANK => The Kansas State Bank (Scranton) => Kansas State Bank
18
+ # ALLIANCE BANK CENTRAL TEXAS => Alliance Bank - Central Texas => Alliance Bank Central Texas
19
+ def normalize_name(fedwire_name, plaid_name)
20
+ return plaid_name if plaid_name.size == fedwire_name.size
21
+
22
+ start_index = plaid_name.upcase.index(fedwire_name)
23
+ if !start_index
24
+ plaid_name.gsub!(" - ", " ")
25
+ start_index = plaid_name.upcase.index(fedwire_name)
26
+ return plaid_name if !start_index
27
+ end
28
+ plaid_name.slice(start_index, fedwire_name.size)
29
+ end
30
+
31
+ names.each_with_index do |name, i|
32
+ puts "#{i+1}/#{names.size}: #{name}"
33
+
34
+ response = RestClient.get("https://tartan.plaid.com/institutions/all/search?p=connect&q=#{CGI::escape(name)}")
35
+ response = JSON.parse(response)
36
+
37
+ # Only if there is one result, consider that to be an exact match.
38
+ next unless response.size == 1
39
+
40
+ institutions[name] = normalize_name(name, institution[:name])
41
+
42
+ # Something reasonable to ensure we aren't overloading Plaid
43
+ sleep 0.5
44
+ end
45
+
46
+ File.write("./data/plaid-institution-names.json", JSON.neat_generate(institutions, wrap: 200, after_comma: 1))
47
+ File.write("./data/plaid-institution-names.yml", institutions.to_yaml)