thirteen_f 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97448bdbcdaea2e3d0e690584c24503c7d9e65c0140441ae8afa037b6a0d96b0
4
- data.tar.gz: 4aaf17e842ee4b83693d1977fc3a36036adbdc4a65a2208b44191b0dc4237373
3
+ metadata.gz: 2055d576a8a4c7d6328c15325eb1a34b02c7c390346ef9111b6aa82387f88a37
4
+ data.tar.gz: 60571d9e9ca221b80596453fab70fa284e841cc9e64e516bb616503c484c182d
5
5
  SHA512:
6
- metadata.gz: eacc83d2d8aaf67caff1807e5e4368e6c954ac5f4a59758c020241b56e53d018c430b2c7874d56a2761a8da0ad288f01fcba32ff8ab60dd651a86d822f3d4759
7
- data.tar.gz: 483483c8d663da64483efa03a8292308f2425e201071155c87810d715e8d54470b6fb39ca643db6b9a96f06be1a23c58815458e726017318b88b5c7821ef0812
6
+ metadata.gz: f5944c92f5e8ed3e0daa1cacd1089774f7eb5b26d134de33ae17f1e3b6a006d06ae616209d3c91b92ddc7d3789e5ed85d18382ae3765bc186ae6d41c3a7637fe
7
+ data.tar.gz: c4c9ebf3bfc18ef017004c286ff2b99e013f448873e4bd10ba60082a7911d737ca4a8cad267b2ebab0dfb575cde3de0c500038e277f24022012e05ba81301134
data/Gemfile.lock CHANGED
@@ -1,15 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- thirteen_f (0.1.0)
4
+ thirteen_f (0.2.2)
5
5
  http (>= 4.4)
6
6
  nokogiri
7
+ pdf-reader
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
12
+ Ascii85 (1.0.3)
11
13
  addressable (2.7.0)
12
14
  public_suffix (>= 2.0.2, < 5.0)
15
+ afm (0.2.2)
13
16
  coderay (1.1.2)
14
17
  domain_name (0.5.20190701)
15
18
  unf (>= 0.0.5, < 1.0.0)
@@ -17,7 +20,8 @@ GEM
17
20
  ffi-compiler (1.0.1)
18
21
  ffi (>= 1.0.0)
19
22
  rake
20
- http (4.4.0)
23
+ hashery (2.1.2)
24
+ http (4.4.1)
21
25
  addressable (~> 2.3)
22
26
  http-cookie (~> 1.0)
23
27
  http-form_data (~> 2.2)
@@ -32,14 +36,22 @@ GEM
32
36
  minitest (5.14.0)
33
37
  nokogiri (1.10.9)
34
38
  mini_portile2 (~> 2.4.0)
39
+ pdf-reader (2.4.0)
40
+ Ascii85 (~> 1.0.0)
41
+ afm (~> 0.2.1)
42
+ hashery (~> 2.0)
43
+ ruby-rc4
44
+ ttfunk
35
45
  pry (0.13.0)
36
46
  coderay (~> 1.1)
37
47
  method_source (~> 1.0)
38
48
  public_suffix (4.0.3)
39
49
  rake (12.3.3)
50
+ ruby-rc4 (0.1.5)
51
+ ttfunk (1.6.2.1)
40
52
  unf (0.1.4)
41
53
  unf_ext
42
- unf_ext (0.0.7.6)
54
+ unf_ext (0.0.7.7)
43
55
 
44
56
  PLATFORMS
45
57
  ruby
data/README.md CHANGED
@@ -39,7 +39,6 @@ Or install it yourself as:
39
39
 
40
40
  ```ruby
41
41
  search = ThirteenF::Search.new('Berkshire Hathaway')
42
- search = ThirteenF::Search.new('BERKSHIRE HATHAWAY INC')
43
42
  search.get_companies
44
43
  search.companies
45
44
  ```
@@ -51,7 +50,7 @@ company = search.companies.first
51
50
  company.get_filings # grabs 10 13F filings by default which is the minimum
