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 +4 -4
- data/README.md +11 -3
- data/lib/thirteen_f/company.rb +12 -8
- data/lib/thirteen_f/filing.rb +118 -1
- data/lib/thirteen_f/search.rb +1 -1
- data/lib/thirteen_f/version.rb +1 -1
- data/thirteen_f.gemspec +3 -7
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b6299aaa6691236c2f61152986f601cb6714609759b85ecbfac375d74522e32
|
4
|
+
data.tar.gz: d9135d7b9f522841ce392cffcada7db8b8bf557bc071ed05602f904ebaf794ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62336e373ed54038ac532e0500eae824be5886e876bc24eff2b1be255ceb85e20585f069348a63baa6e3ed9bb96953eb03aa8af92e8c8c40557096ad9808a5a4
|
7
|
+
data.tar.gz: 3a97bb255bb67dae639ef478e5954fa64b1dbb479ae6b50707bc7e3b356d2d128209b6c11237e4c4af287765253dd2abb4ec74c71b76721c607e0c6919d6dbff
|
data/README.md
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
# ThirteenF
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
|
data/lib/thirteen_f/company.rb
CHANGED
@@ -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
|
46
|
-
|
47
|
-
|
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
|
|
data/lib/thirteen_f/filing.rb
CHANGED
@@ -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
|
-
|
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
|
+
|
data/lib/thirteen_f/search.rb
CHANGED
data/lib/thirteen_f/version.rb
CHANGED
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{
|
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
|
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.
|
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-
|
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
|
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:
|
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: []
|