coinpare 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pastel'
4
+ require 'tty-pager'
5
+ require 'tty-spinner'
6
+ require 'tty-table'
7
+ require 'timers'
8
+
9
+ require_relative '../command'
10
+ require_relative '../fetcher'
11
+
12
+ module Coinpare
13
+ module Commands
14
+ class Markets < Coinpare::Command
15
+ def initialize(name, options)
16
+ @name = name
17
+ @options = options
18
+ @pastel = Pastel.new
19
+ @timers = Timers::Group.new
20
+ @spinner = TTY::Spinner.new(':spinner Fetching data...',
21
+ format: :dots, clear: true)
22
+ end
23
+
24
+ def execute(input: $stdin, output: $stdout)
25
+ pager = TTY::Pager::BasicPager.new(output: output)
26
+ @spinner.auto_spin
27
+
28
+ if @options['watch']
29
+ output.print cursor.hide
30
+ interval = @options['watch'].to_f > 0 ? @options['watch'].to_f : DEFAULT_INTERVAL
31
+ @timers.now_and_every(interval) { display_markets(output, pager) }
32
+ loop { @timers.wait }
33
+ else
34
+ display_markets(output, pager)
35
+ end
36
+ ensure
37
+ @spinner.stop
38
+ if @options['watch']
39
+ @timers.cancel
40
+ output.print cursor.clear_screen_down
41
+ output.print cursor.show
42
+ end
43
+ end
44
+
45
+ def display_markets(output, pager)
46
+ to_symbol = fetch_symbol
47
+ response = Fetcher.fetch_top_exchanges_by_pair(
48
+ @name.upcase, @options['base'].upcase, @options)
49
+ return unless response
50
+ table = setup_table(response["Data"]["Exchanges"], to_symbol)
51
+
52
+ lines = banner.lines.size + 1 + table.rows_size + 3
53
+ @spinner.stop
54
+ clear_output(output, lines) { print_results(table, output, pager) }
55
+ end
56
+
57
+ def clear_output(output, lines)
58
+ output.print cursor.clear_screen_down if @options['watch']
59
+ yield if block_given?
60
+ output.print cursor.up(lines) if @options['watch']
61
+ end
62
+
63
+ def print_results(table, output, pager)
64
+ output.puts banner
65
+ pager.page(table.render(:unicode, padding: [0, 1], alignment: :right))
66
+ output.puts
67
+ end
68
+
69
+ def fetch_symbol
70
+ prices = Fetcher.fetch_prices(
71
+ @name.upcase, @options['base'].upcase, @options)
72
+ return unless prices
73
+ prices['DISPLAY'][@name.upcase][@options['base'].upcase]['TOSYMBOL']
74
+ end
75
+
76
+ def banner
77
+ "\n#{add_color('Coin', :yellow)} #{@name.upcase} " \
78
+ "#{add_color('Base Currency', :yellow)} #{@options['base'].upcase} " \
79
+ "#{add_color('Time', :yellow)} #{timestamp}\n\n"
80
+ end
81
+
82
+ def setup_table(data, to_symbol)
83
+ table = TTY::Table.new(header: [
84
+ { value: 'Market', alignment: :left },
85
+ 'Price',
86
+ 'Chg. 24H',
87
+ 'Chg.% 24H',
88
+ 'Open 24H',
89
+ 'High 24H',
90
+ 'Low 24H',
91
+ 'Direct Vol. 24H',
92
+ ])
93
+
94
+ data.each do |market|
95
+ change24h = market['CHANGE24HOUR']
96
+ market_details = [
97
+ { value: add_color(market['MARKET'], :yellow), alignment: :left },
98
+ add_color("#{to_symbol} #{number_to_currency(round_to(market['PRICE']))}", pick_color(change24h)),
99
+ add_color("#{pick_arrow(change24h)} #{to_symbol} #{number_to_currency(round_to(change24h))}", pick_color(change24h)),
100
+ add_color("#{pick_arrow(change24h)} #{round_to(market['CHANGEPCT24HOUR'] * 100)}%", pick_color(change24h)),
101
+ "#{to_symbol} #{number_to_currency(round_to(market['OPEN24HOUR']))}",
102
+ "#{to_symbol} #{number_to_currency(round_to(market['HIGH24HOUR']))}",
103
+ "#{to_symbol} #{number_to_currency(round_to(market['LOW24HOUR']))}",
104
+ "#{to_symbol} #{number_to_currency(round_to(market['VOLUME24HOURTO']))}"
105
+ ]
106
+ table << market_details
107
+ end
108
+
109
+ table
110
+ end
111
+ end # Markets
112
+ end # Commands
113
+ end # Coinpare
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Coinpare
7
+ # Handle all data fetching from remote api
8
+ module Fetcher
9
+ API_URL = "https://min-api.cryptocompare.com/data/"
10
+
11
+ def handle_response(response)
12
+ status = response["Response"]
13
+ if status == "Error"
14
+ puts response["Message"]
15
+ exit
16
+ end
17
+ response
18
+ end
19
+ module_function :handle_response
20
+
21
+ def fetch_json(url)
22
+ uri = URI.parse(url)
23
+ http = Net::HTTP.new(uri.host, uri.port)
24
+ http.read_timeout = 5
25
+ http.use_ssl = uri.scheme == 'https'
26
+ response = http.start { |req| req.get(uri.request_uri) }
27
+ case response
28
+ when Net::HTTPSuccess
29
+ handle_response(JSON.parse(response.body))
30
+ else
31
+ response.value
32
+ end
33
+ rescue Net::ReadTimeout
34
+ end
35
+ module_function :fetch_json
36
+
37
+ def fetch_daily_hist(from_symbol, to_symbol, options)
38
+ url = ["#{API_URL}histoday"]
39
+ url << "?fsym=BTC&tsym=USD&limit=7&aggregate=7"
40
+
41
+ fetch_json(url.join)
42
+ end
43
+
44
+ def fetch_top_coins_by_volume(to_symbol, options)
45
+ url = ["#{API_URL}top/totalvol"]
46
+ url << "?tsym=#{to_symbol}"
47
+ url << "&limit=#{options['top']}&page=0" if options['top']
48
+
49
+ fetch_json(url.join)
50
+ end
51
+ module_function :fetch_top_coins_by_volume
52
+
53
+ def fetch_prices(from_symbols, to_symbols, options)
54
+ url = ["#{API_URL}pricemultifull"]
55
+ url << "?fsyms=#{from_symbols}&tsyms=#{to_symbols}"
56
+ url << "&e=#{options['exchange']}" if options['exchange']
57
+ url << "&tryConversion=true"
58
+
59
+ fetch_json(url.join)
60
+ end
61
+ module_function :fetch_prices
62
+
63
+ def fetch_top_exchanges_by_pair(from_symbol, to_symbol, options)
64
+ url = ["#{API_URL}top/exchanges/full"]
65
+ url << "?fsym=#{from_symbol}&tsym=#{to_symbol}"
66
+ url << "&limit=#{options['top']}&page=0" if options['top']
67
+
68
+ fetch_json(url.join)
69
+ end
70
+ module_function :fetch_top_exchanges_by_pair
71
+ end
72
+ end
@@ -1,3 +1,3 @@
1
1
  module Coinpare
