honeymaker 0.1.0 → 0.3.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -0
  3. data/lib/honeymaker/client.rb +96 -0
  4. data/lib/honeymaker/clients/binance.rb +288 -0
  5. data/lib/honeymaker/clients/binance_us.rb +9 -0
  6. data/lib/honeymaker/clients/bingx.rb +136 -0
  7. data/lib/honeymaker/clients/bitget.rb +157 -0
  8. data/lib/honeymaker/clients/bitmart.rb +146 -0
  9. data/lib/honeymaker/clients/bitrue.rb +130 -0
  10. data/lib/honeymaker/clients/bitvavo.rb +160 -0
  11. data/lib/honeymaker/clients/bybit.rb +166 -0
  12. data/lib/honeymaker/clients/coinbase.rb +219 -0
  13. data/lib/honeymaker/clients/gemini.rb +99 -0
  14. data/lib/honeymaker/clients/hyperliquid.rb +65 -0
  15. data/lib/honeymaker/clients/kraken.rb +162 -0
  16. data/lib/honeymaker/clients/kucoin.rb +180 -0
  17. data/lib/honeymaker/clients/mexc.rb +166 -0
  18. data/lib/honeymaker/exchanges/binance.rb +11 -17
  19. data/lib/honeymaker/exchanges/bitget.rb +2 -2
  20. data/lib/honeymaker/exchanges/bitrue.rb +6 -16
  21. data/lib/honeymaker/exchanges/bitvavo.rb +2 -2
  22. data/lib/honeymaker/exchanges/bybit.rb +2 -2
  23. data/lib/honeymaker/exchanges/coinbase.rb +5 -9
  24. data/lib/honeymaker/exchanges/gemini.rb +4 -6
  25. data/lib/honeymaker/exchanges/kraken.rb +5 -9
  26. data/lib/honeymaker/exchanges/kucoin.rb +2 -2
  27. data/lib/honeymaker/exchanges/mexc.rb +11 -17
  28. data/lib/honeymaker/utils.rb +9 -0
  29. data/lib/honeymaker/version.rb +1 -1
  30. data/lib/honeymaker.rb +38 -0
  31. data/test/fixtures/bingx_symbols.json +26 -0
  32. data/test/fixtures/bitget_symbols.json +28 -0
  33. data/test/fixtures/bitmart_symbols.json +26 -0
  34. data/test/fixtures/bitrue_exchange_info.json +34 -0
  35. data/test/fixtures/bitvavo_markets.json +16 -0
  36. data/test/fixtures/bybit_instruments.json +23 -0
  37. data/test/fixtures/coinbase_products.json +24 -0
  38. data/test/fixtures/gemini_symbol_detail.json +9 -0
  39. data/test/fixtures/gemini_symbols.json +1 -0
  40. data/test/fixtures/hyperliquid_spot_meta.json +12 -0
  41. data/test/fixtures/kucoin_symbols.json +17 -0
  42. data/test/fixtures/mexc_exchange_info.json +40 -0
  43. data/test/honeymaker/client_test.rb +53 -0
  44. data/test/honeymaker/clients/binance_client_test.rb +101 -0
  45. data/test/honeymaker/clients/binance_us_client_test.rb +25 -0
  46. data/test/honeymaker/clients/bingx_client_test.rb +82 -0
  47. data/test/honeymaker/clients/bitget_client_test.rb +109 -0
  48. data/test/honeymaker/clients/bitmart_client_test.rb +96 -0
  49. data/test/honeymaker/clients/bitrue_client_test.rb +69 -0
  50. data/test/honeymaker/clients/bitvavo_client_test.rb +105 -0
  51. data/test/honeymaker/clients/bybit_client_test.rb +102 -0
  52. data/test/honeymaker/clients/coinbase_client_test.rb +132 -0
  53. data/test/honeymaker/clients/gemini_client_test.rb +83 -0
  54. data/test/honeymaker/clients/honeymaker_client_registry_test.rb +44 -0
  55. data/test/honeymaker/clients/hyperliquid_client_test.rb +65 -0
  56. data/test/honeymaker/clients/kraken_client_test.rb +84 -0
  57. data/test/honeymaker/clients/kucoin_client_test.rb +106 -0
  58. data/test/honeymaker/clients/mexc_client_test.rb +93 -0
  59. data/test/honeymaker/clients/validation_test.rb +182 -0
  60. data/test/honeymaker/exchanges/binance_us_test.rb +40 -0
  61. data/test/honeymaker/exchanges/bingx_test.rb +53 -0
  62. data/test/honeymaker/exchanges/bitget_test.rb +52 -0
  63. data/test/honeymaker/exchanges/bitmart_test.rb +52 -0
  64. data/test/honeymaker/exchanges/bitrue_test.rb +53 -0
  65. data/test/honeymaker/exchanges/bitvavo_test.rb +52 -0
  66. data/test/honeymaker/exchanges/bybit_test.rb +43 -0
  67. data/test/honeymaker/exchanges/coinbase_test.rb +52 -0
  68. data/test/honeymaker/exchanges/gemini_test.rb +48 -0
  69. data/test/honeymaker/exchanges/hyperliquid_test.rb +52 -0
  70. data/test/honeymaker/exchanges/kucoin_test.rb +43 -0
  71. data/test/honeymaker/exchanges/mexc_test.rb +64 -0
  72. data/test/honeymaker/utils_test.rb +38 -0
  73. data/test/test_helper.rb +1 -0
  74. metadata +74 -3
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "uri"
5
+
6
+ module Honeymaker
7
+ module Clients
8
+ class Kraken < Client
9
+ URL = "https://api.kraken.com"
10
+
11
+ def query_orders_info(txid:, trades: nil, userref: nil, consolidate_taker: true)
12
+ post_private("/0/private/QueryOrders", {
13
+ nonce: nonce, trades: trades, userref: userref,
14
+ txid: txid, consolidate_taker: consolidate_taker
15
+ })
16
+ end
17
+
18
+ def add_order(ordertype:, type:, volume:, pair:, userref: nil, cl_ord_id: nil,
19
+ displayvol: nil, price: nil, price2: nil, trigger: nil, leverage: nil,
20
+ reduce_only: nil, stptype: nil, oflags: [], timeinforce: nil,
21
+ starttm: nil, expiretm: nil, close: nil, close_price: nil,
22
+ close_price2: nil, deadline: nil, validate: nil)
23
+ post_private("/0/private/AddOrder", {
24
+ "nonce" => nonce, "ordertype" => ordertype, "type" => type,
25
+ "volume" => volume, "pair" => pair, "userref" => userref,
26
+ "cl_ord_id" => cl_ord_id, "displayvol" => displayvol,
27
+ "price" => price, "price2" => price2, "trigger" => trigger,
28
+ "leverage" => leverage, "reduce_only" => reduce_only,
29
+ "stptype" => stptype,
30
+ "oflags" => oflags.any? ? oflags.join(",") : nil,
31
+ "timeinforce" => timeinforce, "starttm" => starttm,
32
+ "expiretm" => expiretm, "close[ordertype]" => close,
33
+ "close[price]" => close_price, "close[price2]" => close_price2,
34
+ "deadline" => deadline, "validate" => validate
35
+ })
36
+ end
37
+
38
+ def cancel_order(txid: nil, cl_ord_id: nil)
39
+ post_private("/0/private/CancelOrder", { nonce: nonce, txid: txid, cl_ord_id: cl_ord_id })
40
+ end
41
+
42
+ def get_tradable_asset_pairs(pairs: nil, info: nil, country_code: nil)
43
+ get_public("/0/public/AssetPairs", {
44
+ pair: pairs ? pairs.join(",") : nil, info: info, country_code: country_code
45
+ })
46
+ end
47
+
48
+ def get_asset_info(assets: nil, aclass: nil)
49
+ get_public("/0/public/Assets", { asset: assets ? assets.join(",") : nil, aclass: aclass })
50
+ end
51
+
52
+ def get_ticker_information(pair: nil)
53
+ get_public("/0/public/Ticker", { pair: pair })
54
+ end
55
+
56
+ def get_extended_balance
57
+ post_private("/0/private/BalanceEx", { nonce: nonce })
58
+ end
59
+
60
+ def get_ohlc_data(pair:, interval: nil, since: nil)
61
+ get_public("/0/public/OHLC", { pair: pair, interval: interval, since: since })
62
+ end
63
+
64
+ def get_trades_history(type: nil, trades: nil, start: nil, end_time: nil, ofs: nil)
65
+ post_private("/0/private/TradesHistory", {
66
+ nonce: nonce, type: type, trades: trades,
67
+ start: start, end: end_time, ofs: ofs
68
+ })
69
+ end
70
+
71
+ def get_ledgers(asset: nil, type: nil, start: nil, end_time: nil, ofs: nil)
72
+ post_private("/0/private/Ledgers", {
73
+ nonce: nonce, asset: asset, type: type,
74
+ start: start, end: end_time, ofs: ofs
75
+ })
76
+ end
77
+
78
+ def get_withdraw_addresses(asset: nil, method: nil)
79
+ post_private("/0/private/WithdrawAddresses", { nonce: nonce, asset: asset, method: method })
80
+ end
81
+
82
+ def get_withdraw_methods(asset: nil)
83
+ post_private("/0/private/WithdrawMethods", { nonce: nonce, asset: asset })
84
+ end
85
+
86
+ def withdraw(asset:, key:, amount:, address: nil)
87
+ post_private("/0/private/Withdraw", { nonce: nonce, asset: asset, key: key, amount: amount, address: address })
88
+ end
89
+
90
+ private
91
+
92
+ def validate_trading_credentials
93
+ result = get_extended_balance
94
+ return Result::Failure.new("Invalid trading credentials") if result.failure?
95
+
96
+ errors = result.data["error"]
97
+ if errors.is_a?(Array) && errors.none?
98
+ Result::Success.new(true)
99
+ else
100
+ Result::Failure.new("Invalid trading credentials")
101
+ end
102
+ end
103
+
104
+ def validate_read_credentials
105
+ validate_trading_credentials
106
+ end
107
+
108
+ def get_public(path, params = {})
109
+ with_rescue do
110
+ response = connection.get do |req|
111
+ req.url path
112
+ req.headers = public_headers
113
+ req.params = params.compact
114
+ end
115
+ response.body
116
+ end
117
+ end
118
+
119
+ def post_private(path, body = {})
120
+ with_rescue do
121
+ response = connection.post do |req|
122
+ req.url path
123
+ req.body = URI.encode_www_form(body.compact)
124
+ req.headers = private_headers(req.path, req.body)
125
+ end
126
+ response.body
127
+ end
128
+ end
129
+
130
+ def nonce
131
+ (Time.now.utc.to_f * 1_000_000).to_i
132
+ end
133
+
134
+ def private_headers(path, body)
135
+ return public_headers unless authenticated?
136
+
137
+ request_nonce = URI.decode_www_form(body).to_h["nonce"]
138
+ data = "#{request_nonce}#{body}"
139
+ message = path + Digest::SHA256.digest(data)
140
+ decoded_key = Base64.decode64(@api_secret)
141
+ begin
142
+ hmac = OpenSSL::HMAC.digest("sha512", decoded_key, message)
143
+ rescue OpenSSL::HMACError
144
+ return public_headers
145
+ end
146
+ signature = Base64.strict_encode64(hmac)
147
+
148
+ {
149
+ "API-Key": @api_key,
150
+ "API-Sign": signature,
151
+ Accept: "application/json",
152
+ "Content-Type": "application/x-www-form-urlencoded",
153
+ "User-Agent": "Honeymaker Ruby"
154
+ }
155
+ end
156
+
157
+ def public_headers
158
+ { Accept: "application/json", "Content-Type": "application/json", "User-Agent": "Honeymaker Ruby" }
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Honeymaker
4
+ module Clients
5
+ class Kucoin < Client
6
+ URL = "https://api.kucoin.com"
7
+
8
+ attr_reader :passphrase
9
+
10
+ def initialize(api_key: nil, api_secret: nil, passphrase: nil, proxy: nil, logger: nil)
11
+ super(api_key: api_key, api_secret: api_secret, proxy: proxy, logger: logger)
12
+ @passphrase = passphrase
13
+ end
14
+
15
+ def get_symbols
16
+ get_public("/api/v2/symbols")
17
+ end
18
+
19
+ def get_ticker(symbol:)
20
+ get_public("/api/v1/market/orderbook/level1", { symbol: symbol })
21
+ end
22
+
23
+ def get_all_tickers
24
+ get_public("/api/v1/market/allTickers")
25
+ end
26
+
27
+ def get_klines(symbol:, type:, start_at: nil, end_at: nil)
28
+ get_public("/api/v1/market/candles", {
29
+ symbol: symbol, type: type, startAt: start_at, endAt: end_at
30
+ })
31
+ end
32
+
33
+ def get_accounts(currency: nil, type: nil)
34
+ get_signed("/api/v1/accounts", { currency: currency, type: type })
35
+ end
36
+
37
+ def place_order(client_oid:, side:, symbol:, type:, size: nil, funds: nil, price: nil,
38
+ time_in_force: nil, stp: nil)
39
+ post_signed("/api/v1/orders", {
40
+ clientOid: client_oid, side: side, symbol: symbol, type: type,
41
+ size: size, funds: funds, price: price,
42
+ timeInForce: time_in_force, stp: stp
43
+ })
44
+ end
45
+
46
+ def get_order(order_id:)
47
+ get_signed("/api/v1/orders/#{order_id}")
48
+ end
49
+
50
+ def cancel_order(order_id:)
51
+ delete_signed("/api/v1/orders/#{order_id}")
52
+ end
53
+
54
+ def get_currencies
55
+ get_public("/api/v3/currencies")
56
+ end
57
+
58
+ def get_withdrawal_quotas(currency:, chain: nil)
59
+ get_signed("/api/v1/withdrawals/quotas", { currency: currency, chain: chain })
60
+ end
61
+
62
+ def get_fills(order_id: nil, symbol: nil, side: nil, type: nil, start_at: nil, end_at: nil,
63
+ trade_type: nil, limit: nil, current_page: nil)
64
+ get_signed("/api/v1/fills", {
65
+ orderId: order_id, symbol: symbol, side: side, type: type,
66
+ startAt: start_at, endAt: end_at, tradeType: trade_type,
67
+ pageSize: limit, currentPage: current_page
68
+ })
69
+ end
70
+
71
+ def get_deposits(currency: nil, start_at: nil, end_at: nil, status: nil, current_page: nil, page_size: nil)
72
+ get_signed("/api/v1/deposits", {
73
+ currency: currency, startAt: start_at, endAt: end_at,
74
+ status: status, currentPage: current_page, pageSize: page_size
75
+ })
76
+ end
77
+
78
+ def get_withdrawals(currency: nil, start_at: nil, end_at: nil, status: nil, current_page: nil, page_size: nil)
79
+ get_signed("/api/v1/withdrawals", {
80
+ currency: currency, startAt: start_at, endAt: end_at,
81
+ status: status, currentPage: current_page, pageSize: page_size
82
+ })
83
+ end
84
+
85
+ def withdraw(currency:, address:, amount:, chain: nil, memo: nil)
86
+ post_signed("/api/v1/withdrawals", {
87
+ currency: currency, address: address, amount: amount,
88
+ chain: chain, memo: memo
89
+ })
90
+ end
91
+
92
+ private
93
+
94
+ def validate_trading_credentials
95
+ result = get_accounts(type: "trade")
96
+ return Result::Failure.new("Invalid trading credentials") if result.failure?
97
+ result.data["code"] == "200000" ? Result::Success.new(true) : Result::Failure.new("Invalid trading credentials")
98
+ end
99
+
100
+ def validate_read_credentials
101
+ validate_trading_credentials
102
+ end
103
+
104
+ def get_public(path, params = {})
105
+ with_rescue do
106
+ response = connection.get do |req|
107
+ req.url path
108
+ req.headers = unauthenticated_headers
109
+ req.params = params.compact
110
+ end
111
+ response.body
112
+ end
113
+ end
114
+
115
+ def get_signed(path, params = {})
116
+ with_rescue do
117
+ params = params.compact
118
+ query_string = params.empty? ? "" : "?#{Faraday::Utils.build_query(params)}"
119
+ ts = timestamp_ms.to_s
120
+ pre_sign = "#{ts}GET#{path}#{query_string}"
121
+
122
+ response = connection.get do |req|
123
+ req.url path
124
+ req.headers = signed_headers(ts, pre_sign)
125
+ req.params = params
126
+ end
127
+ response.body
128
+ end
129
+ end
130
+
131
+ def post_signed(path, body = {})
132
+ with_rescue do
133
+ body = body.compact
134
+ ts = timestamp_ms.to_s
135
+ pre_sign = "#{ts}POST#{path}#{body.to_json}"
136
+
137
+ response = connection.post do |req|
138
+ req.url path
139
+ req.headers = signed_headers(ts, pre_sign)
140
+ req.body = body
141
+ end
142
+ response.body
143
+ end
144
+ end
145
+
146
+ def delete_signed(path)
147
+ with_rescue do
148
+ ts = timestamp_ms.to_s
149
+ pre_sign = "#{ts}DELETE#{path}"
150
+
151
+ response = connection.delete do |req|
152
+ req.url path
153
+ req.headers = signed_headers(ts, pre_sign)
154
+ end
155
+ response.body
156
+ end
157
+ end
158
+
159
+ def unauthenticated_headers
160
+ { Accept: "application/json", "Content-Type": "application/json" }
161
+ end
162
+
163
+ def signed_headers(timestamp, pre_sign)
164
+ signature = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", @api_secret, pre_sign))
165
+ signed_passphrase = Base64.strict_encode64(
166
+ OpenSSL::HMAC.digest("sha256", @api_secret, @passphrase)
167
+ )
168
+ {
169
+ "KC-API-KEY": @api_key,
170
+ "KC-API-SIGN": signature,
171
+ "KC-API-TIMESTAMP": timestamp,
172
+ "KC-API-PASSPHRASE": signed_passphrase,
173
+ "KC-API-KEY-VERSION": "2",
174
+ Accept: "application/json",
175
+ "Content-Type": "application/json"
176
+ }
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Honeymaker
4
+ module Clients
5
+ class Mexc < Client
6
+ URL = "https://api.mexc.com"
7
+
8
+ def get_all_coins_information
9
+ get_public("/api/v3/capital/config/getall")
10
+ end
11
+
12
+ def exchange_information
13
+ get_public("/api/v3/exchangeInfo")
14
+ end
15
+
16
+ def symbol_price_ticker(symbol: nil)
17
+ get_public("/api/v3/ticker/price", { symbol: symbol })
18
+ end
19
+
20
+ def symbol_order_book_ticker(symbol: nil)
21
+ get_public("/api/v3/ticker/bookTicker", { symbol: symbol })
22
+ end
23
+
24
+ def candlestick_data(symbol:, interval:, start_time: nil, end_time: nil, limit: 500)
25
+ get_public("/api/v3/klines", {
26
+ symbol: symbol, interval: interval,
27
+ startTime: start_time, endTime: end_time, limit: limit
28
+ })
29
+ end
30
+
31
+ def account_information(recv_window: 5000)
32
+ get_signed("/api/v3/account", { recvWindow: recv_window })
33
+ end
34
+
35
+ def query_order(symbol:, order_id: nil, orig_client_order_id: nil, recv_window: 5000)
36
+ get_signed("/api/v3/order", {
37
+ symbol: symbol, orderId: order_id,
38
+ origClientOrderId: orig_client_order_id, recvWindow: recv_window
39
+ })
40
+ end
41
+
42
+ def new_order(symbol:, side:, type:, time_in_force: nil, quantity: nil, quote_order_qty: nil,
43
+ price: nil, new_client_order_id: nil, recv_window: 5000)
44
+ post_signed("/api/v3/order", {
45
+ symbol: symbol, side: side, type: type,
46
+ timeInForce: time_in_force, quantity: quantity,
47
+ quoteOrderQty: quote_order_qty, price: price,
48
+ newClientOrderId: new_client_order_id, recvWindow: recv_window
49
+ })
50
+ end
51
+
52
+ def cancel_order(symbol:, order_id: nil, orig_client_order_id: nil,
53
+ new_client_order_id: nil, recv_window: 5000)
54
+ delete_signed("/api/v3/order", {
55
+ symbol: symbol, orderId: order_id,
56
+ origClientOrderId: orig_client_order_id,
57
+ newClientOrderId: new_client_order_id, recvWindow: recv_window
58
+ })
59
+ end
60
+
61
+ def account_trade_list(symbol:, order_id: nil, start_time: nil, end_time: nil, limit: 500, recv_window: 5000)
62
+ get_signed("/api/v3/myTrades", {
63
+ symbol: symbol, orderId: order_id,
64
+ startTime: start_time, endTime: end_time, limit: limit, recvWindow: recv_window
65
+ })
66
+ end
67
+
68
+ def deposit_history(coin: nil, status: nil, start_time: nil, end_time: nil, limit: 1000, recv_window: 5000)
69
+ get_signed("/api/v3/capital/deposit/hisrec", {
70
+ coin: coin, status: status,
71
+ startTime: start_time, endTime: end_time, limit: limit, recvWindow: recv_window
72
+ })
73
+ end
74
+
75
+ def withdraw_history(coin: nil, status: nil, start_time: nil, end_time: nil, limit: 1000, recv_window: 5000)
76
+ get_signed("/api/v3/capital/withdraw/history", {
77
+ coin: coin, status: status,
78
+ startTime: start_time, endTime: end_time, limit: limit, recvWindow: recv_window
79
+ })
80
+ end
81
+
82
+ def get_withdraw_addresses(recv_window: 5000)
83
+ get_signed("/api/v3/capital/withdraw/address", { recvWindow: recv_window })
84
+ end
85
+
86
+ def withdraw(coin:, address:, amount:, network: nil, memo: nil, recv_window: 5000)
87
+ post_signed("/api/v3/capital/withdraw/apply", {
88
+ coin: coin, address: address, amount: amount,
89
+ network: network, memo: memo, recvWindow: recv_window
90
+ })
91
+ end
92
+
93
+ private
94
+
95
+ def validate_trading_credentials
96
+ result = account_information
97
+ result.success? ? Result::Success.new(true) : Result::Failure.new("Invalid trading credentials")
98
+ end
99
+
100
+ def validate_read_credentials
101
+ validate_trading_credentials
102
+ end
103
+
104
+ def get_public(path, params = {})
105
+ with_rescue do
106
+ response = connection.get do |req|
107
+ req.url path
108
+ req.headers = headers
109
+ req.params = params.compact
110
+ end
111
+ response.body
112
+ end
113
+ end
114
+
115
+ def get_signed(path, params = {})
116
+ with_rescue do
117
+ response = connection.get do |req|
118
+ req.url path
119
+ req.headers = headers
120
+ req.params = params.compact.merge(timestamp: timestamp_ms)
121
+ req.params[:signature] = sign_params(req.params)
122
+ end
123
+ response.body
124
+ end
125
+ end
126
+
127
+ def post_signed(path, params = {})
128
+ with_rescue do
129
+ response = connection.post do |req|
130
+ req.url path
131
+ req.headers = headers
132
+ req.params = params.compact.merge(timestamp: timestamp_ms)
133
+ req.params[:signature] = sign_params(req.params)
134
+ end
135
+ response.body
136
+ end
137
+ end
138
+
139
+ def delete_signed(path, params = {})
140
+ with_rescue do
141
+ response = connection.delete do |req|
142
+ req.url path
143
+ req.headers = headers
144
+ req.params = params.compact.merge(timestamp: timestamp_ms)
145
+ req.params[:signature] = sign_params(req.params)
146
+ end
147
+ response.body
148
+ end
149
+ end
150
+
151
+ def headers
152
+ if authenticated?
153
+ { "X-MEXC-APIKEY": @api_key, Accept: "application/json", "Content-Type": "application/json" }
154
+ else
155
+ { Accept: "application/json", "Content-Type": "application/json" }
156
+ end
157
+ end
158
+
159
+ def sign_params(params)
160
+ return unless @api_secret
161
+ query = Faraday::Utils.build_query(params)
162
+ hmac_sha256(@api_secret, query)
163
+ end
164
+ end
165
+ end
166
+ end
@@ -11,29 +11,23 @@ module Honeymaker
11
11
  req.params = { permissions: "SPOT" }
