lita-onewheel-finance 0.6.0 → 0.7.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/lib/lita/handlers/alphavantage_quote.rb +68 -0
- data/lib/lita/handlers/irc_colors.rb +43 -0
- data/lib/lita/handlers/onewheel_finance.rb +47 -227
- data/lib/lita/handlers/worldtradedata_quote.rb +128 -0
- data/lib/lita/handlers/yahoo_quote.rb +58 -0
- data/lita-onewheel-finance.gemspec +1 -1
- data/spec/fixtures/yahoo-quote.json +1664 -0
- metadata +9 -4
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef2f754f9b1fe08aa1fe7749a6cc7b338e83b0ecb5d2745decb441f8773f278e
|
4
|
+
data.tar.gz: 95d1163691c52c32eeae155112c0d86fad7bec95226ec56156e28ef94eceb616
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33982576f1623d697254375a928dab14974cac4173d8f6079d30c381d8ce56b62d13013ec799f7ca07c1b6e6c8a5f585cdce4d2ae0aaa329072483890b155e71
|
7
|
+
data.tar.gz: cd8eb5c4a74651005cf8579511af016206fbceca03337c4b323b892e6c4204057c8d7df8bc00b05c7df5788648aa7ce0940197c2533ed920d0488c5e4d5d40cb
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class AlphaVantageQuote
|
2
|
+
attr_reader :open, :high, :low, :price, :volume, :trading_day, :prev_close, :change, :change_percent, :exchange, :error, :name, :message, :is_index
|
3
|
+
attr_accessor :symbol
|
4
|
+
|
5
|
+
def initialize(symbol, apikey)
|
6
|
+
# Lita.logger.debug "parsing: #{json_blob}"
|
7
|
+
# hash = JSON.parse(json_blob)
|
8
|
+
@symbol = symbol
|
9
|
+
@apikey = apikey
|
10
|
+
@is_index = false
|
11
|
+
|
12
|
+
if @symbol[0] == '^'
|
13
|
+
@is_index = true
|
14
|
+
end
|
15
|
+
|
16
|
+
response = call_api
|
17
|
+
hash = JSON.parse response
|
18
|
+
|
19
|
+
quote = hash["Global Quote"]
|
20
|
+
|
21
|
+
quote.keys.each do |key|
|
22
|
+
case key
|
23
|
+
when "01. symbol"
|
24
|
+
@symbol = quote[key]
|
25
|
+
when "02. open"
|
26
|
+
@open = self.fix_number quote[key]
|
27
|
+
when "03. high"
|
28
|
+
@high = self.fix_number quote[key]
|
29
|
+
when "04. low"
|
30
|
+
@low = self.fix_number quote[key]
|
31
|
+
when "05. price"
|
32
|
+
@price = self.fix_number quote[key]
|
33
|
+
when "06. volume"
|
34
|
+
@volume = quote[key]
|
35
|
+
when "07. latest trading day"
|
36
|
+
@trading_day = quote[key]
|
37
|
+
when "08. previous close"
|
38
|
+
@prev_close = self.fix_number quote[key]
|
39
|
+
when "09. change"
|
40
|
+
@change = self.fix_number quote[key]
|
41
|
+
when "10. change percent"
|
42
|
+
@change_percent = self.fix_number quote[key]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def fix_number(price_str)
|
48
|
+
price_str.to_f.round(2)
|
49
|
+
end
|
50
|
+
|
51
|
+
def is_index?
|
52
|
+
@is_index
|
53
|
+
end
|
54
|
+
|
55
|
+
def call_api
|
56
|
+
url = "https://www.alphavantage.co/query"
|
57
|
+
params = {function: 'GLOBAL_QUOTE', symbol: @symbol, apikey: @apikey}
|
58
|
+
Lita.logger.debug "#{url} #{params.inspect}"
|
59
|
+
response = RestClient.get url, {params: params}
|
60
|
+
|
61
|
+
# if @exchange
|
62
|
+
# params[:stock_exchange] = @exchange
|
63
|
+
# end
|
64
|
+
|
65
|
+
Lita.logger.debug "response: #{response}"
|
66
|
+
response
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module IrcColors
|
2
|
+
prefix = "\x03"
|
3
|
+
@white = "#{prefix}00"
|
4
|
+
@black = "#{prefix}01"
|
5
|
+
@blue = "#{prefix}02"
|
6
|
+
@green = "#{prefix}03"
|
7
|
+
@red = "#{prefix}04"
|
8
|
+
@brown = "#{prefix}05"
|
9
|
+
@purple = "#{prefix}06"
|
10
|
+
@orange = "#{prefix}07"
|
11
|
+
@yellow = "#{prefix}08"
|
12
|
+
@lime = "#{prefix}09"
|
13
|
+
@teal = "#{prefix}10"
|
14
|
+
@aqua = "#{prefix}11"
|
15
|
+
@royal = "#{prefix}12"
|
16
|
+
@pink = "#{prefix}13"
|
17
|
+
@grey = "#{prefix}14"
|
18
|
+
@silver = "#{prefix}15"
|
19
|
+
@reset = prefix
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_reader :white,
|
23
|
+
:black,
|
24
|
+
:blue,
|
25
|
+
:green,
|
26
|
+
:red,
|
27
|
+
:brown,
|
28
|
+
:purple,
|
29
|
+
:orange,
|
30
|
+
:yellow,
|
31
|
+
:lime,
|
32
|
+
:teal,
|
33
|
+
:aqua,
|
34
|
+
:royal,
|
35
|
+
:pink,
|
36
|
+
:grey,
|
37
|
+
:silver,
|
38
|
+
:reset
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
end
|
43
|
+
end
|
@@ -1,226 +1,32 @@
|
|
1
|
+
require_relative 'irc_colors'
|
2
|
+
require_relative 'alphavantage_quote'
|
3
|
+
require_relative 'worldtradedata_quote'
|
4
|
+
require_relative 'yahoo_quote'
|
1
5
|
require 'rest-client'
|
2
6
|
|
3
|
-
class IrcColors
|
4
|
-
prefix = "\x03"
|
5
|
-
@white = "#{prefix}00"
|
6
|
-
@black = "#{prefix}01"
|
7
|
-
@blue = "#{prefix}02"
|
8
|
-
@green = "#{prefix}03"
|
9
|
-
@red = "#{prefix}04"
|
10
|
-
@brown = "#{prefix}05"
|
11
|
-
@purple = "#{prefix}06"
|
12
|
-
@orange = "#{prefix}07"
|
13
|
-
@yellow = "#{prefix}08"
|
14
|
-
@lime = "#{prefix}09"
|
15
|
-
@teal = "#{prefix}10"
|
16
|
-
@aqua = "#{prefix}11"
|
17
|
-
@royal = "#{prefix}12"
|
18
|
-
@pink = "#{prefix}13"
|
19
|
-
@grey = "#{prefix}14"
|
20
|
-
@silver = "#{prefix}15"
|
21
|
-
@reset = prefix
|
22
|
-
|
23
|
-
class << self
|
24
|
-
attr_reader :white,
|
25
|
-
:black,
|
26
|
-
:blue,
|
27
|
-
:green,
|
28
|
-
:red,
|
29
|
-
:brown,
|
30
|
-
:purple,
|
31
|
-
:orange,
|
32
|
-
:yellow,
|
33
|
-
:lime,
|
34
|
-
:teal,
|
35
|
-
:aqua,
|
36
|
-
:royal,
|
37
|
-
:pink,
|
38
|
-
:grey,
|
39
|
-
:silver,
|
40
|
-
:reset
|
41
|
-
end
|
42
|
-
|
43
|
-
def initialize
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class AlphaVantageQuote
|
48
|
-
attr_reader :symbol, :open, :high, :low, :price, :volume, :trading_day, :prev_close, :change, :change_percent
|
49
|
-
|
50
|
-
def initialize(json_blob)
|
51
|
-
Lita.logger.debug "parsing: #{json_blob}"
|
52
|
-
hash = JSON.parse(json_blob)
|
53
|
-
quote = hash["Global Quote"]
|
54
|
-
|
55
|
-
quote.keys.each do |key|
|
56
|
-
case key
|
57
|
-
when "01. symbol"
|
58
|
-
@symbol = quote[key]
|
59
|
-
when "02. open"
|
60
|
-
@open = self.fix_number quote[key]
|
61
|
-
when "03. high"
|
62
|
-
@high = self.fix_number quote[key]
|
63
|
-
when "04. low"
|
64
|
-
@low = self.fix_number quote[key]
|
65
|
-
when "05. price"
|
66
|
-
@price = self.fix_number quote[key]
|
67
|
-
when "06. volume"
|
68
|
-
@volume = quote[key]
|
69
|
-
when "07. latest trading day"
|
70
|
-
@trading_day = quote[key]
|
71
|
-
when "08. previous close"
|
72
|
-
@prev_close = self.fix_number quote[key]
|
73
|
-
when "09. change"
|
74
|
-
@change = self.fix_number quote[key]
|
75
|
-
when "10. change percent"
|
76
|
-
@change_percent = self.fix_number quote[key]
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def fix_number(price_str)
|
82
|
-
price_str.to_f.round(2)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class WorldTradeDataQuote
|
87
|
-
attr_reader :open, :high, :low, :price, :volume, :trading_day, :prev_close, :change, :change_percent, :exchange, :error, :name, :message, :is_index
|
88
|
-
attr_accessor :symbol
|
89
|
-
|
90
|
-
def initialize(symbol, api_key)
|
91
|
-
@base_uri = 'https://api.worldtradingdata.com/api/v1'
|
92
|
-
@symbol = symbol
|
93
|
-
@api_key = api_key
|
94
|
-
|
95
|
-
if @symbol[':']
|
96
|
-
(@exchange, @symbol) = @symbol.split /:/
|
97
|
-
end
|
98
|
-
|
99
|
-
if @symbol['^']
|
100
|
-
@is_index = true
|
101
|
-
else
|
102
|
-
@is_index = false
|
103
|
-
end
|
104
|
-
|
105
|
-
self.call_api
|
106
|
-
|
107
|
-
hash = JSON.parse(@response)
|
108
|
-
|
109
|
-
# We couldn't find the stock. Let's look for it real quick.
|
110
|
-
if hash['Message'].to_s.include? 'Error'
|
111
|
-
@error = true
|
112
|
-
self.run_search
|
113
|
-
|
114
|
-
if @message
|
115
|
-
@error = true
|
116
|
-
return
|
117
|
-
else
|
118
|
-
self.call_api
|
119
|
-
hash = JSON.parse(@response)
|
120
|
-
@error = false
|
121
|
-
end
|
122
|
-
else
|
123
|
-
@error = false
|
124
|
-
end
|
125
|
-
|
126
|
-
unless hash['data']
|
127
|
-
@message = "Error getting data for #{@symbol}"
|
128
|
-
@error = true
|
129
|
-
return
|
130
|
-
end
|
131
|
-
|
132
|
-
quote = hash['data'][0]
|
133
|
-
|
134
|
-
quote.keys.each do |key|
|
135
|
-
case key
|
136
|
-
when "symbol"
|
137
|
-
@symbol = quote[key]
|
138
|
-
when "price_open"
|
139
|
-
@open = self.fix_number quote[key]
|
140
|
-
when "day_high"
|
141
|
-
@high = self.fix_number quote[key]
|
142
|
-
when "day_low"
|
143
|
-
@low = self.fix_number quote[key]
|
144
|
-
when "price"
|
145
|
-
@price = self.fix_number quote[key]
|
146
|
-
when "volume"
|
147
|
-
@volume = quote[key].to_i
|
148
|
-
when "last_trade_time"
|
149
|
-
@trading_day = quote[key]
|
150
|
-
when "08. previous close"
|
151
|
-
@prev_close = self.fix_number quote[key]
|
152
|
-
when "day_change"
|
153
|
-
@change = self.fix_number quote[key]
|
154
|
-
when "change_pct"
|
155
|
-
@change_percent = self.fix_number quote[key]
|
156
|
-
when 'stock_exchange_short'
|
157
|
-
@exchange = quote[key].sub /NYSEARCA/, 'NYSE'
|
158
|
-
when 'name'
|
159
|
-
@name = quote[key]
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def is_index?
|
164
|
-
is_index
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Let's see what we can get from the api.
|
169
|
-
def call_api
|
170
|
-
url = "#{@base_uri}/stock"
|
171
|
-
params = {symbol: @symbol, api_token: @api_key}
|
172
|
-
|
173
|
-
if @exchange
|
174
|
-
params[:stock_exchange] = @exchange
|
175
|
-
end
|
176
|
-
|
177
|
-
Lita.logger.debug "call_api: #{url} #{params.inspect}"
|
178
|
-
|
179
|
-
@response = RestClient.get url, {params: params}
|
180
|
-
|
181
|
-
Lita.logger.debug "response: #{@response}"
|
182
|
-
end
|
183
|
-
|
184
|
-
def run_search
|
185
|
-
url = "#{@base_uri}/stock_search"
|
186
|
-
params = {search_term: @symbol,
|
187
|
-
search_by: 'symbol,name',
|
188
|
-
stock_exchange: 'NASDAQ,NYSE',
|
189
|
-
limit: 5,
|
190
|
-
page: 1,
|
191
|
-
api_token: @api_key
|
192
|
-
}
|
193
|
-
|
194
|
-
Lita.logger.debug "run_search: #{url} #{params.inspect}"
|
195
|
-
|
196
|
-
response = RestClient.get url, {params: params}
|
197
|
-
|
198
|
-
Lita.logger.debug "response: #{response}"
|
199
|
-
result = JSON.parse(response)
|
200
|
-
|
201
|
-
if result['total_returned'] == 1
|
202
|
-
@symbol = result['data'][0]['symbol']
|
203
|
-
elsif result['total_returned'].to_i > 1
|
204
|
-
Lita.logger.debug "many search results: #{result.inspect}"
|
205
|
-
x = result['data'].map { |k| k.values[0] }
|
206
|
-
@message = "`#{symbol}` not found, did you mean one of #{x.join(', ')}?"
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def fix_number(price_str)
|
211
|
-
price_str.to_f.round(2)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
7
|
module Lita
|
216
8
|
module Handlers
|
217
9
|
class OnewheelFinance < Handler
|
218
10
|
config :apikey, required: true
|
11
|
+
config :mode, default: 'irc'
|
12
|
+
config :handler, default: 'alphavantage'
|
219
13
|
route /qu*o*t*e*\s+(.+)/i, :handle_quote, command: true
|
14
|
+
# route /q2\s+(.+)/i, :handle_alphavantage, command: true
|
220
15
|
|
221
16
|
def handle_quote(response)
|
222
|
-
stock =
|
17
|
+
stock = nil
|
18
|
+
if config.handler == 'worldtradedata'
|
19
|
+
stock = handle_world_trade_data response.matches[0][0]
|
20
|
+
elsif config.handler == 'alphavantage'
|
21
|
+
stock = handle_alphavantage response.matches[0][0]
|
22
|
+
elsif config.handler == 'yahoo'
|
23
|
+
stock = handle_yahoo response.matches[0][0]
|
24
|
+
else
|
25
|
+
Lita.logger.error "Unknown/missing config.handler #{config.handler}. Try 'worldtradedata' or 'alphavantage'"
|
26
|
+
return
|
27
|
+
end
|
223
28
|
|
29
|
+
# Continue!
|
224
30
|
if stock.error
|
225
31
|
if stock.message
|
226
32
|
str = stock.message
|
@@ -233,14 +39,27 @@ module Lita
|
|
233
39
|
dollar_sign = ''
|
234
40
|
end
|
235
41
|
|
236
|
-
|
237
|
-
if
|
238
|
-
#
|
239
|
-
|
240
|
-
|
42
|
+
# IRC mode
|
43
|
+
if config.mode == 'irc'
|
44
|
+
str = "#{IrcColors::grey}#{stock.exchange} - #{IrcColors::reset}#{stock.symbol}: #{IrcColors::blue}#{dollar_sign}#{stock.price}#{IrcColors::reset} "
|
45
|
+
if stock.change >= 0
|
46
|
+
# if irc
|
47
|
+
str += "#{IrcColors::green} ⬆#{dollar_sign}#{stock.change}#{IrcColors::reset}, #{IrcColors::green}#{stock.change_percent}%#{IrcColors::reset} "
|
48
|
+
str += "#{IrcColors::grey}(#{stock.name})#{IrcColors::reset}"
|
49
|
+
else
|
50
|
+
str += "#{IrcColors::red} ↯#{dollar_sign}#{stock.change}#{IrcColors::reset}, #{IrcColors::red}#{stock.change_percent}%#{IrcColors::reset} "
|
51
|
+
str += "#{IrcColors::grey}(#{stock.name})#{IrcColors::reset}"
|
52
|
+
end
|
241
53
|
else
|
242
|
-
str
|
243
|
-
|
54
|
+
str = "#{stock.exchange} - #{stock.symbol}: #{dollar_sign}#{stock.price} "
|
55
|
+
if stock.change >= 0
|
56
|
+
# if irc
|
57
|
+
str += " :arrow_up:#{dollar_sign}#{stock.change}, :heavy_plus_sign:#{stock.change_percent}% "
|
58
|
+
str += "(#{stock.name})"
|
59
|
+
else
|
60
|
+
str += " :chart_with_downwards_trend:#{dollar_sign}#{stock.change}, :heavy_minus_sign:#{stock.change_percent}% "
|
61
|
+
str += "(#{stock.name})"
|
62
|
+
end
|
244
63
|
end
|
245
64
|
end
|
246
65
|
|
@@ -256,13 +75,14 @@ module Lita
|
|
256
75
|
end
|
257
76
|
|
258
77
|
# deprecated for now
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
#
|
264
|
-
|
265
|
-
|
78
|
+
def handle_alphavantage(symbol)
|
79
|
+
stock = AlphaVantageQuote.new symbol, config.apikey
|
80
|
+
end
|
81
|
+
|
82
|
+
# welp
|
83
|
+
def handle_yahoo(symbol)
|
84
|
+
stock = YahooQuote.new symbol, config.apikey
|
85
|
+
end
|
266
86
|
|
267
87
|
Lita.register_handler(self)
|
268
88
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
class WorldTradeDataQuote
|
2
|
+
attr_reader :open, :high, :low, :price, :volume, :trading_day, :prev_close, :change, :change_percent, :exchange, :error, :name, :message, :is_index
|
3
|
+
attr_accessor :symbol
|
4
|
+
|
5
|
+
def initialize(symbol, api_key)
|
6
|
+
@base_uri = 'https://api.worldtradingdata.com/api/v1'
|
7
|
+
@symbol = symbol
|
8
|
+
@api_key = api_key
|
9
|
+
|
10
|
+
if @symbol[':']
|
11
|
+
(@exchange, @symbol) = @symbol.split /:/
|
12
|
+
end
|
13
|
+
|
14
|
+
if @symbol['^']
|
15
|
+
@is_index = true
|
16
|
+
else
|
17
|
+
@is_index = false
|
18
|
+
end
|
19
|
+
|
20
|
+
self.call_api
|
21
|
+
|
22
|
+
hash = JSON.parse(@response)
|
23
|
+
|
24
|
+
# We couldn't find the stock. Let's look for it real quick.
|
25
|
+
if hash['Message'].to_s.include? 'Error'
|
26
|
+
@error = true
|
27
|
+
self.run_search
|
28
|
+
|
29
|
+
if @message
|
30
|
+
@error = true
|
31
|
+
return
|
32
|
+
else
|
33
|
+
self.call_api
|
34
|
+
hash = JSON.parse(@response)
|
35
|
+
@error = false
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@error = false
|
39
|
+
end
|
40
|
+
|
41
|
+
unless hash['data']
|
42
|
+
@message = "Error getting data for #{@symbol}"
|
43
|
+
@error = true
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
quote = hash['data'][0]
|
48
|
+
|
49
|
+
quote.keys.each do |key|
|
50
|
+
case key
|
51
|
+
when "symbol"
|
52
|
+
@symbol = quote[key]
|
53
|
+
when "price_open"
|
54
|
+
@open = self.fix_number quote[key]
|
55
|
+
when "day_high"
|
56
|
+
@high = self.fix_number quote[key]
|
57
|
+
when "day_low"
|
58
|
+
@low = self.fix_number quote[key]
|
59
|
+
when "price"
|
60
|
+
@price = self.fix_number quote[key]
|
61
|
+
when "volume"
|
62
|
+
@volume = quote[key].to_i
|
63
|
+
when "last_trade_time"
|
64
|
+
@trading_day = quote[key]
|
65
|
+
when "08. previous close"
|
66
|
+
@prev_close = self.fix_number quote[key]
|
67
|
+
when "day_change"
|
68
|
+
@change = self.fix_number quote[key]
|
69
|
+
when "change_pct"
|
70
|
+
@change_percent = self.fix_number quote[key]
|
71
|
+
when 'stock_exchange_short'
|
72
|
+
@exchange = quote[key].sub /NYSEARCA/, 'NYSE'
|
73
|
+
when 'name'
|
74
|
+
@name = quote[key]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_index?
|
79
|
+
is_index
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Let's see what we can get from the api.
|
84
|
+
def call_api
|
85
|
+
url = "#{@base_uri}/stock"
|
86
|
+
params = {symbol: @symbol, api_token: @api_key}
|
87
|
+
|
88
|
+
if @exchange
|
89
|
+
params[:stock_exchange] = @exchange
|
90
|
+
end
|
91
|
+
|
92
|
+
Lita.logger.debug "call_api: #{url} #{params.inspect}"
|
93
|
+
|
94
|
+
@response = RestClient.get url, {params: params}
|
95
|
+
|
96
|
+
Lita.logger.debug "response: #{@response}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def run_search
|
100
|
+
url = "#{@base_uri}/stock_search"
|
101
|
+
params = {search_term: @symbol,
|
102
|
+
search_by: 'symbol,name',
|
103
|
+
stock_exchange: 'NASDAQ,NYSE',
|
104
|
+
limit: 5,
|
105
|
+
page: 1,
|
106
|
+
api_token: @api_key
|
107
|
+
}
|
108
|
+
|
109
|
+
Lita.logger.debug "run_search: #{url} #{params.inspect}"
|
110
|
+
|
111
|
+
response = RestClient.get url, {params: params}
|
112
|
+
|
113
|
+
Lita.logger.debug "response: #{response}"
|
114
|
+
result = JSON.parse(response)
|
115
|
+
|
116
|
+
if result['total_returned'] == 1
|
117
|
+
@symbol = result['data'][0]['symbol']
|
118
|
+
elsif result['total_returned'].to_i > 1
|
119
|
+
Lita.logger.debug "many search results: #{result.inspect}"
|
120
|
+
x = result['data'].map { |k| k.values[0] }
|
121
|
+
@message = "`#{symbol}` not found, did you mean one of #{x.join(', ')}?"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def fix_number(price_str)
|
126
|
+
price_str.to_f.round(2)
|
127
|
+
end
|
128
|
+
end
|