bitget.rb 0.3.1 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d2751725e270a3466b6fb00e665fefcc824fad5817f45f6805e4f2abe4ce4ed
4
- data.tar.gz: 69e156c08596016abae4b32252da43a687f487740f0a347a0c6dc605e295da5b
3
+ metadata.gz: a9a76dd0384385ec874d2689053e2a9af7ed9cc4167e9980691bcca9b4855005
4
+ data.tar.gz: 5d1f16940c82a9f072360fbecb5941be0df52d3161dab7db217814b5a5a2b00e
5
5
  SHA512:
6
- metadata.gz: 56798524a003cfa167d2993dcfc59fb2fc76788e6260495577c677ed00faeebab1f1f48495a1d1fd1064ff909f2b79867a618fa9179a7441f8ce8dc000989f8c
7
- data.tar.gz: 4108e6fbc9dc198054605cefd79d51ca9cd02fdb3fe3f96c43b29e4f67c399bffe481fbe4bbee6aaeff87a05ccf94461f91da14e894a286b33f06503dfdd3ec7
6
+ metadata.gz: 975b7a27c4ab2834dbcdd907b65d0fe66b17bb7d8a8c2fddee5d4cc6d3f4f2431afd670beee84312d5ff828e7d88a1dcdabb20fa1cb1a32a72a55f8da809c2b5
7
+ data.tar.gz: 3f030a15eaf44fd3ccba97ea216a11da4f377135c9c49127b5dbe713d4227357512950ec6ffa4e521bd2d73fed4df903b9a574cf7ea92054110eb2a366f08857
data/README.md CHANGED
@@ -23,7 +23,7 @@ Or install it yourself as:
23
23
 
24
24
  ### Setup
25
25
  ```ruby
26
- bitget_client ||= Bitget::Client.new(
26
+ bitget_client = Bitget::Client.new(
27
27
  api_key: 'api_key0',
28
28
  api_secret: 'api_secret0',
29
29
  api_passphrase: 'api_passphrase0'
@@ -97,9 +97,24 @@ bitget_client.spot_public_coins(coin: 'BTC')
97
97
  # }
98
98
  ```
99
99
 
100
+ ### Get Account Information
101
+ ```ruby
102
+ bitget_client.spot_account_info
103
+ ```
104
+
105
+ ### Get Account Assets
106
+ ```ruby
107
+ bitget_client.spot_account_assets
108
+ ```
109
+ ```ruby
110
+ bitget_client.spot_account_assets(coin: 'BTC')
111
+ ```
112
+
113
+ See https://www.bitget.com/api-doc/spot/intro for further information on endpoint arguments
114
+
100
115
  ## Contributing
101
116
 