12
12
  end
13
13
 
14
- response.body["symbols"].map do |product|
15
- ticker = product["symbol"]
16
- status = product["status"]
17
-
18
- filters = product["filters"]
19
- price_filter = filters.find { |f| f["filterType"] == "PRICE_FILTER" }
20
- lot_size_filter = filters.find { |f| f["filterType"] == "LOT_SIZE" }
21
- notional_filter = filters.find { |f| %w[NOTIONAL MIN_NOTIONAL].include?(f["filterType"]) }
14
+ response.body["symbols"].filter_map do |product|
15
+ f = Utils.parse_filters(product["filters"])
22
16
 
23
17
  {
24
- ticker: ticker,
18
+ ticker: product["symbol"],
25
19
  base: product["baseAsset"],
26
20
  quote: product["quoteAsset"],
27
- minimum_base_size: lot_size_filter["minQty"],
28
- minimum_quote_size: notional_filter["minNotional"],
29
- maximum_base_size: lot_size_filter["maxQty"],
30
- maximum_quote_size: notional_filter["maxNotional"],
31
- base_decimals: Utils.decimals(lot_size_filter["stepSize"]),
21
+ minimum_base_size: f[:lot_size]["minQty"],
22
+ minimum_quote_size: f[:notional]["minNotional"],
23
+ maximum_base_size: f[:lot_size]["maxQty"],
24
+ maximum_quote_size: f[:notional]["maxNotional"],
25
+ base_decimals: Utils.decimals(f[:lot_size]["stepSize"]),
32
26
  quote_decimals: product["quoteAssetPrecision"],
33
- price_decimals: Utils.decimals(price_filter["tickSize"]),
34
- available: status == "TRADING"
27
+ price_decimals: Utils.decimals(f[:price]["tickSize"]),
28
+ available: product["status"] == "TRADING"
35
29
  }
