kaesen 0.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.
@@ -0,0 +1,26 @@
1
+ require_relative 'market.rb'
2
+ require 'net/http'
3
+ require 'openssl'
4
+ require 'json'
5
+ require 'date'
6
+ require 'bigdecimal'
7
+
8
+ module Kaesen
9
+ # BitFlyer FX Wrapper Class
10
+ # https://coincheck.jp/documents/exchange/api?locale=ja
11
+ ## API制限
12
+ ## . Private API は 1 分間に約 200 回を上限とします。
13
+ ## . IP アドレスごとに 1 分間に約 500 回を上限とします。
14
+
15
+ class Bitflyerfx < Bitflyer
16
+ def initialize
17
+ super()
18
+ @name = "BitFlyerFX"
19
+ @product_code = "FX_BTC_JPY"
20
+ end
21
+
22
+ def balance
23
+ raise NotImplemented.new() # getcollateral
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,294 @@
1
+ require_relative 'market.rb'
2
+ require 'net/http'
3
+ require 'openssl'
4
+ require 'json'
5
+ require 'bigdecimal'
6
+
7
+ module Kaesen
8
+ # BtcBox Wrapper Class
9
+ # https://www.btcbox.co.jp/help/api.html
10
+
11
+ class Btcbox < Market
12
+ @@nonce = 0
13
+
14
+ def initialize()
15
+ super()
16
+ @name = "BtcBox"
17
+ @api_key = ENV["BTCBOX_KEY"]
18
+ @api_secret = ENV["BTCBOX_SECRET"]
19
+ @url_public = "https://www.btcbox.co.jp/api/v1"
20
+ @url_private = @url_public
21
+ end
22
+
23
+ #############################################################
24
+ # API for public information
25
+ #############################################################
26
+
27
+ # Get ticker information.
28
+ # @return [hash] ticker
29
+ # ask: [BigDecimal] 最良売気配値
30
+ # bid: [BigDecimal] 最良買気配値
31
+ # last: [BigDecimal] 最近値(?用語要チェック), last price
32
+ # high: [BigDecimal] 高値
33
+ # low: [BigDecimal] 安値
34
+ # volume: [BigDecimal] 取引量
35
+ # ltimestamp: [int] ローカルタイムスタンプ
36
+ def ticker
37
+ h = get_ssl(@url_public + "/ticker")
38
+ {
39
+ "ask" => BigDecimal.new(h["sell"].to_s),
40
+ "bid" => BigDecimal.new(h["buy"].to_s),
41
+ "last" => BigDecimal.new(h["last"].to_s),
42
+ "high" => BigDecimal.new(h["high"].to_s),
43
+ "low" => BigDecimal.new(h["low"].to_s),
44
+ "volume" => BigDecimal.new(h["vol"].to_s),
45
+ "ltimestamp" => Time.now.to_i,
46
+ }
47
+ end
48
+
49
+ # Get order book.
50
+ # @abstract
51
+ # @return [hash] array of market depth
52
+ # asks: [Array] 売りオーダー
53
+ # price : [BigDecimal]
54
+ # size : [BigDecimal]
55
+ # bids: [Array] 買いオーダー
56
+ # price : [BigDecimal]
57
+ # size : [BigDecimal]
58
+ # ltimestamp: [int] ローカルタイムスタンプ
59
+ def depth
60
+ h = get_ssl(@url_public + "/depth")
61
+ {
62
+ "asks" => h["asks"].map{|a,b| [BigDecimal.new(a.to_s), BigDecimal.new(b.to_s)]}, # to_s でないと誤差が生じる
63
+ "bids" => h["bids"].map{|a,b| [BigDecimal.new(a.to_s), BigDecimal.new(b.to_s)]}, # to_s でないと誤差が生じる
64
+ "ltimestamp" => Time.now.to_i,
65
+ }
66
+ end
67
+
68
+ #############################################################
69
+ # API for private user data and trading
70
+ #############################################################
71
+
72
+ # Get account balance.
73
+ # @abstract
74
+ # @return [hash] account_balance_hash
75
+ # jpy: [hash]
76
+ # amount: [BigDecimal] 総日本円
77
+ # available: [BigDecimal] 取引可能な日本円
78
+ # btc [hash]
79
+ # amount: [BigDecimal] 総BTC
80
+ # available: [BigDecimal] 取引可能なBTC
81
+ # ltimestamp: [int] ローカルタイムスタンプ
82
+ def balance
83
+ have_key?
84
+ h = post_ssl_with_sign(@url_private + "/balance/")
85
+ {
86
+ "jpy" => {
87
+ "amount" => BigDecimal.new(h["jpy_balance"].to_s) + BigDecimal.new(h["jpy_lock"].to_s),
88
+ "available" => BigDecimal.new(h["jpy_balance"].to_s),
89
+ },
90
+ "btc" => {
91
+ "amount" => BigDecimal.new(h["btc_balance"].to_s) + BigDecimal.new(h["btc_lock"].to_s),
92
+ "available" => BigDecimal.new(h["btc_balance"].to_s),
93
+ },
94
+ "ltimestamp" => Time.now.to_i,
95
+ }
96
+ end
97
+
98
+ # Get open orders.
99
+ # @abstract
100
+ # @return [Array] open_orders_array
101
+ # @return [hash] history_order_hash
102
+ # success: [bool]
103
+ # id: [String] order id in the market
104
+ # rate: [BigDecimal]
105
+ # amount: [BigDecimal]
106
+ # order_type: [String] "sell" or "buy"
107
+ # ltimestamp: [int] Local Timestamp
108
+ def opens
109
+ have_key?
110
+ address = @url_private + "/trade_list/"
111
+ params = {
112
+ "type" => "open",
113
+ }
114
+ h = post_ssl_with_sign(address, params)
115
+ h.map{|x|
116
+ {
117
+ "success" => "true",
118
+ "id" => x["id"],
119
+ "rate" => BigDecimal.new(x["price"].to_s),
120
+ "amount" => BigDecimal.new(x["amount_outstanding"].to_s),
121
+ "order_type" => x["type"],
122
+ }
123
+ }
124
+ end
125
+
126
+ # Bought the amount of Bitcoin at the rate.
127
+ # 指数注文 買い.
128
+ # Abstract Method.
129
+ # @param [BigDecimal] rate
130
+ # @param [BigDecimal] amount # minimal trade amount is 0.01 BTC
131
+ # @return [hash] history_order_hash
132
+ # success: [String] "true" or "false"
133
+ # id: [String] order id at the market
134
+ # rate: [BigDecimal]
135
+ # amount: [BigDecimal] minimal amount is 0.01 BTC
136
+ # order_type: [String] "sell" or "buy"
137
+ # ltimestamp: [int] ローカルタイムスタンプ
138
+ def buy(rate, amount=BigDecimal.new(0))
139
+ have_key?
140
+ address = @url_private + "/trade_add/"
141
+ params = {
142
+ "amount" => amount.to_f.round(4),
143
+ "price" => rate.to_i,
144
+ "type" => "buy",
145
+ }
146
+ h = post_ssl_with_sign(address, params)
147
+ {
148
+ "success" => h["result"].to_s,
149
+ "id" => h["id"].to_s,
150
+ "rate" => BigDecimal.new(rate.to_s),
151
+ "amount" => BigDecimal.new(amount.to_s),
152
+ "order_type" => "sell",
153
+ "ltimestamp" => Time.now.to_i,
154
+ }
155
+ end
156
+
157
+ # Sell the amount of Bitcoin at the rate.
158
+ # 指数注文 売り.
159
+ # Abstract Method.
160
+ # @param [BigDecimal] rate
161
+ # @param [BigDecimal] amount # minimal trade amount is 0.01 BTC
162
+ # @return [hash] history_order_hash
163
+ # success: [String] "true" or "false"
164
+ # id: [String] order id at the market
165
+ # rate: [BigDecimal]
166
+ # amount: [BigDecimal] minimal amount is 0.01 BTC
167
+ # order_type: [String] "sell" or "buy"
168
+ # ltimestamp: [int] ローカルタイムスタンプ
169
+ def sell(rate, amount=BigDecimal.new(0))
170
+ have_key?
171
+ address = @url_private + "/trade_add/"
172
+ params = {
173
+ "amount" => amount.to_f.round(4),
174
+ "price" => rate.to_i,
175
+ "type" => "sell",
176
+ }
177
+ h = post_ssl_with_sign(address, params)
178
+ {
179
+ "success" => h["result"].to_s,
180
+ "id" => h["id"].to_s,
181
+ "rate" => BigDecimal.new(rate.to_s),
182
+ "amount" => BigDecimal.new(amount.to_s),
183
+ "order_type" => "sell",
184
+ "ltimestamp" => Time.now.to_i,
185
+ }
186
+ end
187
+
188
+ private
189
+
190
+ def initialize_https(uri)
191
+ https = Net::HTTP.new(uri.host, uri.port)
192
+ https.use_ssl = true
193
+ https.open_timeout = 5
194
+ https.read_timeout = 15
195
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
196
+ https.verify_depth = 5
197
+ https
198
+ end
199
+
200
+ # Connect to address via https, and return json reponse.
201
+ def get_ssl(address)
202
+ uri = URI.parse(address)
203
+
204
+ begin
205
+ https = initialize_https(uri)
206
+ https.start {|w|
207
+ response = w.get(uri.request_uri)
208
+ case response
209
+ when Net::HTTPSuccess
210
+ json = JSON.parse(response.body)
211
+ raise JSONException, response.body if json == nil
212
+ return json
213
+ else
214
+ raise ConnectionFailedException, "Failed to connect to #{@name}."
215
+ end
216
+ }
217
+ rescue
218
+ raise
219
+ end
220
+ end
221
+
222
+ def get_nonce
223
+ pre_nonce = @@nonce
224
+ next_nonce = (1000*Time.now.to_f).to_i
225
+
226
+ if next_nonce <= pre_nonce
227
+ @@nonce = pre_nonce + 1
228
+ else
229
+ @@nonce = next_nonce
230
+ end
231
+
232
+ return @@nonce
233
+ end
234
+
235
+ def get_sign(params)
236
+ secret = Digest::MD5.hexdigest(@api_secret)
237
+ text = URI.encode_www_form(params)
238
+
239
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text)
240
+ end
241
+
242
+ def get_ssl_with_sign(address, params={})
243
+ uri = URI.parse(address)
244
+ params["key"] = @api_key
245
+ params["nonce"] = get_nonce
246
+ params["signature"] = get_sign(params)
247
+
248
+ begin
249
+ req = Net::HTTP::Get.new(uri)
250
+ req.set_form(params)
251
+
252
+ https = initialize_https(uri)
253
+ https.start {|w|
254
+ response = w.request(req)
255
+ case response
256
+ when Net::HTTPSuccess
257
+ json = JSON.parse(response.body)
258
+ return json
259
+ else
260
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
261
+ end
262
+ }
263
+ rescue
264
+ raise
265
+ end
266
+ end
267
+
268
+ def post_ssl_with_sign(address, params={})
269
+ uri = URI.parse(address)
270
+ params["key"] = @api_key
271
+ params["nonce"] = get_nonce
272
+ params["signature"] = get_sign(params)
273
+
274
+ begin
275
+ req = Net::HTTP::Post.new(uri)
276
+ req.set_form(params)
277
+
278
+ https = initialize_https(uri)
279
+ https.start {|w|
280
+ response = w.request(req)
281
+ case response
282
+ when Net::HTTPSuccess
283
+ json = JSON.parse(response.body)
284
+ return json
285
+ else
286
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
287
+ end
288
+ }
289
+ rescue
290
+ raise
291
+ end
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,65 @@
1
+ module Kaesen
2
+ class Client
3
+ attr_reader :markets
4
+ attr_reader :ticker
5
+ attr_reader :balance
6
+ attr_reader :depth
7
+
8
+ def initialize
9
+ @markets = [] # [Array]:
10
+ # [Market] instance of markets
11
+ @tickers = {} # [Hash]
12
+ # [String]: market name
13
+ # [Hash]: hash of ticker
14
+ @depths = {} # [Hash]:
15
+ # [String]: market name
16
+ # [Hash]: hash of depth
17
+ @balances = {} # [Hash]:
18
+ # [String]: market name
19
+ # [Hash]: hash of depth
20
+ end
21
+
22
+ # register the instance of market
23
+ # @parm [Market]
24
+ def push(market)
25
+ @markets.push(market)
26
+ end
27
+
28
+ # get the instance of market with key
29
+ # @parms [String] market name
30
+ # @return [Market] or nil
31
+ def get(market_name)
32
+ @markets.each{|m|
33
+ return m if m.name == market_name
34
+ }
35
+ return nil
36
+ end
37
+
38
+ # Update market information.
39
+ # @return [hash] hash of ticker
40
+ def update_tickers()
41
+ @markets.each{|m|
42
+ @tickers[m.name] = m.ticker
43
+ }
44
+ @tickers
45
+ end
46
+
47
+ # Update market information.
48
+ # @return [hash] hash of depth
49
+ def update_depths()
50
+ @markets.each{|m|
51
+ @depths[m.name] = m.depth
52
+ }
53
+ @depths
54
+ end
55
+
56
+ # Update asset information.
57
+ # @return [hash] hash of balance
58
+ def update_balances()
59
+ @markets.each{|m|
60
+ @balances[m.name] = m.balance
61
+ }
62
+ @balances
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,371 @@
1
+ require_relative 'market.rb'
2
+ require 'net/http'
3
+ require 'openssl'
4
+ require 'json'
5
+ require 'bigdecimal'
6
+
7
+ module Kaesen
8
+ # Coincheck Wrapper Class
9
+ # https://coincheck.jp/documents/exchange/api?locale=ja
10
+
11
+ class Coincheck < Market
12
+ @@nonce = 0
13
+
14
+ def initialize()
15
+ super()
16
+ @name = "Coincheck"
17
+ @api_key = ENV["COINCHECK_KEY"]
18
+ @api_secret = ENV["COINCHECK_SECRET"]
19
+ @url_public = "https://coincheck.jp"
20
+ @url_private = @url_public
21
+ end
22
+
23
+ #############################################################
24
+ # API for public information
25
+ #############################################################
26
+
27
+ # Get ticker information.
28
+ # @return [hash] ticker
29
+ # ask: [BigDecimal] 最良売気配値
30
+ # bid: [BigDecimal] 最良買気配値
31
+ # last: [BigDecimal] 最近値(?用語要チェック), last price
32
+ # high: [BigDecimal] 高値
33
+ # low: [BigDecimal] 安値
34
+ # volume: [BigDecimal] 取引量
35
+ # ltimestamp: [int] ローカルタイムスタンプ
36
+ # timestamp: [int] タイムスタンプ
37
+ def ticker
38
+ h = get_ssl(@url_public + "/api/ticker")
39
+ @ticker =
40
+ {
41
+ "ask" => BigDecimal.new(h["ask"].to_s),
42
+ "bid" => BigDecimal.new(h["bid"].to_s),
43
+ "last" => BigDecimal.new(h["last"].to_s),
44
+ "high" => BigDecimal.new(h["high"].to_s),
45
+ "low" => BigDecimal.new(h["low"].to_s),
46
+ "volume" => BigDecimal.new(h["volume"].to_s),
47
+ "ltimestamp" => Time.now.to_i,
48
+ "timestamp" => h["timestamp"].to_i,
49
+ }
50
+ end
51
+
52
+ # Get order book.
53
+ # @abstract
54
+ # @return [hash] array of market depth
55
+ # asks: [Array] 売りオーダー
56
+ # price : [BigDecimal]
57
+ # size : [BigDecimal]
58
+ # bids: [Array] 買いオーダー
59
+ # price : [BigDecimal]
60
+ # size : [BigDecimal]
61
+ # ltimestamp: [int] ローカルタイムスタンプ
62
+ def depth
63
+ h = get_ssl(@url_public + "/api/order_books")
64
+ {
65
+ "asks" => h["asks"].map{|a,b| [BigDecimal.new(a.to_s), BigDecimal.new(b.to_s)]},
66
+ "bids" => h["bids"].map{|a,b| [BigDecimal.new(a.to_s), BigDecimal.new(b.to_s)]},
67
+ "ltimestamp" => Time.now.to_i,
68
+ }
69
+ end
70
+
71
+ #############################################################
72
+ # API for private user data and trading
73
+ #############################################################
74
+
75
+ # Get account balance.
76
+ # @abstract
77
+ # @return [hash] account_balance_hash
78
+ # jpy: [hash]
79
+ # amount: [BigDecimal] 総日本円
80
+ # available: [BigDecimal] 取引可能な日本円
81
+ # btc [hash]
82
+ # amount: [BigDecimal] 総BTC
83
+ # available: [BigDecimal] 取引可能なBTC
84
+ # ltimestamp: [int] ローカルタイムスタンプ
85
+ def balance
86
+ have_key?
87
+ address = @url_private + "/api/accounts/balance"
88
+ h = get_ssl_with_sign(address)
89
+ {
90
+ "jpy" => {
91
+ "amount" => BigDecimal.new(h["jpy"].to_s) + BigDecimal.new(h["jpy_reserved"].to_s),
92
+ "available" => BigDecimal.new(h["jpy"].to_s),
93
+ },
94
+ "btc" => {
95
+ "amount" => BigDecimal.new(h["btc"].to_s) + BigDecimal.new(h["btc_reserved"].to_s),
96
+ "available" => BigDecimal.new(h["btc"].to_s),
97
+ },
98
+ "ltimestamp" => Time.now.to_i,
99
+ }
100
+ end
101
+
102
+ # Get open orders.
103
+ # @abstract
104
+ # @return [Array] open_orders_array
105
+ # @return [hash] history_order_hash
106
+ # success: [bool]
107
+ # id: [String] order id in the market
108
+ # rate: [BigDecimal]
109
+ # amount: [BigDecimal]
110
+ # order_type: [String] "sell" or "buy"
111
+ # ltimestamp: [int] Local Timestamp
112
+ def opens
113
+ have_key?
114
+ address = @url_private + "/api/exchange/orders/opens"
115
+ h = get_ssl_with_sign(address)
116
+ h["orders"].map{|x|
117
+ {
118
+ "success" => "true",
119
+ "id" => x["id"].to_s,
120
+ "rate" => BigDecimal.new(x["rate"].to_s),
121
+ "amount" => BigDecimal.new(x["pending_amount"].to_s),
122
+ "order_type" => x["order_type"],
123
+ }
124
+ }
125
+ end
126
+
127
+ # Buy the amount of Bitcoin at the rate.
128
+ # 指数注文 買い.
129
+ # @abstract
130
+ # @param [BigDecimal] rate
131
+ # @param [BigDecimal] amount # # minimal trade amount is 0.005 BTC
132
+ # @return [hash] history_order_hash
133
+ # success: [String] "true" or "false"
134
+ # id: [String] order id at the market
135
+ # rate: [BigDecimal]
136
+ # amount: [BigDecimal]
137
+ # order_type: [String] "sell" or "buy"
138
+ # ltimestamp: [int] ローカルタイムスタンプ
139
+ # timestamp: [int] タイムスタンプ
140
+ def buy(rate, amount=BigDecimal.new(0))
141
+ have_key?
142
+ address = @url_private + "/api/exchange/orders"
143
+ body = {
144
+ "rate" => rate.to_i,
145
+ "amount" => amount.to_f.round(4),
146
+ "order_type" => "buy",
147
+ "pair" => "btc_jpy",
148
+ }
149
+ h = post_ssl_with_sign(address,body)
150
+ {
151
+ "success" => h["success"].to_s,
152
+ "id" => h["id"].to_s,
153
+ "rate" => BigDecimal.new(h["rate"].to_s),
154
+ "amount" => BigDecimal.new(h["size"].to_s),
155
+ "order_type" => h["order_type"],
156
+ "ltimestamp" => Time.now.to_i,
157
+ "timestamp" => DateTime.parse(h["created_at"]).to_time.to_i,
158
+ }
159
+ end
160
+
161
+ # Buy the amount of Bitcoin from the market.
162
+ # 成行注文 買い.
163
+ # @abstract
164
+ # @param [BigDecimal] amount
165
+ # @return [hash] history_order_hash
166
+ # success: [bool]
167
+ # id: [String] order id in the market
168
+ # rate: [BigDecimal]
169
+ # market_buy_amount: [BigDecimal] amount of JPY
170
+ # order_type: [String] "sell" or "buy"
171
+ # ltimestamp: [int] Local Timestamp
172
+ def market_buy(market_buy_amount=BigDecimal.new("0.0"))
173
+ have_key?
174
+ address = @url_private + "/api/exchange/orders"
175
+ body = {
176
+ "market_buy_amount" => market_buy_amount.to_f.round(4),
177
+ "order_type" => "market_buy",
178
+ "pair" => "btc_jpy",
179
+ }
180
+ h = post_ssl_with_sign(address,body)
181
+ {
182
+ "success" => h["success"].to_s,
183
+ "id" => h["id"].to_s,
184
+ "rate" => BigDecimal.new(h["rate"].to_s),
185
+ "amount" => BigDecimal.new(h["size"].to_s),
186
+ "order_type" => h["order_type"],
187
+ "ltimestamp" => Time.now.to_i,
188
+ "timestamp" => DateTime.parse(h["created_at"]).to_time.to_i,
189
+ }
190
+ end
191
+
192
+ # Sell the amount of Bitcoin at the rate.
193
+ # 指数注文 売り.
194
+ # @abstract
195
+ # @param [BigDecimal] rate
196
+ # @param [BigDecimal] amount # minimal trade amount is 0.005 BTC
197
+ # @return [hash] history_order_hash
198
+ # success: [String] "true" or "false"
199
+ # id: [String] order id at the market
200
+ # rate: [BigDecimal]
201
+ # amount: [BigDecimal]
202
+ # order_type: [String] "sell" or "buy"
203
+ # ltimestamp: [int] ローカルタイムスタンプ
204
+ # timestamp: [int] タイムスタンプ
205
+ def sell(rate, amount=BigDecimal.new(0))
206
+ have_key?
207
+ address = @url_private + "/api/exchange/orders"
208
+ body = {
209
+ "rate" => rate.to_i,
210
+ "amount" => amount.to_f.round(4),
211
+ "order_type" => "sell",
212
+ "pair" => "btc_jpy",
213
+ }
214
+ h = post_ssl_with_sign(address,body)
215
+ {
216
+ "success" => h["success"].to_s,
217
+ "id" => h["id"].to_s,
218
+ "rate" => BigDecimal.new(h["rate"].to_s),
219
+ "amount" => BigDecimal.new(h["size"].to_s),
220
+ "order_type" => h["order_type"],
221
+ "ltimestamp" => Time.now.to_i,
222
+ "timestamp" => DateTime.parse(h["created_at"]).to_time.to_i,
223
+ }
224
+ end
225
+
226
+ # Sell the amount of Bitcoin to the market.
227
+ # 成行注文 売り.
228
+ # @abstract
229
+ # @param [BigDecimal] amount
230
+ # @return [hash] history_order_hash
231
+ # success: [bool]
232
+ # id: [String] order id in the market
233
+ # rate: [BigDecimal]
234
+ # amount: [BigDecimal]
235
+ # order_type: [String] "sell" or "buy"
236
+ # ltimestamp: [int] Local Timestamp
237
+ def market_sell(amount=BigDecimal.new("0.0"))
238
+ have_key?
239
+ address = @url_private + "/api/exchange/orders"
240
+ body = {
241
+ "amount" => amount.to_f.round(4),
242
+ "order_type" => "market_sell",
243
+ "pair" => "btc_jpy",
244
+ }
245
+ h = post_ssl_with_sign(address,body)
246
+ {
247
+ "success" => h["success"].to_s,
248
+ "id" => h["id"].to_s,
249
+ "rate" => BigDecimal.new(h["rate"].to_s),
250
+ "amount" => BigDecimal.new(h["size"].to_s),
251
+ "order_type" => h["order_type"],
252
+ "ltimestamp" => Time.now.to_i,
253
+ "timestamp" => DateTime.parse(h["created_at"]).to_time.to_i,
254
+ }
255
+ end
256
+
257
+ private
258
+
259
+ def initialize_https(uri)
260
+ https = Net::HTTP.new(uri.host, uri.port)
261
+ https.use_ssl = true
262
+ https.open_timeout = 5
263
+ https.read_timeout = 15
264
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
265
+ https.verify_depth = 5
266
+ https
267
+ end
268
+
269
+ def get_nonce
270
+ pre_nonce = @@nonce
271
+ next_nonce = (1000*Time.now.to_f).to_i
272
+
273
+ if next_nonce <= pre_nonce
274
+ @@nonce = pre_nonce + 1
275
+ else
276
+ @@nonce = next_nonce
277
+ end
278
+
279
+ return @@nonce
280
+ end
281
+
282
+ def get_sign(address, nonce, body)
283
+ secret = @api_secret
284
+ text = nonce.to_s + address.to_s + body
285
+
286
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, text)
287
+ end
288
+
289
+ # Connect to address via https, and return json response.
290
+ def get_ssl(address)
291
+ uri = URI.parse(address)
292
+ begin
293
+ https = initialize_https(uri)
294
+ https.start {|w|
295
+ response = w.get(uri.request_uri)
296
+ case response
297
+ when Net::HTTPSuccess
298
+ json = JSON.parse(response.body)
299
+ raise JSONException, response.body if json == nil
300
+ return json
301
+ else
302
+ raise ConnectionFailedException, "Failed to connect to #{@name}."
303
+ end
304
+ }
305
+ rescue
306
+ raise
307
+ end
308
+ end
309
+
310
+ def get_headers(address, nonce, body="")
311
+ {
312
+ "ACCESS-KEY" => @api_key,
313
+ "ACCESS-NONCE" => nonce.to_s,
314
+ "ACCESS-SIGNATURE" => get_sign(address, nonce, body.to_json),
315
+ "Content-Type" => "application/json",
316
+ }
317
+ end
318
+
319
+ # Connect to address via https, and return json response.
320
+ def get_ssl_with_sign(address,body="")
321
+ uri = URI.parse(address)
322
+ nonce = get_nonce
323
+ headers = get_headers(address, nonce, body)
324
+
325
+ begin
326
+ req = Net::HTTP::Get.new(uri, headers)
327
+ req.body = body.to_json
328
+
329
+ https = initialize_https(uri)
330
+ https.start {|w|
331
+ response = w.request(req)
332
+ case response
333
+ when Net::HTTPSuccess
334
+ json = JSON.parse(response.body)
335
+ raise JSONException, response.body if json == nil
336
+ return json
337
+ else
338
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
339
+ end
340
+ }
341
+ rescue
342
+ raise
343
+ end
344
+ end
345
+
346
+ def post_ssl_with_sign(address, body="")
347
+ uri = URI.parse(address)
348
+ nonce = get_nonce
349
+ headers = get_headers(address, nonce, body)
350
+
351
+ begin
352
+ req = Net::HTTP::Post.new(uri, headers)
353
+ req.body = body.to_json
354
+
355
+ https = initialize_https(uri)
356
+ https.start {|w|
357
+ response = w.request(req)
358
+ case response
359
+ when Net::HTTPSuccess
360
+ json = JSON.parse(response.body)
361
+ return json
362
+ else
363
+ raise ConnectionFailedException, "Failed to connect to #{@name}: " + response.value
364
+ end
365
+ }
366
+ rescue
367
+ raise
368
+ end
369
+ end
370
+ end
371
+ end