thirteen_f 0.1.0 → 0.1.1

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: faa86b34f746b8c24e08c909422945e7d16c1fc970532f0ed47b030484f3c75b
4
- data.tar.gz: 2f6bea3847ab8ae71d4ad93935935f736b3f6aa2dbf7857ebc3ddd118d6f46cc
3
+ metadata.gz: 3b6299aaa6691236c2f61152986f601cb6714609759b85ecbfac375d74522e32
4
+ data.tar.gz: d9135d7b9f522841ce392cffcada7db8b8bf557bc071ed05602f904ebaf794ef
5
5
  SHA512:
6
- metadata.gz: bae8ed73b154e06568f55d4debeef353dc67bf5dfef321f52a9a42c126177ed4ebcd92fa21e6eb0c2fdf307258b5d02faa8c09965a895de6d37e8e352b2f8b71
7
- data.tar.gz: 876b5c9291b0845f14932e36143c9e5d19f5dc723a826975a0fceb390421d8ce4a522b78891ca87394b5b4a403543e5274a6719ee798d864e9b3228c1f2e0713
6
+ metadata.gz: 62336e373ed54038ac532e0500eae824be5886e876bc24eff2b1be255ceb85e20585f069348a63baa6e3ed9bb96953eb03aa8af92e8c8c40557096ad9808a5a4
7
+ data.tar.gz: 3a97bb255bb67dae639ef478e5954fa64b1dbb479ae6b50707bc7e3b356d2d128209b6c11237e4c4af287765253dd2abb4ec74c71b76721c607e0c6919d6dbff
data/README.md CHANGED
@@ -1,8 +1,16 @@
1
1
  # ThirteenF
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/thirteen_f`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ A ruby interface for S.E.C. 13-F Data. There is a lot of great finance and
4
+ investing data that is available for free, but few developer tools that let
5
+ us interact with the data outside of commercial platforms. This library
6
+ aims to remedy a small piece of this by providing a robust API to search and
7
+ retrieve investment holdings data of institutional investors through 13F
8
+ Reports. What is a 13F Report? Please visit
9
+ [this S.E.C. webpage](https://www.sec.gov/fast-answers/answers-form13fhtm.html)
10
+ for a full description.
11
+
12
+ This library is meant to serve a lightweight API which developers can enhance
13
+ via a persistence layer in their own applications.
6
14
 
7
15
  ## Installation
8
16
 
@@ -4,7 +4,7 @@ require 'http'
4
4
 
5
5
  class ThirteenF
6
6
  class Company
7
- attr_reader :cik, :name, :state_or_country
7
+ attr_reader :cik, :name, :state_or_country, :filings
8
8
 
9
9
  BASE_URL = 'https://www.sec.gov'
10
10
 
@@ -42,19 +42,23 @@ class ThirteenF
42
42
  "#{sec_filings_page_url}&type=13f&count=#{count}"
43
43
  end
44
44
 
45
- def get_links_to_filings
46
- response = HTTP.get thirteen_f_filings_url
47
- page = Nokogiri::HTML response.to_s
48
- # compare these two - documents_button would be more direct
49
- rows = page.search('table/tableFile2 > tr')[1..-1]
50
- btns = page.search('#documentsbutton')
51
- p [rows.count, btns.count]
45
+ def get_filings(count: 100)
46
+ @filings = Filing.from_index_urls thirteen_f_urls(count: count)
47
+ true
52
48
  end
53
49
 
54
50
  private
55
51
  def self.parse_name(name_cell)
56
52
  name_cell.text.split("\n").first
57
53
  end
54
+
55
+ def thirteen_f_urls(count: 100)
56
+ response = HTTP.get thirteen_f_filings_url(count: count)
57
+ page = Nokogiri::HTML response.to_s
58
+ page.search('#documentsbutton').map do |btn|
59
+ "#{BASE_URL + btn.attributes['href'].value}"
60
+ end
61
+ end
58
62
  end
59
63
  end
60
64
 
@@ -1,11 +1,128 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'http'
4
+ require 'date'
4
5
 
5
6
  class ThirteenF
6
7
  class Filing
7
- def initialize
8
+ attr_reader :index_url, :table_html_url, :table_xml_url,
9
+ :cover_page_html_url, :cover_page_xml_url, :complete_text_file_url,
10
+ :period_of_report, :time_accepted, :response_status
11
+
12
+ BASE_URL = 'https://www.sec.gov'
13
+
14
+ def self.from_index_urls(urls)
15
+ redo_count = 0
16
+ urls.map do |index_url|
17
+ response = HTTP.get index_url
18
+ sleep 0.33
19
+ if response.status == 200
20
+ redo_count = 0
21
+ attributes = set_attributes(response, index_url)
22
+ new(**attributes)
23
+ else
24
+ redo_count += 1
25
+ redo unless redo_count > 1
26
+ attributes = bad_response_attributes(response, index_url)
27
+ new(**attributes)
28
+ end
29
+ end
30
+ end
31
+
32
+ def reset_attributes_from_index_url
33
+ return unless index_url
34
+ response = HTTP.get index_url
35
+ sleep 0.33
36
+ if response.status == 200
37
+ attributes = self.class.set_attributes(response, index_url)
38
+ assign_attributes(**attributes)
39
+ true
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ def initialize(response_status:, index_url:, complete_text_file_url:,
46
+ period_of_report:, time_accepted:, table_html_url: nil,
47
+ table_xml_url: nil, cover_page_html_url: nil,
48
+ cover_page_xml_url: nil)
49
+ @response_status = response_status
50
+ @index_url = index_url
51
+ @table_html_url = table_html_url
52
+ @table_xml_url = table_xml_url
53
+ @cover_page_html_url = cover_page_html_url
54
+ @cover_page_xml_url = cover_page_xml_url
55
+ @complete_text_file_url = complete_text_file_url
56
+ @period_of_report = period_of_report
57
+ @time_accepted = time_accepted
8
58
  true
9
59
  end
60
+
61
+ private
62
+ def self.set_attributes(response, index_url)
63
+ page = Nokogiri::HTML response.to_s
64
+ table_links = page.search('table.tableFile')[0].search('a')
65
+ attributes = Hash.new
66
+ attributes[:response_status] = response.status.to_s
67
+ attributes[:index_url] = index_url
68
+ attributes[:period_of_report] = get_period_of_report page
69
+ attributes[:time_accepted] = get_time_accepted page
70
+ attributes[:complete_text_file_url] = "#{BASE_URL + table_links[-1].attributes['href'].value}"
71
+ if table_links.count == 5
72
+ attributes = xml_present(attributes, table_links)
73
+ end
74
+ attributes
75
+ end
76
+
77
+ def self.get_period_of_report(page)
78
+ period_header_div = page.search('div.infoHead').find do |div|
79
+ div.text.include?('Period of Report')
80
+ end
81
+ period_string = period_header_div.next.next.text.strip
82
+ Date.parse period_string
83
+ end
84
+
85
+ def self.get_time_accepted(page)
86
+ accepted_header_div = page.search('div.infoHead').find do |div|
87
+ div.text.include?('Accepted')
88
+ end
89
+ accepted_string = accepted_header_div.next.next.text.strip
90
+ DateTime.parse accepted_string
91
+ end
92
+
93
+ def self.xml_present(attributes, table_links)
94
+ attributes[:table_html_url] = "#{BASE_URL + table_links[2].attributes['href'].value}"
95
+ attributes[:table_xml_url] = "#{BASE_URL + table_links[3].attributes['href'].value}"
96
+ attributes[:cover_page_html_url] = "#{BASE_URL + table_links[0].attributes['href'].value}"
97
+ attributes[:cover_page_xml_url] = "#{BASE_URL + table_links[1].attributes['href'].value}"
98
+ attributes
99
+ end
100
+
101
+ def self.bad_response_attributes(response, index_url)
102
+ attributes = Hash.new
103
+ attributes[:response_status] = response.status.to_s
104
+ attributes[:index_url] = index_url
105
+ attributes[:period_of_report] = nil
106
+ attributes[:time_accepted] = nil
107
+ attributes[:complete_text_file_url] = nil
108
+ attributes
109
+ end
110
+
111
+ def assign_attributes(response_status:, index_url:, complete_text_file_url:,
112
+ period_of_report:, time_accepted:, table_html_url: nil,
113
+ table_xml_url: nil, cover_page_html_url: nil,
114
+ cover_page_xml_url: nil)
115
+ @response_status = response_status
116
+ @index_url = index_url
117
+ @table_html_url = table_html_url
118
+ @table_xml_url = table_xml_url
119
+ @cover_page_html_url = cover_page_html_url
120
+ @cover_page_xml_url = cover_page_xml_url
121
+ @complete_text_file_url = complete_text_file_url
122
+ @period_of_report = period_of_report
123
+ @time_accepted = time_accepted
124
+ true
125
+ end
10
126
  end
11
127
  end
128
+
@@ -25,7 +25,7 @@ class ThirteenF
25
25
  else
26
26
  raise 'SEC results are not available right now'
27
27
  end
28
-
28
+ true
29
29
  end
30
30
 
31
31
  private
@@ -1,3 +1,3 @@
1
1
  class ThirteenF
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/thirteen_f.gemspec CHANGED
@@ -6,17 +6,13 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["fordfischer"]
7
7
  spec.email = ["fordfischer07@gmail.com"]
8
8
 
9
- spec.summary = %q{thirteen_f lets you easily interact with SEC 13-F
10
- filing data in all the ways we think normal human beings might want to. The
11
- SEC is the U.S. Securities and Exchange Commission. 13-F filings are
12
- disclosures large investors in public securites have to provide and make
13
- public every quarter.}
9
+ spec.summary = %q{A ruby interface for S.E.C. 13-F Data.}
14
10
 
15
11
  spec.description = %q{thirteen_f lets you easily interact with SEC 13-F
16
12
  filing data in all the ways we think normal human beings might want to. The
17
13
  SEC is the U.S. Securities and Exchange Commission. 13-F filings are
18
- disclosures large investors in public securites have to provide and make
19
- public every quarter.}
14
+ disclosures large institutional investors in public securites have to provide
15
+ and make public every quarter.}
20
16
  spec.homepage = "https://github.com/fordfischer/thirteen_f"
21
17
  spec.license = "MIT"
22
18
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
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.1.0
4
+ version: 0.1.1
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-28 00:00:00.000000000 Z
11
+ date: 2020-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -70,8 +70,8 @@ description: |-
70
70
  thirteen_f lets you easily interact with SEC 13-F
71
71
  filing data in all the ways we think normal human beings might want to. The
72
72
  SEC is the U.S. Securities and Exchange Commission. 13-F filings are
73
- disclosures large investors in public securites have to provide and make
74
- public every quarter.
73
+ disclosures large institutional investors in public securites have to provide
74
+ and make public every quarter.
75
75
  email:
76
76
  - fordfischer07@gmail.com
77
77
  executables: []
@@ -119,8 +119,5 @@ requirements: []
119
119
  rubygems_version: 3.1.2
120
120
  signing_key:
121
121
  specification_version: 4
122
- summary: thirteen_f lets you easily interact with SEC 13-F filing data in all the
123
- ways we think normal human beings might want to. The SEC is the U.S. Securities
124
- and Exchange Commission. 13-F filings are disclosures large investors in public
125
- securites have to provide and make public every quarter.
122
+ summary: A ruby interface for S.E.C. 13-F Data.
126
123
  test_files: []