honeymaker 0.1.0 → 0.2.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/honeymaker-0.1.0.gem +0 -0
  3. data/lib/honeymaker/client.rb +74 -0
  4. data/lib/honeymaker/clients/binance.rb +240 -0
  5. data/lib/honeymaker/clients/binance_us.rb +9 -0
  6. data/lib/honeymaker/clients/bingx.rb +105 -0
  7. data/lib/honeymaker/clients/bitget.rb +128 -0
  8. data/lib/honeymaker/clients/bitmart.rb +117 -0
  9. data/lib/honeymaker/clients/bitrue.rb +114 -0
  10. data/lib/honeymaker/clients/bitvavo.rb +136 -0
  11. data/lib/honeymaker/clients/bybit.rb +136 -0
  12. data/lib/honeymaker/clients/coinbase.rb +184 -0
  13. data/lib/honeymaker/clients/gemini.rb +81 -0
  14. data/lib/honeymaker/clients/hyperliquid.rb +42 -0
  15. data/lib/honeymaker/clients/kraken.rb +132 -0
  16. data/lib/honeymaker/clients/kucoin.rb +147 -0
  17. data/lib/honeymaker/clients/mexc.rb +136 -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 +80 -0
  45. data/test/honeymaker/clients/binance_us_client_test.rb +25 -0
  46. data/test/honeymaker/clients/bingx_client_test.rb +64 -0
  47. data/test/honeymaker/clients/bitget_client_test.rb +85 -0
  48. data/test/honeymaker/clients/bitmart_client_test.rb +78 -0
  49. data/test/honeymaker/clients/bitrue_client_test.rb +63 -0
  50. data/test/honeymaker/clients/bitvavo_client_test.rb +87 -0
  51. data/test/honeymaker/clients/bybit_client_test.rb +84 -0
  52. data/test/honeymaker/clients/coinbase_client_test.rb +118 -0
  53. data/test/honeymaker/clients/gemini_client_test.rb +71 -0
  54. data/test/honeymaker/clients/honeymaker_client_registry_test.rb +44 -0
  55. data/test/honeymaker/clients/hyperliquid_client_test.rb +53 -0
  56. data/test/honeymaker/clients/kraken_client_test.rb +70 -0
  57. data/test/honeymaker/clients/kucoin_client_test.rb +88 -0
  58. data/test/honeymaker/clients/mexc_client_test.rb +75 -0
  59. data/test/honeymaker/exchanges/binance_us_test.rb +40 -0
  60. data/test/honeymaker/exchanges/bingx_test.rb +53 -0
  61. data/test/honeymaker/exchanges/bitget_test.rb +52 -0
  62. data/test/honeymaker/exchanges/bitmart_test.rb +52 -0
  63. data/test/honeymaker/exchanges/bitrue_test.rb +53 -0
  64. data/test/honeymaker/exchanges/bitvavo_test.rb +52 -0
  65. data/test/honeymaker/exchanges/bybit_test.rb +43 -0
  66. data/test/honeymaker/exchanges/coinbase_test.rb +52 -0
  67. data/test/honeymaker/exchanges/gemini_test.rb +48 -0
  68. data/test/honeymaker/exchanges/hyperliquid_test.rb +52 -0
  69. data/test/honeymaker/exchanges/kucoin_test.rb +43 -0
  70. data/test/honeymaker/exchanges/mexc_test.rb +64 -0
  71. data/test/honeymaker/utils_test.rb +38 -0
  72. data/test/test_helper.rb +1 -0
  73. metadata +74 -3