36
- end.compact
30
+ end
37
31
  end
38
32
  end
39
33
 
@@ -9,7 +9,7 @@ module Honeymaker
9
9
  with_rescue do
10
10
  response = connection.get("/api/v2/spot/public/symbols")
11
11
 
12
- response.body["data"].map do |product|
12
+ response.body["data"].filter_map do |product|
13
13
  {
14
14
  ticker: product["symbol"],
15
15
  base: product["baseCoin"],
@@ -23,7 +23,7 @@ module Honeymaker
23
23
  price_decimals: product["pricePrecision"].to_i,
24
24
  available: product["status"] == "online"
25
25
  }
26
- end.compact
26
+ end
27
27
  end
28
28
  end
29
29
 
@@ -10,29 +10,19 @@ module Honeymaker
10
10
  response = connection.get("/api/v1/exchangeInfo")
11
11
 
12
12
  response.body["symbols"].filter_map do |product|
13
- filters = product["filters"] || []
14
- price_filter = filters.find { |f| f["filterType"] == "PRICE_FILTER" }
15
- lot_size_filter = filters.find { |f| f["filterType"] == "LOT_SIZE" }
13
+ f = Utils.parse_filters(product["filters"] || [])
16
14
 
17
15
  {
18
16
  ticker: product["symbol"],
19
17
  base: product["baseAsset"]&.upcase,
20
18
  quote: product["quoteAsset"]&.upcase,
21
- minimum_base_size: lot_size_filter&.dig("minQty"),
22
- minimum_quote_size: lot_size_filter&.dig("minVal"),
23
- maximum_base_size: lot_size_filter&.dig("maxQty"),
19
+ minimum_base_size: f[:lot_size]&.dig("minQty"),
20
+ minimum_quote_size: f[:lot_size]&.dig("minVal"),
21
+ maximum_base_size: f[:lot_size]&.dig("maxQty"),
24
22
  maximum_quote_size: nil,
25
- base_decimals: if lot_size_filter
26
- Utils.decimals(lot_size_filter["stepSize"])
27
- else
28
- product["baseAssetPrecision"]
29
- end,
23
+ base_decimals: f[:lot_size] ? Utils.decimals(f[:lot_size]["stepSize"]) : product["baseAssetPrecision"],
30
24
  quote_decimals: product["quotePrecision"],
31
- price_decimals: if price_filter
32
- Utils.decimals(price_filter["tickSize"])
33
- else
34
- product["quotePrecision"]
35
- end,
25
+ price_decimals: f[:price] ? Utils.decimals(f[:price]["tickSize"]) : product["quotePrecision"],
36
26
  available: product["status"] == "TRADING"
37
27
  }
