coincapper 1.0.0 → 1.1.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/.gitignore +1 -0
- data/LICENSE.txt +1 -1
- data/README.md +70 -8
- data/coincapper.gemspec +5 -5
- data/lib/coincapper.rb +154 -98
- data/lib/coincapper/version.rb +2 -2
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48cf58727f9ab2527e3172010e0b48d28d1c0591
|
4
|
+
data.tar.gz: 05a4c2a9a90b9fbb2ec76e2b9302f16f8cae56c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4515cdf093bdb3d2d34f47f7c4a9f82e989d12ea051643bb88e34bfc04aecd454e74c3d3a656881a8a7f2b966fc73655d9a7750567361529c3c386112d0c59e9
|
7
|
+
data.tar.gz: e956f186176adb955921aafde496ba271a66b85b9dfcb5ff42def6330ffbcc9469b4ba603c159ce70ebdcd8d64e84213c8821c159f20bc19d617f3fc418f24ee
|
data/.gitignore
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
# CoinCapper
|
4
4
|
|
5
|
-
|
5
|
+
An API wrapper to the V1 coinmarketcap.com public API with additional historic, symbol, and market functionality.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem 'coincapper',
|
12
|
+
gem 'coincapper', '~> 1.0'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
@@ -30,7 +30,7 @@ Or install it yourself as:
|
|
30
30
|
CoinCapper.coins(limit: 0, rank: nil, currency: nil)
|
31
31
|
```
|
32
32
|
|
33
|
-
#### Coin by
|
33
|
+
#### Coin by CoinMarketCap ID
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
CoinCapper.coin('litecoin', currency: nil)
|
@@ -48,18 +48,80 @@ CoinCapper.global(currency: nil)
|
|
48
48
|
|
49
49
|
```ruby
|
50
50
|
CoinCapper.coin_by_symbol('FUN')
|
51
|
+
|
52
|
+
=> {:id=>"funfair",
|
53
|
+
:name=>"FunFair",
|
54
|
+
:symbol=>"FUN",
|
55
|
+
:rank=>"84",
|
56
|
+
:price_usd=>"0.0382094",
|
57
|
+
:price_btc=>"0.00000557",
|
58
|
+
:"24h_volume_usd"=>"5375680.0",
|
59
|
+
:market_cap_usd=>"172083246.0",
|
60
|
+
:available_supply=>"4503688789.0",
|
61
|
+
:total_supply=>"10999873621.0",
|
62
|
+
:max_supply=>nil,
|
63
|
+
:percent_change_1h=>"-6.89",
|
64
|
+
:percent_change_24h=>"-24.77",
|
65
|
+
:percent_change_7d=>"-59.6",
|
66
|
+
:last_updated=>"1517873357"}
|
51
67
|
```
|
52
68
|
|
53
|
-
####
|
69
|
+
#### Available markets by coin id or symbol
|
54
70
|
|
55
71
|
```ruby
|
56
72
|
CoinCapper.coin_markets(id: 'iota', symbol: nil)
|
73
|
+
|
74
|
+
=> [{:source=>"Bitfinex", :pair=>"MIOTA/USD", :volume_usd=>33835200.0, :price_usd=>1.41, :volume_percentage=>50.21, :last_updated=>"Recently"},
|
75
|
+
{:source=>"Binance", :pair=>"IOTA/BTC", :volume_usd=>7733790.0, :price_usd=>1.41, :volume_percentage=>11.48, :last_updated=>"Recently"}]
|
76
|
+
```
|
77
|
+
|
78
|
+
#### Historical prices by id, start, end date
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
CoinCapper.historical_price('request-network', '2018-01-01', '2018-01-02')
|
82
|
+
|
83
|
+
=> [{:date=>"2018-01-02", :open=>0.8126, :high=>0.881387, :low=>0.650608, :close=>0.783648, :average=>0.7659975},
|
84
|
+
{:date=>"2018-01-01", :open=>0.606538, :high=>0.888908, :low=>0.528808, :close=>0.820232, :average=>0.708858}]
|
57
85
|
```
|
58
86
|
|
59
|
-
####
|
87
|
+
#### All Cryptocurrencies by type (coins, tokens)
|
60
88
|
|
61
89
|
```ruby
|
62
|
-
|
90
|
+
# coins
|
91
|
+
CoinCapper.all('coins')
|
92
|
+
|
93
|
+
=> [{:id=>"bitcoin",
|
94
|
+
:rank=>1,
|
95
|
+
:name=>"Bitcoin",
|
96
|
+
:symbol=>"BTC",
|
97
|
+
:market_cap_usd=>116671271686.0,
|
98
|
+
:market_cap_btc=>16848275.0,
|
99
|
+
:price_usd=>6924.82,
|
100
|
+
:price_btc=>1.0,
|
101
|
+
:circulating_supply=>16848275.0,
|
102
|
+
:volume_usd_24h=>9116750000.0,
|
103
|
+
:volume_btc_24h=>1309170.0,
|
104
|
+
:percent_change_1h=>-4.59,
|
105
|
+
:percent_change_24h=>-16.75,
|
106
|
+
:percent_change_7d=>-38.38}]
|
107
|
+
|
108
|
+
# tokens
|
109
|
+
CoinCapper.all('tokens')
|
110
|
+
|
111
|
+
=> [{:id=>"eos",
|
112
|
+
:rank=>1,
|
113
|
+
:name=>"EOS",
|
114
|
+
:platform=>"Ethereum",
|
115
|
+
:market_cap_usd=>4598392073.93,
|
116
|
+
:market_cap_btc=>663307.647514,
|
117
|
+
:price_usd=>7.07817,
|
118
|
+
:price_btc=>0.00102101,
|
119
|
+
:circulating_supply=>649658326.083,
|
120
|
+
:volume_usd_24h=>630722000.0,
|
121
|
+
:volume_btc_24h=>90980.3,
|
122
|
+
:percent_change_1h=>-6.02,
|
123
|
+
:percent_change_24h=>-18.88,
|
124
|
+
:percent_change_7d=>-49.0}]
|
63
125
|
```
|
64
126
|
|
65
127
|
## Development
|
@@ -70,7 +132,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
70
132
|
|
71
133
|
## Contributing
|
72
134
|
|
73
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/kurt-smith/
|
135
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/kurt-smith/coincapper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
74
136
|
|
75
137
|
## License
|
76
138
|
|
@@ -78,4 +140,4 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
78
140
|
|
79
141
|
## Code of Conduct
|
80
142
|
|
81
|
-
Everyone interacting in the CoinCapper project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/kurt-smith/
|
143
|
+
Everyone interacting in the CoinCapper project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/kurt-smith/coincapper/blob/master/CODE_OF_CONDUCT.md).
|
data/coincapper.gemspec
CHANGED
@@ -9,9 +9,9 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.version = CoinCapper::VERSION
|
10
10
|
spec.authors = ['Kurt Smith']
|
11
11
|
spec.email = ['zippydev@protonmail.com']
|
12
|
-
|
13
|
-
spec.
|
14
|
-
|
12
|
+
spec.summary = 'Coinmarketcap V1 API wrapper'
|
13
|
+
spec.description = 'coinmarketcap.com V1 API wrapper including additional historical prices, coin market pairs, '\
|
14
|
+
'and currencies by type (coins/tokens) parsed from Coin Market Cap.'
|
15
15
|
spec.homepage = 'https://github.com/kurt-smith/coincapper'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
spec.add_development_dependency 'pry', '~> 0.11'
|
39
39
|
spec.add_development_dependency 'rake', '~> 10.0'
|
40
40
|
spec.add_development_dependency 'rspec', '~> 3.7'
|
41
|
-
spec.add_development_dependency 'rubocop'
|
42
|
-
spec.add_development_dependency 'simplecov'
|
41
|
+
spec.add_development_dependency 'rubocop', '>= 0.52'
|
42
|
+
spec.add_development_dependency 'simplecov', '>= 0.14'
|
43
43
|
spec.add_development_dependency 'webmock', '~> 3.2'
|
44
44
|
end
|
data/lib/coincapper.rb
CHANGED
@@ -6,120 +6,176 @@ require 'coincapper/version'
|
|
6
6
|
require 'http'
|
7
7
|
require 'nokogiri'
|
8
8
|
|
9
|
-
|
9
|
+
class CoinCapper
|
10
10
|
API_URL = 'https://api.coinmarketcap.com/v1'.freeze
|
11
11
|
BASE_URL = 'https://coinmarketcap.com'.freeze
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
13
|
+
class << self
|
14
|
+
# @param rank [Integer] Coins market cap rank greater than or equal
|
15
|
+
# @param limit [Integer] Maximum limit set. Defaults to 0 to return all results
|
16
|
+
# @param currency [String] Country currency code to convert price
|
17
|
+
# @return [Array<Hash>]
|
18
|
+
# @see https://coinmarketcap.com/api/
|
19
|
+
def coins(limit: 0, rank: nil, currency: nil)
|
20
|
+
params = {
|
21
|
+
limit: limit,
|
22
|
+
start: rank,
|
23
|
+
convert: currency
|
24
|
+
}.compact.to_param
|
25
|
+
|
26
|
+
url = "#{API_URL}/ticker/"
|
27
|
+
url << "?#{params}" if params.present?
|
28
|
+
|
29
|
+
response = HTTP.get(url)
|
30
|
+
JSON.parse(response.body.to_s, symbolize_names: true)
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
# @param id [Integer] Coinmarketcap coin id
|
34
|
+
# @param currency [String] Country currency code to convert price
|
35
|
+
# @return [Hash]
|
36
|
+
def coin(id, currency: nil)
|
37
|
+
params = {
|
38
|
+
convert: currency
|
39
|
+
}.compact.to_param
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
url = "#{API_URL}/ticker/#{id}/"
|
42
|
+
url << "?#{params}" if params.present?
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
response = HTTP.get(url)
|
45
|
+
json = JSON.parse(response.body.to_s, symbolize_names: true)
|
46
|
+
json.is_a?(Array) ? json.first : json
|
47
|
+
end
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
# @param symbol [String] Coin symbol
|
50
|
+
# @return [Hash]
|
51
|
+
def coin_by_symbol(symbol)
|
52
|
+
response = HTTP.get("#{API_URL}/ticker/?limit=0")
|
53
|
+
json = JSON.parse(response.body.to_s, symbolize_names: true)
|
54
|
+
json.find { |x| x[:symbol].strip.casecmp(symbol.strip.upcase).zero? }
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
57
|
+
# @param id [String] Coin market cap id
|
58
|
+
# @param symbol [String] Coin symbol
|
59
|
+
# @return [Array<Hash>]
|
60
|
+
def coin_markets(id: nil, symbol: nil)
|
61
|
+
raise ArgumentError.new('id or symbol is required') if id.blank? && symbol.blank?
|
62
|
+
|
63
|
+
coin_id = symbol.present? ? coin_by_symbol(symbol)[:id] : id
|
64
|
+
response = HTTP.get("#{BASE_URL}/currencies/#{coin_id}/\#markets")
|
65
|
+
html = Nokogiri::HTML(response.body.to_s)
|
66
|
+
rows = html.css('table#markets-table tbody tr')
|
67
|
+
return { error: 'invalid id' } if rows.blank?
|
68
|
+
|
69
|
+
markets = rows.each_with_object([]) do |row, arr|
|
70
|
+
td = row.css('td')
|
71
|
+
arr << {
|
72
|
+
source: td[1].text.strip,
|
73
|
+
pair: td[2].text.strip,
|
74
|
+
volume_usd: td[3].text.strip[/\$(.+)/, 1].delete(',').to_f,
|
75
|
+
price_usd: td[4].text.strip[/\$(.+)/, 1].delete(',').to_f,
|
76
|
+
volume_percentage: td[5].text.to_f,
|
77
|
+
last_updated: td[6].text.strip
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
markets
|
77
82
|
end
|
78
83
|
|
79
|
-
|
80
|
-
|
84
|
+
# @param currency [String] Country currency code to convert price
|
85
|
+
# @return [Hash]
|
86
|
+
def global(currency: nil)
|
87
|
+
params = {
|
88
|
+
convert: currency
|
89
|
+
}.compact.to_param
|
81
90
|
|
82
|
-
|
83
|
-
|
84
|
-
def self.global(currency: nil)
|
85
|
-
params = {
|
86
|
-
convert: currency
|
87
|
-
}.compact.to_param
|
91
|
+
url = "#{API_URL}/global/"
|
92
|
+
url << "?#{params}" if params.present?
|
88
93
|
|
89
|
-
|
90
|
-
|
94
|
+
response = HTTP.get(url)
|
95
|
+
JSON.parse(response.body.to_s, symbolize_names: true)
|
96
|
+
end
|
91
97
|
|
92
|
-
|
93
|
-
|
94
|
-
|
98
|
+
# @param id [String] Coinmarketcap coin id
|
99
|
+
# @param start_date [String] Start date (YYYY-MM-DD)
|
100
|
+
# @param end_date [String] End date (YYYY-MM-DD)
|
101
|
+
# @return [Array<Hash>]
|
102
|
+
def historical_price(id, start_date, end_date)
|
103
|
+
sd = parse_date(start_date, format: '%Y%m%d')
|
104
|
+
ed = parse_date(end_date, format: '%Y%m%d')
|
105
|
+
return { error: 'invalid date format' } if sd.blank? || ed.blank?
|
106
|
+
|
107
|
+
url = "#{BASE_URL}/currencies/#{id}/historical-data/?start=#{sd}&end=#{ed}"
|
108
|
+
response = HTTP.get(url)
|
109
|
+
html = Nokogiri::HTML(response.body.to_s)
|
110
|
+
rows = html.css('#historical-data table tbody tr')
|
111
|
+
return { error: 'invalid id' } if rows.blank?
|
112
|
+
|
113
|
+
prices = rows.each_with_object([]) do |row, arr|
|
114
|
+
td = row.css('td')
|
115
|
+
daily = {
|
116
|
+
date: parse_date(td[0].text, format: '%F'),
|
117
|
+
open: td[1].text.to_f,
|
118
|
+
high: td[2].text.to_f,
|
119
|
+
low: td[3].text.to_f,
|
120
|
+
close: td[4].text.to_f
|
121
|
+
}
|
122
|
+
|
123
|
+
daily[:average] = ((daily[:high] + daily[:low]).to_d / 2).to_f
|
124
|
+
arr << daily
|
125
|
+
end
|
126
|
+
|
127
|
+
prices
|
128
|
+
end
|
95
129
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
130
|
+
# Returns list of cryptocurrencies by type (coins, tokens)
|
131
|
+
# @param type [String] Cryptocurrency type. i.e. 'coins' or 'tokens'
|
132
|
+
# @return [Array<Hash>] List of all coins (or tokens)
|
133
|
+
def all(type)
|
134
|
+
return { error: 'invalid type' } unless /coins|tokens/ =~ type
|
135
|
+
|
136
|
+
url = "#{BASE_URL}/#{type}/views/all/"
|
137
|
+
response = HTTP.get(url)
|
138
|
+
html = Nokogiri::HTML(response.body.to_s)
|
139
|
+
table = html.css('table#currencies-all, table#assets-all')
|
140
|
+
rows = table.css('tbody tr')
|
141
|
+
|
142
|
+
cryptos = rows.each_with_object([]) do |row, arr|
|
143
|
+
td = row.css('td')
|
144
|
+
arr << {
|
145
|
+
id: row&.attribute('id')&.text[/id-(.+)/, 1],
|
146
|
+
rank: td[0].text.to_i,
|
147
|
+
name: td[1].css('a.currency-name-container').text.strip,
|
148
|
+
symbol: type.eql?('coins') ? td[2].text : nil,
|
149
|
+
platform: type.eql?('tokens') ? td[2].text : nil,
|
150
|
+
market_cap_usd: td[3]&.attribute('data-usd')&.text.to_f,
|
151
|
+
market_cap_btc: td[3]&.attribute('data-btc')&.text.to_f,
|
152
|
+
price_usd: td[4].css('a.price')&.attribute('data-usd')&.text.to_f,
|
153
|
+
price_btc: td[4].css('a.price')&.attribute('data-btc')&.text.to_f,
|
154
|
+
circulating_supply: td[5].css('a, span')&.attribute('data-supply')&.text.to_f,
|
155
|
+
volume_usd_24h: td[6].css('a')&.attribute('data-usd')&.text.to_f,
|
156
|
+
volume_btc_24h: td[6].css('a')&.attribute('data-btc')&.text.to_f,
|
157
|
+
percent_change_1h: td[7]&.attribute('data-usd')&.text.to_f,
|
158
|
+
percent_change_24h: td[8]&.attribute('data-usd')&.text.to_f,
|
159
|
+
percent_change_7d: td[9]&.attribute('data-usd')&.text.to_f
|
160
|
+
}.compact
|
161
|
+
end
|
162
|
+
|
163
|
+
cryptos
|
164
|
+
rescue StandardError => e
|
165
|
+
{
|
166
|
+
message: 'An unknown error occurred. Please submit a GitHub issue if problem continues.',
|
167
|
+
error: e.message
|
117
168
|
}
|
118
|
-
|
119
|
-
daily[:average] = ((daily[:high] + daily[:low]).to_d / 2).to_f
|
120
|
-
arr << daily
|
121
169
|
end
|
122
170
|
|
123
|
-
|
171
|
+
private
|
172
|
+
|
173
|
+
def parse_date(date, format: nil)
|
174
|
+
d = Date.parse(date)
|
175
|
+
return d if format.blank?
|
176
|
+
d.strftime(format)
|
177
|
+
rescue StandardError
|
178
|
+
nil
|
179
|
+
end
|
124
180
|
end
|
125
181
|
end
|
data/lib/coincapper/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coincapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kurt Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -114,28 +114,28 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
117
|
+
version: '0.52'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
124
|
+
version: '0.52'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: simplecov
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
131
|
+
version: '0.14'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
138
|
+
version: '0.14'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: webmock
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,8 +150,9 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '3.2'
|
153
|
-
description: coinmarketcap.com V1 API wrapper including additional historical prices
|
154
|
-
|
153
|
+
description: coinmarketcap.com V1 API wrapper including additional historical prices,
|
154
|
+
coin market pairs, and currencies by type (coins/tokens) parsed from Coin Market
|
155
|
+
Cap.
|
155
156
|
email:
|
156
157
|
- zippydev@protonmail.com
|
157
158
|
executables: []
|
@@ -196,5 +197,5 @@ rubyforge_project:
|
|
196
197
|
rubygems_version: 2.6.11
|
197
198
|
signing_key:
|
198
199
|
specification_version: 4
|
199
|
-
summary:
|
200
|
+
summary: Coinmarketcap V1 API wrapper
|
200
201
|
test_files: []
|