@@ -0,0 +1,132 @@
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_withdraw_addresses(asset: nil, method: nil)
65
+ post_private("/0/private/WithdrawAddresses", { nonce: nonce, asset: asset, method: method })
66
+ end
67
+
68
+ def get_withdraw_methods(asset: nil)
69
+ post_private("/0/private/WithdrawMethods", { nonce: nonce, asset: asset })
70
+ end
71
+
72
+ def withdraw(asset:, key:, amount:, address: nil)
73
+ post_private("/0/private/Withdraw", { nonce: nonce, asset: asset, key: key, amount: amount, address: address })
74
+ end
75
+
76
+ private
77
+
78
+ def get_public(path, params = {})
79
+ with_rescue do
80
+ response = connection.get do |req|
81
+ req.url path
82
+ req.headers = public_headers
83
+ req.params = params.compact
84
+ end
85
+ response.body
86
+ end
87
+ end
88
+
89
+ def post_private(path, body = {})
90
+ with_rescue do
91
+ response = connection.post do |req|
92
+ req.url path
93
+ req.body = URI.encode_www_form(body.compact)
94
+ req.headers = private_headers(req.path, req.body)
95
+ end
96
+ response.body
97
+ end
98
+ end
99
+
100
+ def nonce
101
+ (Time.now.utc.to_f * 1_000_000).to_i
102
+ end
103
+
104
+ def private_headers(path, body)
105
+ return public_headers unless authenticated?
106
+
107
+ request_nonce = URI.decode_www_form(body).to_h["nonce"]
108
+ data = "#{request_nonce}#{body}"
109
+ message = path + Digest::SHA256.digest(data)
110
+ decoded_key = Base64.decode64(@api_secret)
111
+ begin
112
+ hmac = OpenSSL::HMAC.digest("sha512", decoded_key, message)
113
+ rescue OpenSSL::HMACError
114
+ return public_headers
115
+ end
116
+ signature = Base64.strict_encode64(hmac)
117
+
118
+ {
119
+ "API-Key": @api_key,
120
+ "API-Sign": signature,
121
+ Accept: "application/json",
122
+ "Content-Type": "application/x-www-form-urlencoded",
123
+ "User-Agent": "Honeymaker Ruby"
124
+ }
125
+ end
126
+
127
+ def public_headers
128
+ { Accept: "application/json", "Content-Type": "application/json", "User-Agent": "Honeymaker Ruby" }
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,147 @@
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 withdraw(currency:, address:, amount:, chain: nil, memo: nil)
63
+ post_signed("/api/v1/withdrawals", {
64
+ currency: currency, address: address, amount: amount,
65
+ chain: chain, memo: memo
66
+ })
67
+ end
68
+
69
+ private
70
+
71
+ def get_public(path, params = {})
72
+ with_rescue do
73
+ response = connection.get do |req|
74
+ req.url path
75
+ req.headers = unauthenticated_headers
76
+ req.params = params.compact
77
+ end
78
+ response.body
79
+ end
80
+ end
81
+
82
+ def get_signed(path, params = {})
83
+ with_rescue do
84
+ params = params.compact
85
+ query_string = params.empty? ? "" : "?#{Faraday::Utils.build_query(params)}"
86
+ ts = timestamp_ms.to_s
87
+ pre_sign = "#{ts}GET#{path}#{query_string}"
88
+
89
+ response = connection.get do |req|
90
+ req.url path
91
+ req.headers = signed_headers(ts, pre_sign)
92
+ req.params = params
93
+ end
94
+ response.body
95
+ end
96
+ end
97
+
98
+ def post_signed(path, body = {})
99
+ with_rescue do
100
+ body = body.compact
101
+ ts = timestamp_ms.to_s
102
+ pre_sign = "#{ts}POST#{path}#{body.to_json}"
103
+
104
+ response = connection.post do |req|
105
+ req.url path
106
+ req.headers = signed_headers(ts, pre_sign)
107
+ req.body = body
108
+ end
109
+ response.body
110
+ end
111
+ end
112
+
113
+ def delete_signed(path)
114
+ with_rescue do
115
+ ts = timestamp_ms.to_s
116
+ pre_sign = "#{ts}DELETE#{path}"
117
+
118
+ response = connection.delete do |req|
119
+ req.url path
120
+ req.headers = signed_headers(ts, pre_sign)
121
+ end
122
+ response.body
123
+ end
124
+ end
125
+
126
+ def unauthenticated_headers
127
+ { Accept: "application/json", "Content-Type": "application/json" }
128
+ end
129
+
130
+ def signed_headers(timestamp, pre_sign)
131
+ signature = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", @api_secret, pre_sign))
132
+ signed_passphrase = Base64.strict_encode64(
133
+ OpenSSL::HMAC.digest("sha256", @api_secret, @passphrase)
134
+ )
135
+ {
136
+ "KC-API-KEY": @api_key,
137
+ "KC-API-SIGN": signature,
138
+ "KC-API-TIMESTAMP": timestamp,
139
+ "KC-API-PASSPHRASE": signed_passphrase,
140
+ "KC-API-KEY-VERSION": "2",
141
+ Accept: "application/json",
142
+ "Content-Type": "application/json"
143
+ }
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,136 @@
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 get_withdraw_addresses(recv_window: 5000)
62
+ get_signed("/api/v3/capital/withdraw/address", { recvWindow: recv_window })
63
+ end
64
+
65
+ def withdraw(coin:, address:, amount:, network: nil, memo: nil, recv_window: 5000)
66
+ post_signed("/api/v3/capital/withdraw/apply", {
67
+ coin: coin, address: address, amount: amount,
68
+ network: network, memo: memo, recvWindow: recv_window
69
+ })
70
+ end
71
+
72
+ private
73
+
74
+ def get_public(path, params = {})
75
+ with_rescue do
76
+ response = connection.get do |req|
77
+ req.url path
78
+ req.headers = headers
79
+ req.params = params.compact
80
+ end
81
+ response.body
82
+ end
83
+ end
84
+
85
+ def get_signed(path, params = {})
86
+ with_rescue do
87
+ response = connection.get do |req|
88
+ req.url path
89
+ req.headers = headers
90
+ req.params = params.compact.merge(timestamp: timestamp_ms)
91
+ req.params[:signature] = sign_params(req.params)
92
+ end
93
+ response.body
94
+ end
95
+ end
96
+
97
+ def post_signed(path, params = {})
98
+ with_rescue do
99
+ response = connection.post do |req|
100
+ req.url path
101
+ req.headers = headers
102
+ req.params = params.compact.merge(timestamp: timestamp_ms)
103
+ req.params[:signature] = sign_params(req.params)
104
+ end
105
+ response.body
106
+ end
107
+ end
108
+
109
+ def delete_signed(path, params = {})
110
+ with_rescue do
111
+ response = connection.delete do |req|
112
+ req.url path
113
+ req.headers = headers
114
+ req.params = params.compact.merge(timestamp: timestamp_ms)
115
+ req.params[:signature] = sign_params(req.params)
116
+ end
117
+ response.body
118
+ end
119
+ end
120
+
121
+ def headers
122
+ if authenticated?
123
+ { "X-MEXC-APIKEY": @api_key, Accept: "application/json", "Content-Type": "application/json" }
124
+ else
125
+ { Accept: "application/json", "Content-Type": "application/json" }
126
+ end
127
+ end
128
+
129
+ def sign_params(params)
130
+ return unless @api_secret
131
+ query = Faraday::Utils.build_query(params)
132
+ hmac_sha256(@api_secret, query)
133
+ end
134
+ end
135
+ end
136
+ 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
 