52
51
  company.get_filings(count: 20) # can supply an optional count keyword arg to get more filings
53
52
  company.get_most_recent_holdings
54
- company.most_recent_holdings # returns positions from more recent 13F filing
53
+ company.most_recent_holdings # returns positions from the most recent 13F filing
55
54
 
56
55
  company.cik # type: String | ex: "0001067983"
57
56
  company.name # type: String | ex: "BERKSHIRE HATHAWAY INC"
@@ -80,6 +79,9 @@ filing.cover_page_html_url # String or nil
80
79
  ### Positions
81
80
 
82
81
  ```ruby
82
+ xml_url = 'https://www.sec.gov/Archives/edgar/data/1061768/000156761920003359/form13fInfoTable.xml'
83
+ positions = Position.from_xml_url(xml_url)
84
+
83
85
  position = filing.positions.first
84
86
  position.filing
85
87
 
@@ -27,6 +27,13 @@ class ThirteenF
27
27
  Array.new 1, new(cik, name, state_or_country)
28
28
  end
29
29
 
30
+ def self.from_cik(cik)
31
+ response = HTTP.get sec_url_from_cik(cik)
32
+ return false unless response.status == 200
33
+ page = Nokogiri::HTML response.to_s
34
+ from_company_page page
35
+ end
36
+
30
37
  def initialize(cik, name, state_or_country)
31
38
  @cik = cik
32
39
  @name = name
@@ -55,6 +62,10 @@ class ThirteenF
55
62
  "#{sec_filings_page_url}&type=13f&count=#{count}"
56
63
  end
57
64
 
65
+ def self.sec_url_from_cik(cik)
66
+ "#{BASE_URL}/cgi-bin/browse-edgar?CIK=#{cik}"
67
+ end
68
+
58
69
  private
59
70
  def self.parse_name(name_cell)
60
71
  name_cell.text.split("\n").first
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+ require 'date'
5
+ require 'open-uri'
6
+ require 'pdf-reader'
7
+
8
+ class ThirteenF
9
+ class CusipSecurities
10
+ attr_reader :file_name, :file_location, :quarter, :period_end, :list_entries
11
+ BASE_URL = 'https://www.sec.gov'
12
+
13
+ def self.all_file_locations
14
+ index_url = "#{BASE_URL}/divisions/investment/13flists.htm"
15
+ response = HTTP.get index_url
16
+ return false unless response.status == 200
17
+ page = Nokogiri::HTML response.to_s
18
+ a_tags = page.search('a').select do |a_tag|
19
+ href = a_tag.attributes['href']&.value.to_s
20
+ href.include?('13flist') && href.include?('.pdf')
21
+ end
22
+ a_tags.map { |a_tag|"#{BASE_URL + a_tag.attributes['href'].value}" }
23
+ end
24
+
25
+ def self.most_recent_list
26
+ index_url = "#{BASE_URL}/divisions/investment/13flists.htm"
27
+ response = HTTP.get index_url
28
+ return false unless response.status == 200
29
+ page = Nokogiri::HTML response.to_s
30
+ a_tag = page.search('a').find { |a| a.text.include?('Current List') }
31
+ file_location = "#{BASE_URL + a_tag.attributes['href'].value}"
32
+ new file_location
33
+ end
34
+
35
+ def initialize(file_location)
36
+ @file_location = file_location
37
+ @file_name = file_location.split('/').last
38
+ @quarter = set_quarter_string file_name
39
+ @period_end = set_period_end file_name
40
+ true
41
+ end
42
+
43
+ def get_list_entries
44
+ return false unless file_location
45
+ io = URI.open file_location
46
+ reader = PDF::Reader.new io
47
+ valid_entries = []
48
+ reader.pages[2..-1].each do |page|
49
+ lines = page.text.split("\n").reject(&:empty?)[3..-1]
50
+ line_arrs = lines.map do |line|
51
+ next nil if line.include?('Total Count')
52
+ line.split(' ').reject(&:empty?).map(&:strip).reject { |text| text == '*' }
53
+ end
54
+ line_arrs.compact.each do |line_arr|
55
+ valid_entries.push ListEntry.new(line_arr)
56
+ end
57
+ end
58
+ @list_entries = valid_entries
59
+ true
60
+ end
61
+
62
+ class ListEntry
63
+ attr_reader :cusip_number, :issuer_name, :issuer_description, :status
64
+
65
+ def initialize(line_arr)
66
+ @cusip_number = line_arr[0].delete(' ')
67
+ @issuer_name = line_arr[1].delete('*').strip
68
+ @issuer_description = line_arr[2]
69
+ @status = line_arr[3] || 'N/A'
70
+ true
71
+ end
72
+ end
73
+
74
+ private
75
+ def set_quarter_string(file_name)
76
+ arr = file_name.sub('13flist', '').delete('.pdf').split('q')
77
+ case arr[1].to_i
78
+ when 1 then "1st Quarter #{arr[0]}"
79
+ when 2 then "2nd Quarter #{arr[0]}"
80
+ when 3 then "3rd Quarter #{arr[0]}"
81
+ when 4 then "4th Quarter #{arr[0]}"
82
+ end
83
+ end
84
+
85
+ def set_period_end(file_name)
86
+ arr = file_name.sub('13flist', '').delete('.pdf').split('q')
87
+ case arr[1].to_i
88
+ when 1 then Date.parse("#{arr[0]}-03-31")
89
+ when 2 then Date.parse("#{arr[0]}-06-30")
90
+ when 3 then Date.parse("#{arr[0]}-09-30")
91
+ when 4 then Date.parse("#{arr[0]}-12-31")
92
+ end
93
+ end
94
+ end
95
+ end
96
+
@@ -13,13 +13,23 @@ class ThirteenF
13
13
  response = HTTP.get filing.table_xml_url
14
14
  xml_doc = Nokogiri::XML response.to_s
15
15
  xml_doc.search('infoTable').map do |info_table|
16
- position = new filing
16
+ position = new filing: filing
17
17
  position.attributes_from_info_table(info_table)
18
18
  position
19
19
  end
20
20
  end
21
21
 
22
- def initialize(filing)
22
+ def self.from_xml_url(table_xml_url)
23
+ response = HTTP.get table_xml_url
24
+ xml_doc = Nokogiri::XML response.to_s
25
+ xml_doc.search('infoTable').map do |info_table|
26
+ position = new
27
+ position.attributes_from_info_table(info_table)
28
+ position
29
+ end
30
+ end
31
+
32
+ def initialize(filing: nil)
23
33
  @filing = filing
24
34
  end
25
35
 
@@ -1,3 +1,3 @@
1
1
  class ThirteenF
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
data/lib/thirteen_f.rb CHANGED
@@ -4,6 +4,7 @@ require "thirteen_f/company"
4
4
  require "thirteen_f/search"
5
5
  require "thirteen_f/filing"
6
6
  require "thirteen_f/position"
7
+ require "thirteen_f/cusip_securities"
7
8
  require "thirteen_f/version"
8
9
 
9
10
  class ThirteenF
data/thirteen_f.gemspec CHANGED
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency "pry"
35
35
  spec.add_dependency "http", ">= 4.4"
36
36
  spec.add_dependency "nokogiri"
37
+ spec.add_dependency "pdf-reader"
37
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thirteen_f
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - fordfischer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-29 00:00:00.000000000 Z
11
+ date: 2020-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pdf-reader
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: |-
70
84
  thirteen_f lets you easily search and retrieve SEC 13F
71
85
  filing data. The SEC is the U.S. Securities and Exchange Commission. 13F
@@ -90,6 +104,7 @@ files:
90
104
  - bin/setup
91
105
  - lib/thirteen_f.rb
92
106
  - lib/thirteen_f/company.rb
107
+ - lib/thirteen_f/cusip_securities.rb
93
108
  - lib/thirteen_f/filing.rb
94
109
  - lib/thirteen_f/position.rb
95
110
  - lib/thirteen_f/search.rb