102
- 1. Fork it ( https://github.com/thoran/bitget.rb/fork )
117
+ 1. Fork it (https://github.com/thoran/bitget.rb/fork)
103
118
  2. Create your feature branch (`git checkout -b my-new-feature`)
104
119
  3. Commit your changes (`git commit -am 'Add some feature'`)
105
120
  4. Push to the branch (`git push origin my-new-feature`)
data/bitget.rb.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
4
4
  spec.name = 'bitget.rb'
5
5
 
6
6
  spec.version = Bitget::VERSION
7
- spec.date = '2025-04-02'
7
+ spec.date = '2025-05-16'
8
8
 
9
9
  spec.summary = "Access the Bitget API with Ruby."
10
10
  spec.description = "Access the Bitget API with Ruby."
@@ -42,22 +42,33 @@ module Bitget
42
42
  end
43
43
  end # class << self
44
44
 
45
+ # Get Coin Info
46
+ # GET /api/v2/spot
45
47
  def spot_public_coins(coin: nil)
46
- response = get(
47
- path: '/spot/public/coins',
48
- args: {
49
- coin: coin
50
- }
51
- )
48
+ response = get(path: '/spot/public/coins', args: {coin: coin})
49
+ handle_response(response)
50
+ end
51
+
52
+ # Get Account Information
53
+ # GET /api/v2/spot/account/info
54
+ def spot_account_info
55
+ response = get(path: '/spot/account/info')
56
+ handle_response(response)
57
+ end
58
+
59
+ # Get Account Assets
60
+ # GET /api/v2/spot/account/assets
61
+ def spot_account_assets(**args)
62
+ response = get(path: '/spot/account/assets', args: args)
52
63
  handle_response(response)
53
64
  end
54
65
 
55
66
  private
56
67
 
57
68
  def initialize(api_key:, api_secret:, api_passphrase:)
58
- @api_key = api_key.encode('UTF-8')
59
- @api_secret = api_secret.encode('UTF-8')
60
- @api_passphrase = api_passphrase.encode('UTF-8')
69
+ @api_key = api_key
70
+ @api_secret = api_secret
71
+ @api_passphrase = api_passphrase
61
72
  end
62
73
 
63
74
  def full_path(path)
@@ -70,30 +81,28 @@ module Bitget
70
81
  end
71
82
 
72
83
  def timestamp
73
- @timestamp ||= Time.now.to_i.to_s
84
+ @timestamp ||= (Time.now.to_f * 1000).to_i.to_s
74
85
  end
75
86
 
76
87
  def message(verb:, path:, args:)
77
- query_string = (
78
- case verb
79
- when 'GET'
80
- args.to_parameter_string
81
- when 'POST'
82
- nil
88
+ case verb
89
+ when 'GET'
90
+ if args.empty?
91
+ [timestamp, verb, full_path(path)].join
83
92
  else
84
- raise "The verb, #{verb}, is not acceptable."
93
+ query_string = args.to_parameter_string
94
+ [timestamp, verb, full_path(path), '?', query_string].join
85
95
  end
86
- )
87
- body = JSON.dump(args)
88
- if query_string.nil?
96
+ when 'POST'
97
+ body = args.to_json
89
98
  [timestamp, verb, full_path(path), body].join
90
- else
91
- [timestamp, verb, full_path(path), '?', query_string, body].join
92
99
  end
93
100
  end
94
101
 
95
102
  def signature(message)
96
- OpenSSL::HMAC.hexdigest('SHA512', @api_secret, message)
103
+ digest = OpenSSL::Digest.new('SHA256')
104
+ hmac = OpenSSL::HMAC.digest(digest, @api_secret, message)
105
+ Base64.strict_encode64(hmac)
97
106
  end
98
107
 
99
108
  def request_string(path)
@@ -106,9 +115,8 @@ module Bitget
106
115
  'ACCESS-SIGN' => signature,
107
116
  'ACCESS-TIMESTAMP' => timestamp,
108
117
  'ACCESS-PASSPHRASE' => @api_passphrase,
109
- 'Content-type' => 'application/json',
110
- 'locale' =>'en-AU',
111
- 'Accept' => 'application/json',
118
+ 'Content-Type' => 'application/json',
119
+ 'X-CHANNEL-API-CODE' => 'spot',
112
120
  }
113
121
  end
114
122
 
@@ -133,7 +141,9 @@ module Bitget
133
141
  log_request(verb: verb, request_string: request_string(path), args: args)
134
142
  message = message(verb: verb, path: path, args: args)
135
143
  signature = signature(message)
136
- HTTP.send(verb.to_s.downcase, request_string(path), args, headers(signature))
144
+ headers = headers(signature)
145
+ @timestamp = nil
146
+ HTTP.send(verb.to_s.downcase, request_string(path), args, headers)
137
147
  end
138
148
 
139
149
  def get(path:, args: {})
@@ -0,0 +1,500 @@
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
@@ -2,5 +2,5 @@
2
2
  # Bitget::VERSION
3
3
 
4
4
  module Bitget
5
- VERSION = '0.3.1'
5
+ VERSION = '0.4.0'
6
6
  end
data/lib/bitget.rb CHANGED
@@ -1,8 +1,4 @@
1
1
  # bitget.rb
2
- # Bitget
3
-
4
- # 20250326
5
- # 0.1.1
6
2
 
7
3
  lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
8
4
  $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
@@ -4,9 +4,9 @@ require_relative '../../lib/Bitget/V2/Client'
4
4
  describe Bitget::V2::Client do
5
5
  let(:client) do
6
6
  Bitget::V2::Client.new(
7
- api_key: api_key,
8
- api_secret: api_secret,
9
- api_passphrase: api_passphrase
7
+ api_key: ENV.fetch('BITGET_API_KEY', '<API_KEY>'),
8
+ api_secret: ENV.fetch('BITGET_API_SECRET', '<API_SECRET>'),
9
+ api_passphrase: ENV.fetch('BITGET_API_PASSPHRASE', '<API_PASSPHRASE>')
10
10
  )
11
11
  end
12
12
 
@@ -50,4 +50,60 @@ describe Bitget::V2::Client do
50
50
  end
51
51
  end
52
52
  end
53
+
54
+ describe "#spot_account_info" do
55
+ it "retrieves account information" do
56
+ VCR.use_cassette('v2/spot/account/info') do
57
+ response = client.spot_account_info
58
+ _(response).must_include('data')
59
+ _(response['data']).must_include('userId')
60
+ _(response['data']).must_include('channelCode')
61
+ _(response['data']).must_include('authorities')
62
+ end
63
+ end
64
+
65
+ context "when an error occurs" do
66
+ it "logs then raises an error" do
67
+ VCR.use_cassette('v2/spot/account/info-when_an_error_occurs') do
68
+ assert_raises(Bitget::Error) do
69
+ mocked_method = Minitest::Mock.new
70
+ mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
71
+ client.stub(:log_error, mocked_method) do
72
+ client.spot_account_info
73
+ end
74
+ mocked_method.verify
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#spot_account_assets" do
82
+ it "retrieves account assets" do
83
+ VCR.use_cassette('v2/spot/account/assets') do
84
+ response = client.spot_account_assets
85
+ _(response).must_include('data')
86
+ _(response['data'].first).must_include('coin')
87
+ _(response['data'].first).must_include('available')
88
+ _(response['data'].first).must_include('frozen')
89
+ _(response['data'].first).must_include('locked')
90
+ _(response['data'].first).must_include('uTime')
91
+ end
92
+ end
93
+
94
+ context "when an error occurs" do
95
+ it "logs then raises an error" do
96
+ VCR.use_cassette('v2/spot/account/assets-when_an_error_occurs') do
97
+ assert_raises(Bitget::Error) do
98
+ mocked_method = Minitest::Mock.new
99
+ mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
100
+ client.stub(:log_error, mocked_method) do
101
+ client.spot_account_assets
102
+ end
103
+ mocked_method.verify
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
53
109
  end
data/test/client_test.rb CHANGED
@@ -4,9 +4,9 @@ require_relative '../lib/Bitget/Client'
4
4
  describe Bitget::Client do
5
5
  let(:client) do
6
6
  Bitget::Client.new(
7
- api_key: api_key,
8
- api_secret: api_secret,
9
- api_passphrase: api_passphrase
7
+ api_key: ENV.fetch('BITGET_API_KEY', '<API_KEY>'),
8
+ api_secret: ENV.fetch('BITGET_API_SECRET', '<API_SECRET>'),
9
+ api_passphrase: ENV.fetch('BITGET_API_PASSPHRASE', '<API_PASSPHRASE>')
10
10
  )
11
11
  end
12
12
 
@@ -50,4 +50,60 @@ describe Bitget::Client do
50
50
  end
51
51
  end
52
52
  end
53
+
54
+ describe "#spot_account_info" do
55
+ it "retrieves account information" do
56
+ VCR.use_cassette('v2/spot/account/info') do
57
+ response = client.spot_account_info
58
+ _(response).must_include('data')
59
+ _(response['data']).must_include('userId')
60
+ _(response['data']).must_include('channelCode')
61
+ _(response['data']).must_include('authorities')
62
+ end
63
+ end
64
+
65
+ context "when an error occurs" do
66
+ it "logs then raises an error" do
67
+ VCR.use_cassette('v2/spot/account/info-when_an_error_occurs') do
68
+ assert_raises(Bitget::Error) do
69
+ mocked_method = Minitest::Mock.new
70
+ mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
71
+ client.stub(:log_error, mocked_method) do
72
+ client.spot_account_info
73
+ end
74
+ mocked_method.verify
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#spot_account_assets" do
82
+ it "retrieves account assets" do
83
+ VCR.use_cassette('v2/spot/account/assets') do
84
+ response = client.spot_account_assets
85
+ _(response).must_include('data')
86
+ _(response['data'].first).must_include('coin')
87
+ _(response['data'].first).must_include('available')
88
+ _(response['data'].first).must_include('frozen')
89
+ _(response['data'].first).must_include('locked')
90
+ _(response['data'].first).must_include('uTime')
91
+ end
92
+ end
93
+
94
+ context "when an error occurs" do
95
+ it "logs then raises an error" do
96
+ VCR.use_cassette('v2/spot/account/assets-when_an_error_occurs') do
97
+ assert_raises(Bitget::Error) do
98
+ mocked_method = Minitest::Mock.new
99
+ mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
100
+ client.stub(:log_error, mocked_method) do
101
+ client.spot_account_assets
102
+ end
103
+ mocked_method.verify
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
53
109
  end
data/test/helper.rb CHANGED
@@ -1,34 +1,13 @@
1
1
  require 'minitest/autorun'
2
2
  require 'minitest-spec-context'
3
3
  require 'minitest/spec'
4
- require 'ostruct'
5
4
  require 'vcr'
6
5
 
7
6
  VCR.configure do |config|
8
7
  config.cassette_library_dir = File.expand_path('../fixtures/vcr_cassettes', __FILE__)
9
8
  config.hook_into :webmock
10
- end
11
-
12
- def api_key
13
- if ENV['BITGET_API_KEY']
14
- ENV['BITGET_API_KEY']
15
- else
16
- 'api_key0'
17
- end
18
- end
19
-
20
- def api_secret
21
- if ENV['BITGET_API_SECRET']
22
- ENV['BITGET_API_SECRET']
23
- else
24
- 'api_secret0'
25
- end
26
- end
27
9
 
28
- def api_passphrase
29
- if ENV['BITGET_API_PASSPHRASE']
30
- ENV['BITGET_API_PASSPHRASE']
31
- else
32
- 'api_passphrase0'
33
- end
10
+ config.filter_sensitive_data('<API_KEY>'){ENV['BITGET_API_KEY']}
11
+ config.filter_sensitive_data('<API_SECRET>'){ENV['BITGET_API_SECRET'] }
12
+ config.filter_sensitive_data('<API_PASSPHRASE>'){ENV['BITGET_API_PASSPHRASE']}
34
13
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitget.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-02 00:00:00.000000000 Z
10
+ date: 2025-05-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: http.rb
@@ -35,7 +35,8 @@ files:
35
35
  - lib/Bitget/Client.rb
36
36
  - lib/Bitget/Error.rb
37
37
  - lib/Bitget/V2/Client.rb
38
- - lib/Bitget/VERSiON.rb
38
+ - lib/Bitget/V2/Client2.rb
39
+ - lib/Bitget/VERSION.rb
39
40
  - lib/Hash/to_parameter_string.rb
40
41
  - lib/Hash/x_www_form_urlencode.rb
41
42
  - lib/String/url_encode.rb
@@ -64,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
65
  - !ruby/object:Gem::Version
65
66
  version: '0'
66
67
  requirements: []
67
- rubygems_version: 3.6.6
68
+ rubygems_version: 3.6.8
68
69
  specification_version: 4
69
70
  summary: Access the Bitget API with Ruby.
70
71
  test_files: []