2
- VERSION = "0.0.0"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,197 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coinpare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-03 00:00:00.000000000 Z
11
+ date: 2018-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tty-color
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty-config
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: tty-cursor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: tty-editor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.4.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.4.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: tty-font
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.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.2.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-pager
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.11.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.11.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-prompt
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.16.1
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.16.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: tty-spinner
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.8.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.8.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: tty-table
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.10.0
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.10.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: pastel
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.7.2
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.7.2
153
+ - !ruby/object:Gem::Dependency
154
+ name: thor
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 0.20.0
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 0.20.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: toml
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 0.2.0
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 0.2.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: timers
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 4.1.2
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 4.1.2
13
195
  - !ruby/object:Gem::Dependency
14
196
  name: bundler
15
197
  requirement: !ruby/object:Gem::Requirement
@@ -52,15 +234,46 @@ dependencies:
52
234
  - - "~>"
53
235
  - !ruby/object:Gem::Version
54
236
  version: '3.0'
55
- description: Write a longer description or delete this line.
56
- email: []
57
- executables: []
237
+ - !ruby/object:Gem::Dependency
238
+ name: webmock
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: '3.3'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - "~>"
249
+ - !ruby/object:Gem::Version
250
+ version: '3.3'
251
+ - !ruby/object:Gem::Dependency
252
+ name: timecop
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: 0.9.1
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: 0.9.1
265
+ description: Compare cryptocurrency trading data across multiple exchanges and blockchains.
266
+ email:
267
+ - ''
268
+ executables:
269
+ - coinpare
58
270
  extensions: []
59
271
  extra_rdoc_files: []
60
272
  files:
61
273
  - ".gitignore"
62
274
  - ".rspec"
63
275
  - ".travis.yml"
276
+ - CHANGELOG.md
64
277
  - CODE_OF_CONDUCT.md
65
278
  - Gemfile
66
279
  - LICENSE.txt
@@ -69,11 +282,19 @@ files:
69
282
  - bin/console
70
283
  - bin/setup
71
284
  - coinpare.gemspec
285
+ - exe/coinpare
72
286
  - lib/coinpare.rb
287
+ - lib/coinpare/cli.rb
288
+ - lib/coinpare/command.rb
289
+ - lib/coinpare/commands/.gitkeep
290
+ - lib/coinpare/commands/coins.rb
291
+ - lib/coinpare/commands/holdings.rb
292
+ - lib/coinpare/commands/markets.rb
293
+ - lib/coinpare/fetcher.rb
73
294
  - lib/coinpare/version.rb
74
- homepage:
295
+ homepage: https://github.com/piotrmurach/coinpare
75
296
  licenses:
76
- - MIT
297
+ - AGPL-3.0
77
298
  metadata: {}
78
299
  post_install_message:
79
300
  rdoc_options: []
@@ -91,8 +312,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
312
  version: '0'
92
313
  requirements: []
93
314
  rubyforge_project:
94
- rubygems_version: 2.5.1
315
+ rubygems_version: 2.7.3
95
316
  signing_key:
96
317
  specification_version: 4
97
- summary: Write a short summary, because RubyGems requires one.
318
+ summary: Compare cryptocurrency trading data across multiple exchanges and blockchains.
98
319
  test_files: []