38
28
  end
@@ -9,7 +9,7 @@ module Honeymaker
9
9
  with_rescue do
10
10
  response = connection.get("/v2/markets")
11
11
 
12
- response.body.map do |product|
12
+ response.body.filter_map do |product|
13
13
  market = product["market"]
14
14
  base, quote = market.split("-")
15
15
 
@@ -26,7 +26,7 @@ module Honeymaker
26
26
  price_decimals: product["pricePrecision"] || 8,
27
27
  available: product["status"] == "trading"
28
28
  }
29
- end.compact
29
+ end
30
30
  end
31
31
  end
32
32
 
@@ -11,7 +11,7 @@ module Honeymaker
11
11
  req.params = { category: "spot" }
12
12
  end
13
13
 
14
- response.body["result"]["list"].map do |product|
14
+ response.body["result"]["list"].filter_map do |product|
15
15
  lot_size_filter = product["lotSizeFilter"]
16
16
  price_filter = product["priceFilter"]
17
17
 
@@ -28,7 +28,7 @@ module Honeymaker
28
28
  price_decimals: Utils.decimals(price_filter["tickSize"]),
29
29
  available: product["status"] == "Trading"
30
30
  }
31
- end.compact
31
+ end
32
32
  end
33
33
  end
34
34
 
@@ -15,15 +15,11 @@ module Honeymaker
15
15
  with_rescue do
