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 +4 -4
- data/README.md +17 -2
- data/bitget.rb.gemspec +1 -1
- data/lib/Bitget/V2/Client.rb +37 -27
- data/lib/Bitget/V2/Client2.rb +500 -0
- data/lib/Bitget/{VERSiON.rb → VERSION.rb} +1 -1
- data/lib/bitget.rb +0 -4
- data/test/V2/client_test.rb +59 -3
- data/test/client_test.rb +59 -3
- data/test/helper.rb +3 -24
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9a76dd0384385ec874d2689053e2a9af7ed9cc4167e9980691bcca9b4855005
|
4
|
+
data.tar.gz: 5d1f16940c82a9f072360fbecb5941be0df52d3161dab7db217814b5a5a2b00e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 (
|
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
data/lib/Bitget/V2/Client.rb
CHANGED
@@ -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
|
-
|
48
|
-
|
49
|
-
|
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
|
59
|
-
@api_secret = api_secret
|
60
|
-
@api_passphrase = api_passphrase
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
93
|
+
query_string = args.to_parameter_string
|
94
|
+
[timestamp, verb, full_path(path), '?', query_string].join
|
85
95
|
end
|
86
|
-
|
87
|
-
|
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::
|
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-
|
110
|
-
'
|
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
|
-
|
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
|
data/lib/bitget.rb
CHANGED
data/test/V2/client_test.rb
CHANGED
@@ -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:
|
8
|
-
api_secret:
|
9
|
-
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:
|
8
|
-
api_secret:
|
9
|
-
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
|
-
|
29
|
-
|
30
|
-
|
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.
|
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-
|
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/
|
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.
|
68
|
+
rubygems_version: 3.6.8
|
68
69
|
specification_version: 4
|
69
70
|
summary: Access the Bitget API with Ruby.
|
70
71
|
test_files: []
|