@@ -10,18 +10,16 @@ module Honeymaker
10
10
  symbols_response = connection.get("/v1/symbols")
11
11
  symbols = symbols_response.body
12
12
 
13
- symbols.map do |symbol|
13
+ symbols.filter_map do |symbol|
14
14
  detail = connection.get("/v1/symbols/details/#{symbol}").body
15
15
 
16
- base = detail["base_currency"].upcase
17
- quote = detail["quote_currency"].upcase
18
16
  tick_size = detail["tick_size"]&.to_s || "0.01"
19
17
  quote_increment = detail["quote_increment"]&.to_s || "0.01"
20
18
 
21
19
  {
22
20
  ticker: symbol.upcase,
23
- base: base,
24
- quote: quote,
21
+ base: detail["base_currency"].upcase,
22
+ quote: detail["quote_currency"].upcase,
25
23
  minimum_base_size: detail["min_order_size"],
26
24
  minimum_quote_size: "0",
27
25
  maximum_base_size: nil,
@@ -31,7 +29,7 @@ module Honeymaker
31
29
  price_decimals: Utils.decimals(quote_increment),
32
30
  available: detail["status"] == "open"
33
31
  }
34
- end.compact
32
+ end
35
33
  end
36
34
  end
37
35
 
@@ -35,22 +35,18 @@ module Honeymaker
35
35
  error = response.body["error"]
36
36
  return Result::Failure.new(*error) if error.is_a?(Array) && error.any?
37
37
 
38
- response.body["result"].map do |_, info|
39
- ticker = info["altname"]
40
-
38
+ response.body["result"].filter_map do |_, info|
41
39
  wsname = info["wsname"]
42
40
  next unless wsname && !wsname.empty?
43
41
 
44
42
  base, quote = wsname.split("/")
45
- minimum_base_size = info["ordermin"]
46
- minimum_quote_size = (REAL_COSTMIN[quote] || info["costmin"] || 0).to_s
47
43
 
48
44
  {
49
- ticker: ticker,
45
+ ticker: info["altname"],
50
46
  base: base,
51
47
  quote: quote,
52
- minimum_base_size: minimum_base_size,
53
- minimum_quote_size: minimum_quote_size,
48
+ minimum_base_size: info["ordermin"],
49
+ minimum_quote_size: (REAL_COSTMIN[quote] || info["costmin"] || 0).to_s,
54
50
  maximum_base_size: nil,
55
51
  maximum_quote_size: nil,
56
52
  base_decimals: info["lot_decimals"],
@@ -58,7 +54,7 @@ module Honeymaker
58
54
  price_decimals: info["pair_decimals"],
59
55
  available: true
60
56
  }
61
- end.compact
57
+ end
62
58
  end
63
59
  end
64
60
 
@@ -9,7 +9,7 @@ module Honeymaker
9
9
  with_rescue do
10
10
  response = connection.get("/api/v2/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["baseCurrency"],
@@ -23,7 +23,7 @@ module Honeymaker
23
23
  price_decimals: Utils.decimals(product["priceIncrement"]),
24
24
  available: product["enableTrading"]
25
25
  }
26
- end.compact
26
+ end
27
27
  end
28
28
  end
29
29