16
16
  response = connection.get("/api/v3/brokerage/market/products")
17
17
 
18
- response.body["products"].map do |product|
18
+ response.body["products"].filter_map do |product|
19
19
  ticker = product["product_id"]
20
20
  base, quote = ticker.split("-")
21
21
  next if ASSET_BLACKLIST.include?(base)
22
22
 
23
- base_increment = product["base_increment"]
24
- quote_increment = product["quote_increment"]
25
- price_increment = product["price_increment"]
26
-
27
23
  {
28
24
  ticker: ticker,
29
25
  base: base,
@@ -32,12 +28,12 @@ module Honeymaker
32
28
  minimum_quote_size: product["quote_min_size"],
33
29
  maximum_base_size: product["base_max_size"],
34
30
  maximum_quote_size: product["quote_max_size"],
35
- base_decimals: Utils.decimals(base_increment),
36
- quote_decimals: Utils.decimals(quote_increment),
37
- price_decimals: Utils.decimals(price_increment),
31
+ base_decimals: Utils.decimals(product["base_increment"]),
32
+ quote_decimals: Utils.decimals(product["quote_increment"]),
33
+ price_decimals: Utils.decimals(product["price_increment"]),
38
34
  available: true
39
35
  }
40
- end.compact
36
+ end
41
37
  end
42
38
  end
43
39