finviz 0.2.1 → 0.3.0
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 +4 -4
- data/.rubocop.yml +0 -3
- data/CHANGELOG.md +4 -0
- data/README.md +164 -157
- data/lib/finviz/quote.rb +30 -0
- data/lib/finviz/quotes.rb +20 -0
- data/lib/finviz/quotes_fetcher.rb +6 -32
- data/lib/finviz/tickers_fetcher.rb +11 -3
- data/lib/finviz/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 835b79336936f1465a97e86c3a82ea4f8d4011b0c0dc4fed645a5d7abef53556
|
4
|
+
data.tar.gz: 56f0e86206d7d7706adb321e4522adb08cd19d13435a5a2fc3acdf296c7481cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3cd8314b97d13589148ffd829c532debc4ec48d43c61a9d8f48d090bca2c09fc13206d5f372b7ed46f225148880980a90b795e9b9410647d234ec36c10cfc3e
|
7
|
+
data.tar.gz: adc4acfc82ac05864a10c6f06d5825cadeec2b271f8be7b4ecee295eea60d2322df43805c8644ec6cacfe7b5deb311e3b1149ec4fd3b9d026cccb87761174791
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -44,166 +44,173 @@ Finviz.tickers filters: %w[fa_pe_u5 sh_price_u3]
|
|
44
44
|
|
45
45
|
### Fetch quotes
|
46
46
|
|
47
|
-
Each quote contain the
|
47
|
+
Each quote contain the OpenStruct with ticker stats and links to the ticker and chart, see
|
48
48
|
example:
|
49
49
|
|
50
50
|
```ruby
|
51
|
-
quotes = Finviz.quotes tickers: %w[
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
=>
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
51
|
+
[1] pry(main)> quotes = Finviz.quotes tickers: %w[aapl mrna]
|
52
|
+
|
53
|
+
[2] pry(main)> quotes.m # If the quote was not requested
|
54
|
+
=> nil
|
55
|
+
|
56
|
+
[3] pry(main)> quotes.aapl
|
57
|
+
=> #<Finviz::Quote:0x00007fb7189895f0
|
58
|
+
@stats=
|
59
|
+
{"Index"=>"DJIA S&P500",
|
60
|
+
"P/E"=>"28.02",
|
61
|
+
"EPS (ttm)"=>"4.46",
|
62
|
+
"Insider Own"=>"0.07%",
|
63
|
+
"Shs Outstand"=>"16.75B",
|
64
|
+
"Perf Week"=>"-0.84%",
|
65
|
+
"Market Cap"=>"2042.91B",
|
66
|
+
"Forward P/E"=>"23.38",
|
67
|
+
"EPS next Y"=>"2.89%",
|
68
|
+
"Insider Trans"=>"-2.80%",
|
69
|
+
"Shs Float"=>"16.68B",
|
70
|
+
"Perf Month"=>"-7.41%",
|
71
|
+
"Income"=>"76.31B",
|
72
|
+
"PEG"=>"1.56",
|
73
|
+
"EPS next Q"=>"0.99",
|
74
|
+
"Inst Own"=>"59.90%",
|
75
|
+
"Short Float"=>"0.50%",
|
76
|
+
"Perf Quarter"=>"-4.58%",
|
77
|
+
"Sales"=>"325.41B",
|
78
|
+
"P/S"=>"6.28",
|
79
|
+
"EPS this Y"=>"10.20%",
|
80
|
+
"Inst Trans"=>"-0.49%",
|
81
|
+
"Short Ratio"=>"0.79",
|
82
|
+
"Perf Half Y"=>"4.69%",
|
83
|
+
"Book/sh"=>"4.13",
|
84
|
+
"P/B"=>"30.23",
|
85
|
+
"ROA"=>"22.90%",
|
86
|
+
"Target Price"=>"159.74",
|
87
|
+
"Perf Year"=>"58.56%",
|
88
|
+
"Cash/sh"=>"4.27",
|
89
|
+
"P/C"=>"29.25",
|
90
|
+
"EPS next 5Y"=>"17.93%",
|
91
|
+
"ROE"=>"111.80%",
|
92
|
+
"52W Range"=>"77.58 - 145.09",
|
93
|
+
"Perf YTD"=>"-5.91%",
|
94
|
+
"Dividend"=>"0.88",
|
95
|
+
"P/FCF"=>"26.79",
|
96
|
+
"EPS past 5Y"=>"7.30%",
|
97
|
+
"ROI"=>"31.70%",
|
98
|
+
"52W High"=>"-13.95%",
|
99
|
+
"Beta"=>"1.22",
|
100
|
+
"Dividend %"=>"0.70%",
|
101
|
+
"Quick Ratio"=>"1.10",
|
102
|
+
"Sales past 5Y"=>"3.30%",
|
103
|
+
"Gross Margin"=>"39.90%",
|
104
|
+
"52W Low"=>"60.93%",
|
105
|
+
"ATR"=>"2.90",
|
106
|
+
"Employees"=>"147000",
|
107
|
+
"Current Ratio"=>"1.10",
|
108
|
+
"Sales Q/Q"=>"53.60%",
|
109
|
+
"Oper. Margin"=>"27.30%",
|
110
|
+
"RSI (14)"=>"41.95",
|
111
|
+
"Volatility"=>"1.65% 2.00%",
|
112
|
+
"Optionable"=>"Yes",
|
113
|
+
"Debt/Eq"=>"1.76",
|
114
|
+
"EPS Q/Q"=>"118.60%",
|
115
|
+
"Profit Margin"=>"23.50%",
|
116
|
+
"Rel Volume"=>"0.60",
|
117
|
+
"Prev Close"=>"126.27",
|
118
|
+
"Shortable"=>"Yes",
|
119
|
+
"LT Debt/Eq"=>"1.57",
|
120
|
+
"Earnings"=>"Apr 28 AMC",
|
121
|
+
"Payout"=>"18.20%",
|
122
|
+
"Avg Volume"=>"104.09M",
|
123
|
+
"Price"=>"124.85",
|
124
|
+
"Recom"=>"2.00",
|
125
|
+
"SMA20"=>"-4.08%",
|
126
|
+
"SMA50"=>"-1.80%",
|
127
|
+
"SMA200"=>"1.15%",
|
128
|
+
"Volume"=>"62,545,117",
|
129
|
+
"Change"=>"-1.12%"},
|
130
|
+
@ticker="aapl">
|
131
|
+
|
132
|
+
[4] pry(main)> quotes.aapl.chart
|
133
|
+
=> "https://charts2.finviz.com/chart.ashx?t=aapl&ty=c&ta=1&p=d&s=l"
|
134
|
+
|
135
|
+
[5] pry(main)> quotes.aapl.path
|
136
|
+
=> "https://finviz.com/quote.ashx?t=aapl"
|
137
|
+
|
138
|
+
[6] pry(main)> quotes.aapl.to_h
|
139
|
+
=> {:stats=>
|
140
|
+
{"Index"=>"DJIA S&P500",
|
141
|
+
"P/E"=>"28.02",
|
142
|
+
"EPS (ttm)"=>"4.46",
|
143
|
+
"Insider Own"=>"0.07%",
|
144
|
+
"Shs Outstand"=>"16.75B",
|
145
|
+
"Perf Week"=>"-0.84%",
|
146
|
+
"Market Cap"=>"2042.91B",
|
147
|
+
"Forward P/E"=>"23.38",
|
148
|
+
"EPS next Y"=>"2.89%",
|
149
|
+
"Insider Trans"=>"-2.80%",
|
150
|
+
"Shs Float"=>"16.68B",
|
151
|
+
"Perf Month"=>"-7.41%",
|
152
|
+
"Income"=>"76.31B",
|
153
|
+
"PEG"=>"1.56",
|
154
|
+
"EPS next Q"=>"0.99",
|
155
|
+
"Inst Own"=>"59.90%",
|
156
|
+
"Short Float"=>"0.50%",
|
157
|
+
"Perf Quarter"=>"-4.58%",
|
158
|
+
"Sales"=>"325.41B",
|
159
|
+
"P/S"=>"6.28",
|
160
|
+
"EPS this Y"=>"10.20%",
|
161
|
+
"Inst Trans"=>"-0.49%",
|
162
|
+
"Short Ratio"=>"0.79",
|
163
|
+
"Perf Half Y"=>"4.69%",
|
164
|
+
"Book/sh"=>"4.13",
|
165
|
+
"P/B"=>"30.23",
|
166
|
+
"ROA"=>"22.90%",
|
167
|
+
"Target Price"=>"159.74",
|
168
|
+
"Perf Year"=>"58.56%",
|
169
|
+
"Cash/sh"=>"4.27",
|
170
|
+
"P/C"=>"29.25",
|
171
|
+
"EPS next 5Y"=>"17.93%",
|
172
|
+
"ROE"=>"111.80%",
|
173
|
+
"52W Range"=>"77.58 - 145.09",
|
174
|
+
"Perf YTD"=>"-5.91%",
|
175
|
+
"Dividend"=>"0.88",
|
176
|
+
"P/FCF"=>"26.79",
|
177
|
+
"EPS past 5Y"=>"7.30%",
|
178
|
+
"ROI"=>"31.70%",
|
179
|
+
"52W High"=>"-13.95%",
|
180
|
+
"Beta"=>"1.22",
|
181
|
+
"Dividend %"=>"0.70%",
|
182
|
+
"Quick Ratio"=>"1.10",
|
183
|
+
"Sales past 5Y"=>"3.30%",
|
184
|
+
"Gross Margin"=>"39.90%",
|
185
|
+
"52W Low"=>"60.93%",
|
186
|
+
"ATR"=>"2.90",
|
187
|
+
"Employees"=>"147000",
|
188
|
+
"Current Ratio"=>"1.10",
|
189
|
+
"Sales Q/Q"=>"53.60%",
|
190
|
+
"Oper. Margin"=>"27.30%",
|
191
|
+
"RSI (14)"=>"41.95",
|
192
|
+
"Volatility"=>"1.65% 2.00%",
|
193
|
+
"Optionable"=>"Yes",
|
194
|
+
"Debt/Eq"=>"1.76",
|
195
|
+
"EPS Q/Q"=>"118.60%",
|
196
|
+
"Profit Margin"=>"23.50%",
|
197
|
+
"Rel Volume"=>"0.60",
|
198
|
+
"Prev Close"=>"126.27",
|
199
|
+
"Shortable"=>"Yes",
|
200
|
+
"LT Debt/Eq"=>"1.57",
|
201
|
+
"Earnings"=>"Apr 28 AMC",
|
202
|
+
"Payout"=>"18.20%",
|
203
|
+
"Avg Volume"=>"104.09M",
|
204
|
+
"Price"=>"124.85",
|
205
|
+
"Recom"=>"2.00",
|
206
|
+
"SMA20"=>"-4.08%",
|
207
|
+
"SMA50"=>"-1.80%",
|
208
|
+
"SMA200"=>"1.15%",
|
209
|
+
"Volume"=>"62,545,117",
|
210
|
+
"Change"=>"-1.12%"},
|
211
|
+
:path=>"https://finviz.com/quote.ashx?t=aapl",
|
212
|
+
:chart=>"https://charts2.finviz.com/chart.ashx?t=aapl&ty=c&ta=1&p=d&s=l",
|
213
|
+
:ticker=>"aapl"}
|
207
214
|
```
|
208
215
|
|
209
216
|
## Development
|
data/lib/finviz/quote.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/hash_with_indifferent_access"
|
4
|
+
|
5
|
+
module Finviz
|
6
|
+
# Single quote representation
|
7
|
+
class Quote
|
8
|
+
attr_reader :ticker, :stats
|
9
|
+
|
10
|
+
def initialize(ticker:, stats: nil)
|
11
|
+
@ticker = ticker
|
12
|
+
@stats = ActiveSupport::HashWithIndifferentAccess.new(stats.to_h)
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
"https://finviz.com/quote.ashx?t=#{ticker}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def chart
|
20
|
+
"https://charts2.finviz.com/chart.ashx?t=#{ticker}&ty=c&ta=1&p=d&s=l"
|
21
|
+
end
|
22
|
+
|
23
|
+
# grab all instance methods to the hash
|
24
|
+
def to_h
|
25
|
+
(self.class.instance_methods(false) - [__callee__]).each_with_object({}) do |method, acc|
|
26
|
+
acc[method] = public_send method
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Finviz
|
4
|
+
# The result of the quotes request
|
5
|
+
class Quotes < OpenStruct
|
6
|
+
def add_quote_from_xpath(ticker_xpath, table_xpath)
|
7
|
+
ticker = ticker_xpath.children.text.downcase
|
8
|
+
stats = table_xpath
|
9
|
+
.css(".table-dark-row")
|
10
|
+
.map { |row| row.css("td").map(&:text) }
|
11
|
+
.flatten
|
12
|
+
.each_slice(2)
|
13
|
+
self[ticker] = Quote.new ticker: ticker, stats: stats
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
super.transform_values(&:to_h)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -10,42 +10,16 @@ module Finviz
|
|
10
10
|
attr_reader :tickers
|
11
11
|
|
12
12
|
def call
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def add_stats_to_results
|
21
|
-
all_pages.each_with_index do |page, page_number|
|
22
|
-
page.html.css(".snapshot-table2").each_with_index do |xpath, selector_offset|
|
23
|
-
current = results[page_number][selector_offset]
|
24
|
-
current.stats = xpath.css(".table-dark-row").map { |row| row.css("td").map(&:text) }
|
25
|
-
.flatten.each_slice(2).to_h
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def add_charts_to_results
|
31
|
-
all_pages.each_with_index do |page, page_number|
|
32
|
-
page.html.css("#chart1").each_with_index do |xpath, selector_offset|
|
33
|
-
current = results[page_number][selector_offset]
|
34
|
-
current.chart = xpath.attributes["src"].text
|
13
|
+
Quotes.new.tap do |result|
|
14
|
+
all_pages.each do |page|
|
15
|
+
page.html.css("#ticker").zip(page.html.css(".snapshot-table2")).each do |(ticker_xpath, table_xpath)|
|
16
|
+
result.add_quote_from_xpath(ticker_xpath, table_xpath)
|
17
|
+
end
|
35
18
|
end
|
36
19
|
end
|
37
20
|
end
|
38
21
|
|
39
|
-
|
40
|
-
@results ||= all_pages.map do |page|
|
41
|
-
page.html.css("#ticker").map do |xpath|
|
42
|
-
ticker = xpath.children.text
|
43
|
-
OpenStruct.new path: "https://finviz.com/quote.ashx?t=#{ticker}",
|
44
|
-
ticker: ticker,
|
45
|
-
chart: "https://charts2.finviz.com/chart.ashx?t=#{ticker}&ty=c&ta=1&p=d&s=l"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
22
|
+
private
|
49
23
|
|
50
24
|
def all_pages
|
51
25
|
@all_pages ||= Crawler.call(paths: paths)
|
@@ -38,12 +38,20 @@ module Finviz
|
|
38
38
|
|
39
39
|
def normalize_uri(uri, filters)
|
40
40
|
uri = URI(uri || base_uri)
|
41
|
-
|
42
|
-
|
41
|
+
|
42
|
+
@uri = URI::HTTPS.build(
|
43
|
+
host: base_uri,
|
44
|
+
path: base_path,
|
45
|
+
query: CGI.unescape(URI.encode_www_form(query(uri, filters)))
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def query(uri, filters)
|
50
|
+
CGI.parse(uri.query || "").tap do |params|
|
51
|
+
params["f"] = filters.join(",") if filters&.any?
|
43
52
|
params["v"] = finviz_view_type
|
44
53
|
params.delete("r") # remove offset if it was provided
|
45
54
|
end
|
46
|
-
@uri = URI::HTTPS.build(host: base_uri, path: base_path, query: CGI.unescape(URI.encode_www_form(query)))
|
47
55
|
end
|
48
56
|
|
49
57
|
def base_uri
|
data/lib/finviz/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: finviz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kvokka
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -102,6 +102,8 @@ files:
|
|
102
102
|
- finviz.gemspec
|
103
103
|
- lib/finviz.rb
|
104
104
|
- lib/finviz/crawler.rb
|
105
|
+
- lib/finviz/quote.rb
|
106
|
+
- lib/finviz/quotes.rb
|
105
107
|
- lib/finviz/quotes_fetcher.rb
|
106
108
|
- lib/finviz/tickers_fetcher.rb
|
107
109
|
- lib/finviz/version.rb
|