bitget.rb 0.4.0 → 0.5.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/bitget.rb.gemspec +1 -1
- data/lib/Bitget/V2/Client.rb +1796 -15
- data/lib/Bitget/{VERSION.rb → VERSiON.rb} +1 -1
- data/test/V2/client_logging_test.rb +92 -0
- data/test/V2/client_test.rb +1083 -43
- data/test/client_test.rb +164 -75
- metadata +5 -6
- data/lib/Bitget/V2/Client2.rb +0 -500
- data/lib/Hash/to_parameter_string.rb +0 -26
data/lib/Bitget/V2/Client2.rb
DELETED
@@ -1,500 +0,0 @@
|
|
1
|
-
# Bitget/V2/Client.rb
|
2
|
-
# Bitget::V2::Client
|
3
|
-
|
4
|
-
require 'fileutils'
|
5
|
-
gem 'http.rb'; require 'http.rb'
|
6
|
-
require 'json'
|
7
|
-
require 'logger'
|
8
|
-
require 'openssl'
|
9
|
-
|
10
|
-
require_relative '../Error'
|
11
|
-
require_relative '../../Hash/to_parameter_string'
|
12
|
-
require_relative '../../Hash/x_www_form_urlencode'
|
13
|
-
|
14
|
-
module Bitget
|
15
|
-
module V2
|
16
|
-
class Client
|
17
|
-
|
18
|
-
API_HOST = 'api.bitget.com'
|
19
|
-
|
20
|
-
class << self
|
21
|
-
attr_writer :log_file_path
|
22
|
-
|
23
|
-
def path_prefix
|
24
|
-
'/api/v2'
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_log_file_path
|
28
|
-
File.join(%w{~ log bitget log.txt})
|
29
|
-
end
|
30
|
-
|
31
|
-
def log_file_path
|
32
|
-
File.expand_path(@log_file_path || default_log_file_path)
|
33
|
-
end
|
34
|
-
|
35
|
-
def log_file
|
36
|
-
FileUtils.mkdir_p(File.dirname(log_file_path))
|
37
|
-
File.open(log_file_path, File::WRONLY | File::APPEND | File::CREAT)
|
38
|
-
end
|
39
|
-
|
40
|
-
def logger
|
41
|
-
@logger ||= Logger.new(log_file, 'daily')
|
42
|
-
end
|
43
|
-
end # class << self
|
44
|
-
|
45
|
-
# Market
|
46
|
-
|
47
|
-
def spot_public_coins(coin: nil)
|
48
|
-
response = get(path: '/spot/public/coins', args: {coin: coin})
|
49
|
-
handle_response(response)
|
50
|
-
end
|
51
|
-
|
52
|
-
def spot_public_symbols(symbol: nil)
|
53
|
-
response = get(path: '/spot/public/symbols', args: {symbol: symbol})
|
54
|
-
handle_response(response)
|
55
|
-
end
|
56
|
-
|
57
|
-
def spot_market_vip_free_rate
|
58
|
-
response = get(path: '/spot/market/vip-fee-rate')
|
59
|
-
handle_response(response)
|
60
|
-
end
|
61
|
-
|
62
|
-
def spot_market_tickers(symbol: nil)
|
63
|
-
response = get(path: '/spot/market/tickers', args: {symbol: symbol})
|
64
|
-
handle_response(response)
|
65
|
-
end
|
66
|
-
|
67
|
-
def spot_market_merge_depth(symbol:, precision: nil, limit: nil)
|
68
|
-
response = get(path: '/spot/market/merge-depth', args: {symbol: symbol, precision: precision, limit: limit})
|
69
|
-
handle_response(response)
|
70
|
-
end
|
71
|
-
|
72
|
-
def spot_market_orderbook(symbol:, type: nil, limit: nil)
|
73
|
-
response = get(path: '/spot/market/orderbook', args: {symbol: symbol, type: type, limit: limit})
|
74
|
-
handle_response(response)
|
75
|
-
end
|
76
|
-
|
77
|
-
def spot_market_candles(symbol:, granularity:, start_time: nil, end_time: nil, limit: nil)
|
78
|
-
response = get(
|
79
|
-
path: '/spot/market/candles',
|
80
|
-
args: {symbol: symbol, granularity: granularity, startTime: start_time, endTime: end_time, limit: limit}
|
81
|
-
)
|
82
|
-
handle_response(response)
|
83
|
-
end
|
84
|
-
|
85
|
-
def spot_market_history_candles(symbol:, granularity:, end_time: nil, limit: nil)
|
86
|
-
response = get(
|
87
|
-
path: '/spot/market/history-candles',
|
88
|
-
args: {symbol: symbol, granularity: granularity, endTime: end_time, limit: limit}
|
89
|
-
)
|
90
|
-
handle_response(response)
|
91
|
-
end
|
92
|
-
|
93
|
-
def spot_market_fills(symbol:, limit: nil)
|
94
|
-
response = get(path: '/spot/market/fills', args: {symbol: symbol, limit: limit})
|
95
|
-
handle_response(response)
|
96
|
-
end
|
97
|
-
|
98
|
-
def spot_market_fills_history(symbol:, limit: nil, id_less_than: nil, start_time: nil, end_time: nil)
|
99
|
-
response = get(
|
100
|
-
path: '/spot/market/fills-history',
|
101
|
-
args: {symbol: symbol, limit: limit, idLessThan: id_less_than, startTime: start_time, endTime: end_time}
|
102
|
-
)
|
103
|
-
handle_response(response)
|
104
|
-
end
|
105
|
-
|
106
|
-
# Trade
|
107
|
-
|
108
|
-
def trade_place_order(
|
109
|
-
symbol:,
|
110
|
-
side:,
|
111
|
-
order_type:,
|
112
|
-
force:,
|
113
|
-
price: nil,
|
114
|
-
size:,
|
115
|
-
client_order_id: nil,
|
116
|
-
trigger_price: nil,
|
117
|
-
tpsl_type: nil,
|
118
|
-
request_time: nil,
|
119
|
-
receive_window: nil,
|
120
|
-
stp_mode: nil,
|
121
|
-
preset_take_profit_price: nil,
|
122
|
-
execute_take_profit_price: nil,
|
123
|
-
preset_stop_loss_price: nil,
|
124
|
-
execute_stop_loss_price: nil
|
125
|
-
)
|
126
|
-
response = post(
|
127
|
-
path: '/trade/place-order',
|
128
|
-
args: {
|
129
|
-
symbol: symbol,
|
130
|
-
side: side,
|
131
|
-
orderType: order_type,
|
132
|
-
force: force,
|
133
|
-
price: price,
|
134
|
-
size: size,
|
135
|
-
client_order_id: clientOid,
|
136
|
-
trigger_price: triggerPrice,
|
137
|
-
tpsl_type: tpslType,
|
138
|
-
request_time: requestTime,
|
139
|
-
receive_window: receiveWindow,
|
140
|
-
stp_mode: stpMode,
|
141
|
-
preset_take_profit_price: presetTakeProfitPrice,
|
142
|
-
execute_take_profit_price: executeTakeProfitPrice,
|
143
|
-
preset_stop_loss_price: presetStopLossPrice,
|
144
|
-
execute_stop_loss_price: executeStopLossPrice,
|
145
|
-
}
|
146
|
-
)
|
147
|
-
handle_response(response)
|
148
|
-
end
|
149
|
-
|
150
|
-
def trade_cancel_replace_order(
|
151
|
-
symbol:,
|
152
|
-
price:,
|
153
|
-
size:,
|
154
|
-
client_order_id: nil,
|
155
|
-
order_id: nil,
|
156
|
-
new_client_order_id: nil,
|
157
|
-
preset_take_profit_price: nil,
|
158
|
-
execute_take_profit_price: nil,
|
159
|
-
preset_stop_loss_price: nil,
|
160
|
-
execute_stop_loss_price: nil
|
161
|
-
)
|
162
|
-
response = post(
|
163
|
-
path: '/trade/cancel-replace-order',
|
164
|
-
args: {
|
165
|
-
symbol: symbol,
|
166
|
-
price: price,
|
167
|
-
size: size,
|
168
|
-
client_order_id: clientOid,
|
169
|
-
order_id: orderId,
|
170
|
-
newClientOid: new_client_order_id,
|
171
|
-
preset_take_profit_price: presetTakeProfitPrice,
|
172
|
-
execute_take_profit_price: executeTakeProfitPrice,
|
173
|
-
preset_stop_loss_price: presetStopLossPrice,
|
174
|
-
execute_stop_loss_price: executeStopLossPrice,
|
175
|
-
}
|
176
|
-
)
|
177
|
-
handle_response(response)
|
178
|
-
end
|
179
|
-
|
180
|
-
# I got lazy... (with specifying the args)
|
181
|
-
|
182
|
-
def trade_batch_cancel_replace_order(**args)
|
183
|
-
response = post(path: '/trade/batch-cancel-replace-order', args: args)
|
184
|
-
handle_response(response)
|
185
|
-
end
|
186
|
-
|
187
|
-
def trade_cancel_order(**args)
|
188
|
-
response = post(path: '/trade/cancel-order', args: args)
|
189
|
-
handle_response(response)
|
190
|
-
end
|
191
|
-
|
192
|
-
def trade_batch_orders(**args)
|
193
|
-
response = post(path: '/trade/batch-orders', args: args)
|
194
|
-
handle_response(response)
|
195
|
-
end
|
196
|
-
|
197
|
-
def trade_batch_cancel_order
|
198
|
-
response = post(path: '/trade/batch-cancel-order', args: args)
|
199
|
-
handle_response(response)
|
200
|
-
end
|
201
|
-
|
202
|
-
def trade_cancel_symbol_order(symbol:)
|
203
|
-
response = post(path: '/trade/cancel-symbol-order', args: {symbol: symbol})
|
204
|
-
handle_response(response)
|
205
|
-
end
|
206
|
-
|
207
|
-
def trade_order_info(**args)
|
208
|
-
response = get(path: '/trade/orderInfo', args: args)
|
209
|
-
handle_response(response)
|
210
|
-
end
|
211
|
-
|
212
|
-
def trade_unfilled_orders(**args)
|
213
|
-
response = get(path: '/trade/unfilled-orders', args: args)
|
214
|
-
handle_response(response)
|
215
|
-
end
|
216
|
-
|
217
|
-
def trade_history_orders(**args)
|
218
|
-
response = get(path: '/trade/history-orders', args: args)
|
219
|
-
handle_response(response)
|
220
|
-
end
|
221
|
-
|
222
|
-
def trade_fills(**args)
|
223
|
-
response = get(path: '/trade/fills', args: args)
|
224
|
-
handle_response(response)
|
225
|
-
end
|
226
|
-
|
227
|
-
# Trigger
|
228
|
-
|
229
|
-
# Place Plan Order
|
230
|
-
# POST /api/v2/spot/trade/place-plan-order
|
231
|
-
|
232
|
-
# Modify Plan Order
|
233
|
-
# POST /api/v2/spot/trade/modify-plan-order
|
234
|
-
|
235
|
-
# Cancel Plan Order
|
236
|
-
# POST /api/v2/spot/trade/cancel-plan-order
|
237
|
-
|
238
|
-
# Get Current Plan Orders
|
239
|
-
# GET /api/v2/spot/trade/current-plan-order
|
240
|
-
|
241
|
-
# Get Plan Sub Order
|
242
|
-
# GET /api/v2/spot/trade/plan-sub-order
|
243
|
-
|
244
|
-
# Get History Plan Orders
|
245
|
-
# GET /api/v2/spot/trade/history-plan-order
|
246
|
-
|
247
|
-
# Cancel Plan Orders in Batch
|
248
|
-
# POST /api/v2/spot/trade/batch-cancel-plan-order
|
249
|
-
|
250
|
-
# Account
|
251
|
-
|
252
|
-
# Get Account Information
|
253
|
-
# GET /api/v2/spot/account/info
|
254
|
-
def spot_account_info
|
255
|
-
response = get(path: '/spot/account/info')
|
256
|
-
handle_response(response)
|
257
|
-
end
|
258
|
-
|
259
|
-
# Get Account Assets
|
260
|
-
# GET /api/v2/spot/account/assets
|
261
|
-
def spot_account_assets(**args)
|
262
|
-
response = get(path: '/spot/account/assets', args: args)
|
263
|
-
handle_response(response)
|
264
|
-
end
|
265
|
-
|
266
|
-
# Get Sub-accounts Assets
|
267
|
-
# GET /api/v2/spot/account/subaccount-assets
|
268
|
-
def spot_account_subaccount_assets(**args)
|
269
|
-
response = get(path: '/spot/account/subaccount-assets', args: args)
|
270
|
-
handle_response(response)
|
271
|
-
end
|
272
|
-
|
273
|
-
# Modify Deposit Account
|
274
|
-
# POST /api/v2/spot/wallet/modify-deposit-account
|
275
|
-
def spot_wallet_modify_deposit_account(**args)
|
276
|
-
response = post(path: '/spot/wallet/modify-deposit-account', args: args)
|
277
|
-
handle_response(response)
|
278
|
-
end
|
279
|
-
|
280
|
-
# Get Account Bills
|
281
|
-
# GET /api/v2/spot/account/bills
|
282
|
-
def spot_account_bills(**args)
|
283
|
-
response = get(path: '/spot/account/bills', args: args)
|
284
|
-
handle_response(response)
|
285
|
-
end
|
286
|
-
|
287
|
-
# Transfer
|
288
|
-
# POST /api/v2/spot/wallet/transfer
|
289
|
-
def spot_wallet_transfer(**args)
|
290
|
-
response = post(path: '/spot/wallet/transfer', args: args)
|
291
|
-
handle_response(response)
|
292
|
-
end
|
293
|
-
|
294
|
-
# GET Transferable Coin List
|
295
|
-
# GET /api/v2/spot/wallet/transfer-coin-info
|
296
|
-
def spot_wallet_transfer_coin_info(**args)
|
297
|
-
response = get(path: '/spot/wallet/transfer-coin-info', args: args)
|
298
|
-
handle_response(response)
|
299
|
-
end
|
300
|
-
|
301
|
-
# Sub Transfer
|
302
|
-
# POST /api/v2/spot/wallet/subaccount-transfer
|
303
|
-
def spot_wallet_subaccount_transer(**args)
|
304
|
-
response = post(path: '/spot/wallet/subaccount-transfer', args: args)
|
305
|
-
handle_response(response)
|
306
|
-
end
|
307
|
-
|
308
|
-
# Withdraw
|
309
|
-
# POST /api/v2/spot/wallet/withdrawal
|
310
|
-
def spot_wallet_withdrawal(**args)
|
311
|
-
response = post(path: '/spot/wallet/withdrawal', args: args)
|
312
|
-
handle_response(response)
|
313
|
-
end
|
314
|
-
|
315
|
-
# Get MainSub Transfer Record
|
316
|
-
# GET /api/v2/spot/account/sub-main-trans-record
|
317
|
-
def spot_account_sub_main_trans_record(**args)
|
318
|
-
response = get(path: '/spot/account/sub-main-trans-record', args: args)
|
319
|
-
handle_response(response)
|
320
|
-
end
|
321
|
-
|
322
|
-
# Get Transfer Record
|
323
|
-
# GET /api/v2/spot/account/transferRecords
|
324
|
-
def spot_account_transfer_records(**args)
|
325
|
-
response = get(path: '/spot/account/transferRecords', args: args)
|
326
|
-
handle_response(response)
|
327
|
-
end
|
328
|
-
|
329
|
-
# Switch BGB Deduct
|
330
|
-
# POST /api/v2/spot/account/switch-deduct
|
331
|
-
def spot_account_switch_deduct(deduct:)
|
332
|
-
response = post(path: '/spot/account/switch-deduct', args: {deduct: deduct})
|
333
|
-
handle_response(response)
|
334
|
-
end
|
335
|
-
|
336
|
-
# Get Deposit Address
|
337
|
-
# GET /api/v2/spot/wallet/deposit-address
|
338
|
-
def spot_wallet_deposit_address(**args)
|
339
|
-
response = get(path: '/spot/wallet/deposit-address', args: args)
|
340
|
-
handle_response(response)
|
341
|
-
end
|
342
|
-
|
343
|
-
# Get SubAccount Deposit Address
|
344
|
-
# GET /api/v2/spot/wallet/subaccount-deposit-address
|
345
|
-
def spot_wallet_subaccount_deposit_address(**args)
|
346
|
-
response = get(path: '/spot/wallet/subaccount-deposit-address', args: args)
|
347
|
-
handle_response(response)
|
348
|
-
end
|
349
|
-
|
350
|
-
# Get BGB Deduct Info
|
351
|
-
# GET /api/v2/spot/account/deduct-info
|
352
|
-
def spot_account_deduct_info
|
353
|
-
response = get(path: '/spot/account/deduct-info')
|
354
|
-
handle_response(response)
|
355
|
-
end
|
356
|
-
|
357
|
-
# Cancel Withdrawal
|
358
|
-
# POST /api/v2/spot/wallet/cancel-withdrawal
|
359
|
-
def spot_wallet_cancel_withdrawal(order_id:)
|
360
|
-
response = post(path: '/spot/wallet/cancel-withdrawal', args: {order_id: order_id})
|
361
|
-
handle_response(response)
|
362
|
-
end
|
363
|
-
|
364
|
-
# Get SubAccount Deposit Records
|
365
|
-
# GET /api/v2/spot/wallet/subaccount-deposit-records
|
366
|
-
def spot_wallet_subaccount_deposit_records(**args)
|
367
|
-
response = get(path: '/spot/wallet/subaccount-deposit-records', args: args)
|
368
|
-
handle_response(response)
|
369
|
-
end
|
370
|
-
|
371
|
-
# Get Withdrawal Records
|
372
|
-
# GET /api/v2/spot/wallet/withdrawal-records
|
373
|
-
def spot_wallet_withdrawal_records(**args)
|
374
|
-
response = get(path: '/spot/wallet/withdrawal-records', args: args)
|
375
|
-
handle_response(response)
|
376
|
-
end
|
377
|
-
|
378
|
-
# Get Deposit Records
|
379
|
-
# GET /api/v2/spot/wallet/deposit-records
|
380
|
-
def spot_wallet_deposit_records(**args)
|
381
|
-
response = get(path: '/spot/wallet/deposit-records', args: args)
|
382
|
-
handle_response(response)
|
383
|
-
end
|
384
|
-
|
385
|
-
private
|
386
|
-
|
387
|
-
def initialize(api_key:, api_secret:, api_passphrase:)
|
388
|
-
@api_key = api_key
|
389
|
-
@api_secret = api_secret
|
390
|
-
@api_passphrase = api_passphrase
|
391
|
-
end
|
392
|
-
|
393
|
-
def initialize(api_key:, api_secret:, api_passphrase:)
|
394
|
-
@api_key = api_key.encode('UTF-8')
|
395
|
-
@api_secret = api_secret.encode('UTF-8')
|
396
|
-
@api_passphrase = api_passphrase.encode('UTF-8')
|
397
|
-
end
|
398
|
-
|
399
|
-
def full_path(path)
|
400
|
-
self.class.path_prefix + path
|
401
|
-
end
|
402
|
-
|
403
|
-
def encoded_payload(args)
|
404
|
-
args.reject!{|k,v| v.nil?}
|
405
|
-
OpenSSL::Digest::SHA512.hexdigest(JSON.dump(args))
|
406
|
-
end
|
407
|
-
|
408
|
-
def timestamp
|
409
|
-
@timestamp ||= (Time.now.to_f * 1000).to_i.to_s
|
410
|
-
end
|
411
|
-
|
412
|
-
def message(verb:, path:, args:)
|
413
|
-
case verb
|
414
|
-
when 'GET'
|
415
|
-
if args.empty?
|
416
|
-
[timestamp, verb, full_path(path)].join
|
417
|
-
else
|
418
|
-
query_string = args.to_parameter_string
|
419
|
-
[timestamp, verb, full_path(path), '?', query_string].join
|
420
|
-
end
|
421
|
-
when 'POST'
|
422
|
-
body = args.to_json
|
423
|
-
[timestamp, verb, full_path(path), body].join
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
def signature(message)
|
428
|
-
digest = OpenSSL::Digest.new('SHA256')
|
429
|
-
hmac = OpenSSL::HMAC.digest(digest, @api_secret, message)
|
430
|
-
Base64.strict_encode64(hmac)
|
431
|
-
end
|
432
|
-
|
433
|
-
def request_string(path)
|
434
|
-
"https://#{API_HOST}#{self.class.path_prefix}#{path}"
|
435
|
-
end
|
436
|
-
|
437
|
-
def headers(signature)
|
438
|
-
{
|
439
|
-
'ACCESS-KEY' => @api_key,
|
440
|
-
'ACCESS-SIGN' => signature,
|
441
|
-
'ACCESS-TIMESTAMP' => timestamp,
|
442
|
-
'ACCESS-PASSPHRASE' => @api_passphrase,
|
443
|
-
'Content-Type' => 'application/json',
|
444
|
-
'X-CHANNEL-API-CODE' => 'spot',
|
445
|
-
}
|
446
|
-
end
|
447
|
-
|
448
|
-
def log_args?(args)
|
449
|
-
!args.values.all?(&:nil?)
|
450
|
-
end
|
451
|
-
|
452
|
-
def log_request(verb:, request_string:, args:)
|
453
|
-
log_string = "#{verb} #{request_string}"
|
454
|
-
if log_args?(args)
|
455
|
-
log_string << "?#{args.x_www_form_urlencode}"
|
456
|
-
end
|
457
|
-
self.class.logger.info(log_string)
|
458
|
-
end
|
459
|
-
|
460
|
-
def log_error(code:, message:, body:)
|
461
|
-
log_string = "#{code}\n#{message}\n#{body}"
|
462
|
-
self.class.logger.error(log_string)
|
463
|
-
end
|
464
|
-
|
465
|
-
def do_request(verb:, path:, args: {})
|
466
|
-
log_request(verb: verb, request_string: request_string(path), args: args)
|
467
|
-
message = message(verb: verb, path: path, args: args)
|
468
|
-
signature = signature(message)
|
469
|
-
headers = headers(signature)
|
470
|
-
@timestamp = nil
|
471
|
-
HTTP.send(verb.to_s.downcase, request_string(path), args, headers)
|
472
|
-
end
|
473
|
-
|
474
|
-
def get(path:, args: {})
|
475
|
-
do_request(verb: 'GET', path: path, args: args)
|
476
|
-
end
|
477
|
-
|
478
|
-
def post(path:, args: {})
|
479
|
-
do_request(verb: 'POST', path: path, args: args)
|
480
|
-
end
|
481
|
-
|
482
|
-
def handle_response(response)
|
483
|
-
if response.success?
|
484
|
-
JSON.parse(response.body)
|
485
|
-
else
|
486
|
-
log_error(
|
487
|
-
code: response.code,
|
488
|
-
message: response.message,
|
489
|
-
body: response.body
|
490
|
-
)
|
491
|
-
raise Bitget::Error.new(
|
492
|
-
code: response.code,
|
493
|
-
message: response.message,
|
494
|
-
body: response.body
|
495
|
-
)
|
496
|
-
end
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# Hash#to_parameter_string
|
2
|
-
|
3
|
-
# 20120610
|
4
|
-
# 1.0.2
|
5
|
-
|
6
|
-
# Changes since 0:
|
7
|
-
# 1. I changed it from a class method to an instance method and hence removed references to any arguments and substituted self for those arguments.
|
8
|
-
# 0/1
|
9
|
-
# 2. I forget about needing String#url_encode, which for now I'll paste in here.
|
10
|
-
# 1/2
|
11
|
-
# 3. - String#url_encode.
|
12
|
-
# 4. + require 'String/url_encode'.
|
13
|
-
|
14
|
-
require 'String/url_encode'
|
15
|
-
|
16
|
-
class Hash
|
17
|
-
|
18
|
-
def to_parameter_string
|
19
|
-
parameters_string_parts = []
|
20
|
-
self.each do |k,v|
|
21
|
-
parameters_string_parts << (k.to_s + '=' + v.url_encode) unless v.nil?
|
22
|
-
end
|
23
|
-
parameters_string_parts.join('&')
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|