thirteen_f 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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