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.
- checksums.yaml +4 -4
- data/honeymaker-0.1.0.gem +0 -0
- data/lib/honeymaker/client.rb +74 -0
- data/lib/honeymaker/clients/binance.rb +240 -0
- data/lib/honeymaker/clients/binance_us.rb +9 -0
- data/lib/honeymaker/clients/bingx.rb +105 -0
- data/lib/honeymaker/clients/bitget.rb +128 -0
- data/lib/honeymaker/clients/bitmart.rb +117 -0
- data/lib/honeymaker/clients/bitrue.rb +114 -0
- data/lib/honeymaker/clients/bitvavo.rb +136 -0
- data/lib/honeymaker/clients/bybit.rb +136 -0
- data/lib/honeymaker/clients/coinbase.rb +184 -0
- data/lib/honeymaker/clients/gemini.rb +81 -0
- data/lib/honeymaker/clients/hyperliquid.rb +42 -0
- data/lib/honeymaker/clients/kraken.rb +132 -0
- data/lib/honeymaker/clients/kucoin.rb +147 -0
- data/lib/honeymaker/clients/mexc.rb +136 -0
- data/lib/honeymaker/exchanges/binance.rb +11 -17
- data/lib/honeymaker/exchanges/bitget.rb +2 -2
- data/lib/honeymaker/exchanges/bitrue.rb +6 -16
- data/lib/honeymaker/exchanges/bitvavo.rb +2 -2
- data/lib/honeymaker/exchanges/bybit.rb +2 -2
- data/lib/honeymaker/exchanges/coinbase.rb +5 -9
- data/lib/honeymaker/exchanges/gemini.rb +4 -6
- data/lib/honeymaker/exchanges/kraken.rb +5 -9
- data/lib/honeymaker/exchanges/kucoin.rb +2 -2
- data/lib/honeymaker/exchanges/mexc.rb +11 -17
- data/lib/honeymaker/utils.rb +9 -0
- data/lib/honeymaker/version.rb +1 -1
- data/lib/honeymaker.rb +38 -0
- data/test/fixtures/bingx_symbols.json +26 -0
- data/test/fixtures/bitget_symbols.json +28 -0
- data/test/fixtures/bitmart_symbols.json +26 -0
- data/test/fixtures/bitrue_exchange_info.json +34 -0
- data/test/fixtures/bitvavo_markets.json +16 -0
- data/test/fixtures/bybit_instruments.json +23 -0
- data/test/fixtures/coinbase_products.json +24 -0
- data/test/fixtures/gemini_symbol_detail.json +9 -0
- data/test/fixtures/gemini_symbols.json +1 -0
- data/test/fixtures/hyperliquid_spot_meta.json +12 -0
- data/test/fixtures/kucoin_symbols.json +17 -0
- data/test/fixtures/mexc_exchange_info.json +40 -0
- data/test/honeymaker/client_test.rb +53 -0
- data/test/honeymaker/clients/binance_client_test.rb +80 -0
- data/test/honeymaker/clients/binance_us_client_test.rb +25 -0
- data/test/honeymaker/clients/bingx_client_test.rb +64 -0
- data/test/honeymaker/clients/bitget_client_test.rb +85 -0
- data/test/honeymaker/clients/bitmart_client_test.rb +78 -0
- data/test/honeymaker/clients/bitrue_client_test.rb +63 -0
- data/test/honeymaker/clients/bitvavo_client_test.rb +87 -0
- data/test/honeymaker/clients/bybit_client_test.rb +84 -0
- data/test/honeymaker/clients/coinbase_client_test.rb +118 -0
- data/test/honeymaker/clients/gemini_client_test.rb +71 -0
- data/test/honeymaker/clients/honeymaker_client_registry_test.rb +44 -0
- data/test/honeymaker/clients/hyperliquid_client_test.rb +53 -0
- data/test/honeymaker/clients/kraken_client_test.rb +70 -0
- data/test/honeymaker/clients/kucoin_client_test.rb +88 -0
- data/test/honeymaker/clients/mexc_client_test.rb +75 -0
- data/test/honeymaker/exchanges/binance_us_test.rb +40 -0
- data/test/honeymaker/exchanges/bingx_test.rb +53 -0
- data/test/honeymaker/exchanges/bitget_test.rb +52 -0
- data/test/honeymaker/exchanges/bitmart_test.rb +52 -0
- data/test/honeymaker/exchanges/bitrue_test.rb +53 -0
- data/test/honeymaker/exchanges/bitvavo_test.rb +52 -0
- data/test/honeymaker/exchanges/bybit_test.rb +43 -0
- data/test/honeymaker/exchanges/coinbase_test.rb +52 -0
- data/test/honeymaker/exchanges/gemini_test.rb +48 -0
- data/test/honeymaker/exchanges/hyperliquid_test.rb +52 -0
- data/test/honeymaker/exchanges/kucoin_test.rb +43 -0
- data/test/honeymaker/exchanges/mexc_test.rb +64 -0
- data/test/honeymaker/utils_test.rb +38 -0
- data/test/test_helper.rb +1 -0
- metadata +74 -3
|
@@ -9,29 +9,23 @@ module Honeymaker
|
|
|
9
9
|
with_rescue do
|
|
10
10
|
response = connection.get("/api/v3/exchangeInfo")
|
|
11
11
|
|
|
12
|
-
response.body["symbols"].
|
|
13
|
-
|
|
14
|
-
status = product["status"]
|
|
15
|
-
|
|
16
|
-
filters = product["filters"]
|
|
17
|
-
price_filter = filters.find { |f| f["filterType"] == "PRICE_FILTER" }
|
|
18
|
-
lot_size_filter = filters.find { |f| f["filterType"] == "LOT_SIZE" }
|
|
19
|
-
notional_filter = filters.find { |f| %w[NOTIONAL MIN_NOTIONAL].include?(f["filterType"]) }
|
|
12
|
+
response.body["symbols"].filter_map do |product|
|
|
13
|
+
f = Utils.parse_filters(product["filters"])
|
|
20
14
|
|
|
21
15
|
{
|
|
22
|
-
ticker:
|
|
16
|
+
ticker: product["symbol"],
|
|
23
17
|
base: product["baseAsset"],
|
|
24
18
|
quote: product["quoteAsset"],
|
|
25
|
-
minimum_base_size:
|
|
26
|
-
minimum_quote_size:
|
|
27
|
-
maximum_base_size:
|
|
28
|
-
maximum_quote_size:
|
|
29
|
-
base_decimals:
|
|
19
|
+
minimum_base_size: f[:lot_size]&.[]("minQty"),
|
|
20
|
+
minimum_quote_size: f[:notional]&.[]("minNotional"),
|
|
21
|
+
maximum_base_size: f[:lot_size]&.[]("maxQty"),
|
|
22
|
+
maximum_quote_size: f[:notional]&.[]("maxNotional"),
|
|
23
|
+
base_decimals: f[:lot_size] ? Utils.decimals(f[:lot_size]["stepSize"]) : product["baseAssetPrecision"],
|
|
30
24
|
quote_decimals: product["quoteAssetPrecision"],
|
|
31
|
-
price_decimals:
|
|
32
|
-
available: status == "TRADING"
|
|
25
|
+
price_decimals: f[:price] ? Utils.decimals(f[:price]["tickSize"]) : product["quotePrecision"],
|
|
26
|
+
available: product["status"] == "TRADING"
|
|
33
27
|
}
|
|
34
|
-
end
|
|
28
|
+
end
|
|
35
29
|
end
|
|
36
30
|
end
|
|
37
31
|
|
data/lib/honeymaker/utils.rb
CHANGED
|
@@ -3,9 +3,18 @@
|
|
|
3
3
|
module Honeymaker
|
|
4
4
|
module Utils
|
|
5
5
|
def self.decimals(num)
|
|
6
|
+
return 0 if num.nil?
|
|
6
7
|
str = num.to_s.sub(/\.?0+$/, "")
|
|
7
8
|
return 0 unless str.include?(".")
|
|
8
9
|
str.split(".").last.length
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.parse_filters(filters)
|
|
13
|
+
{
|
|
14
|
+
price: filters.find { |f| f["filterType"] == "PRICE_FILTER" },
|
|
15
|
+
lot_size: filters.find { |f| f["filterType"] == "LOT_SIZE" },
|
|
16
|
+
notional: filters.find { |f| %w[NOTIONAL MIN_NOTIONAL].include?(f["filterType"]) }
|
|
17
|
+
}
|
|
18
|
+
end
|
|
10
19
|
end
|
|
11
20
|
end
|
data/lib/honeymaker/version.rb
CHANGED
data/lib/honeymaker.rb
CHANGED
|
@@ -8,6 +8,21 @@ require_relative "honeymaker/version"
|
|
|
8
8
|
require_relative "honeymaker/result"
|
|
9
9
|
require_relative "honeymaker/utils"
|
|
10
10
|
require_relative "honeymaker/exchange"
|
|
11
|
+
require_relative "honeymaker/client"
|
|
12
|
+
require_relative "honeymaker/clients/binance"
|
|
13
|
+
require_relative "honeymaker/clients/binance_us"
|
|
14
|
+
require_relative "honeymaker/clients/kraken"
|
|
15
|
+
require_relative "honeymaker/clients/coinbase"
|
|
16
|
+
require_relative "honeymaker/clients/bybit"
|
|
17
|
+
require_relative "honeymaker/clients/mexc"
|
|
18
|
+
require_relative "honeymaker/clients/bitget"
|
|
19
|
+
require_relative "honeymaker/clients/kucoin"
|
|
20
|
+
require_relative "honeymaker/clients/bitvavo"
|
|
21
|
+
require_relative "honeymaker/clients/gemini"
|
|
22
|
+
require_relative "honeymaker/clients/bingx"
|
|
23
|
+
require_relative "honeymaker/clients/bitrue"
|
|
24
|
+
require_relative "honeymaker/clients/bitmart"
|
|
25
|
+
require_relative "honeymaker/clients/hyperliquid"
|
|
11
26
|
require_relative "honeymaker/exchanges/binance"
|
|
12
27
|
require_relative "honeymaker/exchanges/binance_us"
|
|
13
28
|
require_relative "honeymaker/exchanges/kraken"
|
|
@@ -43,9 +58,32 @@ module Honeymaker
|
|
|
43
58
|
"bitmart" => Exchanges::BitMart
|
|
44
59
|
}.freeze
|
|
45
60
|
|
|
61
|
+
CLIENTS = {
|
|
62
|
+
"binance" => Clients::Binance,
|
|
63
|
+
"binance_us" => Clients::BinanceUs,
|
|
64
|
+
"kraken" => Clients::Kraken,
|
|
65
|
+
"coinbase" => Clients::Coinbase,
|
|
66
|
+
"bybit" => Clients::Bybit,
|
|
67
|
+
"mexc" => Clients::Mexc,
|
|
68
|
+
"bitget" => Clients::Bitget,
|
|
69
|
+
"kucoin" => Clients::Kucoin,
|
|
70
|
+
"bitvavo" => Clients::Bitvavo,
|
|
71
|
+
"gemini" => Clients::Gemini,
|
|
72
|
+
"bingx" => Clients::BingX,
|
|
73
|
+
"bitrue" => Clients::Bitrue,
|
|
74
|
+
"bitmart" => Clients::BitMart,
|
|
75
|
+
"hyperliquid" => Clients::Hyperliquid
|
|
76
|
+
}.freeze
|
|
77
|
+
|
|
46
78
|
def self.exchange(name)
|
|
47
79
|
klass = EXCHANGES[name.to_s]
|
|
48
80
|
raise Error, "Unknown exchange: #{name}" unless klass
|
|
49
81
|
klass.new
|
|
50
82
|
end
|
|
83
|
+
|
|
84
|
+
def self.client(name, **kwargs)
|
|
85
|
+
klass = CLIENTS[name.to_s]
|
|
86
|
+
raise Error, "Unknown exchange: #{name}" unless klass
|
|
87
|
+
klass.new(**kwargs)
|
|
88
|
+
end
|
|
51
89
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"symbols": [
|
|
4
|
+
{
|
|
5
|
+
"symbol": "BTC-USDT",
|
|
6
|
+
"minQty": "0.00001",
|
|
7
|
+
"maxQty": "500",
|
|
8
|
+
"minNotional": "1",
|
|
9
|
+
"maxNotional": "5000000",
|
|
10
|
+
"stepSize": "0.00001",
|
|
11
|
+
"tickSize": "0.01",
|
|
12
|
+
"status": 1
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"symbol": "INVALID",
|
|
16
|
+
"minQty": 1,
|
|
17
|
+
"maxQty": 1000,
|
|
18
|
+
"minNotional": 1,
|
|
19
|
+
"maxNotional": 10000,
|
|
20
|
+
"stepSize": "1",
|
|
21
|
+
"tickSize": "0.01",
|
|
22
|
+
"status": 1
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"symbol": "BTCUSDT",
|
|
5
|
+
"baseCoin": "BTC",
|
|
6
|
+
"quoteCoin": "USDT",
|
|
7
|
+
"minTradeAmount": "0.00001",
|
|
8
|
+
"minTradeUSDT": "5",
|
|
9
|
+
"maxTradeAmount": "9000",
|
|
10
|
+
"quantityPrecision": "6",
|
|
11
|
+
"quotePrecision": "8",
|
|
12
|
+
"pricePrecision": "2",
|
|
13
|
+
"status": "online"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"symbol": "ETHUSDT",
|
|
17
|
+
"baseCoin": "ETH",
|
|
18
|
+
"quoteCoin": "USDT",
|
|
19
|
+
"minTradeAmount": "0.001",
|
|
20
|
+
"minTradeUSDT": "5",
|
|
21
|
+
"maxTradeAmount": "5000",
|
|
22
|
+
"quantityPrecision": "4",
|
|
23
|
+
"quotePrecision": "8",
|
|
24
|
+
"pricePrecision": "2",
|
|
25
|
+
"status": "offline"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"symbols": [
|
|
4
|
+
{
|
|
5
|
+
"symbol": "BTC_USDT",
|
|
6
|
+
"base_currency": "BTC",
|
|
7
|
+
"quote_currency": "USDT",
|
|
8
|
+
"base_min_size": "0.00001",
|
|
9
|
+
"min_buy_amount": "5",
|
|
10
|
+
"quote_increment": "0.01",
|
|
11
|
+
"price_max_precision": 2,
|
|
12
|
+
"trade_status": "trading"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"symbol": "ETH_USDT",
|
|
16
|
+
"base_currency": "ETH",
|
|
17
|
+
"quote_currency": "USDT",
|
|
18
|
+
"base_min_size": "0.001",
|
|
19
|
+
"min_buy_amount": "5",
|
|
20
|
+
"quote_increment": "0.0001",
|
|
21
|
+
"price_max_precision": 4,
|
|
22
|
+
"trade_status": "pre-trade"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"symbols": [
|
|
3
|
+
{
|
|
4
|
+
"symbol": "BTCUSDT",
|
|
5
|
+
"baseAsset": "btc",
|
|
6
|
+
"quoteAsset": "usdt",
|
|
7
|
+
"baseAssetPrecision": 8,
|
|
8
|
+
"quotePrecision": 2,
|
|
9
|
+
"status": "TRADING",
|
|
10
|
+
"filters": [
|
|
11
|
+
{
|
|
12
|
+
"filterType": "PRICE_FILTER",
|
|
13
|
+
"tickSize": "0.01"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"filterType": "LOT_SIZE",
|
|
17
|
+
"minQty": "0.00001",
|
|
18
|
+
"maxQty": "9000",
|
|
19
|
+
"stepSize": "0.00001",
|
|
20
|
+
"minVal": "5"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"symbol": "ETHUSDT",
|
|
26
|
+
"baseAsset": "eth",
|
|
27
|
+
"quoteAsset": "usdt",
|
|
28
|
+
"baseAssetPrecision": 6,
|
|
29
|
+
"quotePrecision": 2,
|
|
30
|
+
"status": "TRADING",
|
|
31
|
+
"filters": []
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"market": "BTC-EUR",
|
|
4
|
+
"status": "trading",
|
|
5
|
+
"minOrderInBaseAsset": "0.00001",
|
|
6
|
+
"minOrderInQuoteAsset": "5",
|
|
7
|
+
"pricePrecision": 5
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"market": "ETH-EUR",
|
|
11
|
+
"status": "halted",
|
|
12
|
+
"minOrderInBaseAsset": "0.001",
|
|
13
|
+
"minOrderInQuoteAsset": "5",
|
|
14
|
+
"pricePrecision": 4
|
|
15
|
+
}
|
|
16
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"result": {
|
|
3
|
+
"list": [
|
|
4
|
+
{
|
|
5
|
+
"symbol": "BTCUSDT",
|
|
6
|
+
"baseCoin": "BTC",
|
|
7
|
+
"quoteCoin": "USDT",
|
|
8
|
+
"status": "Trading",
|
|
9
|
+
"lotSizeFilter": {
|
|
10
|
+
"minOrderQty": "0.000048",
|
|
11
|
+
"maxOrderQty": "71.73956243",
|
|
12
|
+
"minOrderAmt": "1",
|
|
13
|
+
"maxOrderAmt": "4000000",
|
|
14
|
+
"basePrecision": "0.000001",
|
|
15
|
+
"quotePrecision": "0.00000001"
|
|
16
|
+
},
|
|
17
|
+
"priceFilter": {
|
|
18
|
+
"tickSize": "0.01"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"products": [
|
|
3
|
+
{
|
|
4
|
+
"product_id": "BTC-USD",
|
|
5
|
+
"base_increment": "0.00000001",
|
|
6
|
+
"quote_increment": "0.01",
|
|
7
|
+
"price_increment": "0.01",
|
|
8
|
+
"base_min_size": "0.00000001",
|
|
9
|
+
"quote_min_size": "1",
|
|
10
|
+
"base_max_size": "3400",
|
|
11
|
+
"quote_max_size": "250000000"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"product_id": "RENDER-USD",
|
|
15
|
+
"base_increment": "0.01",
|
|
16
|
+
"quote_increment": "0.01",
|
|
17
|
+
"price_increment": "0.01",
|
|
18
|
+
"base_min_size": "0.01",
|
|
19
|
+
"quote_min_size": "1",
|
|
20
|
+
"base_max_size": "10000",
|
|
21
|
+
"quote_max_size": "250000000"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["btcusd", "ethusd"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [
|
|
3
|
+
{
|
|
4
|
+
"symbol": "BTC-USDT",
|
|
5
|
+
"baseCurrency": "BTC",
|
|
6
|
+
"quoteCurrency": "USDT",
|
|
7
|
+
"baseMinSize": "0.00001",
|
|
8
|
+
"quoteMinSize": "0.1",
|
|
9
|
+
"baseMaxSize": "10000000000",
|
|
10
|
+
"quoteMaxSize": "99999999",
|
|
11
|
+
"baseIncrement": "0.00000001",
|
|
12
|
+
"quoteIncrement": "0.000001",
|
|
13
|
+
"priceIncrement": "0.1",
|
|
14
|
+
"enableTrading": true
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"symbols": [
|
|
3
|
+
{
|
|
4
|
+
"symbol": "BTCUSDT",
|
|
5
|
+
"status": "TRADING",
|
|
6
|
+
"baseAsset": "BTC",
|
|
7
|
+
"quoteAsset": "USDT",
|
|
8
|
+
"baseAssetPrecision": 8,
|
|
9
|
+
"quoteAssetPrecision": 8,
|
|
10
|
+
"quotePrecision": 2,
|
|
11
|
+
"filters": [
|
|
12
|
+
{
|
|
13
|
+
"filterType": "PRICE_FILTER",
|
|
14
|
+
"tickSize": "0.01"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"filterType": "LOT_SIZE",
|
|
18
|
+
"minQty": "0.00001",
|
|
19
|
+
"maxQty": "9000",
|
|
20
|
+
"stepSize": "0.00001"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"filterType": "MIN_NOTIONAL",
|
|
24
|
+
"minNotional": "5",
|
|
25
|
+
"maxNotional": "9000000"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"symbol": "ETHUSDT",
|
|
31
|
+
"status": "HALT",
|
|
32
|
+
"baseAsset": "ETH",
|
|
33
|
+
"quoteAsset": "USDT",
|
|
34
|
+
"baseAssetPrecision": 6,
|
|
35
|
+
"quoteAssetPrecision": 8,
|
|
36
|
+
"quotePrecision": 2,
|
|
37
|
+
"filters": []
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class Honeymaker::ClientTest < Minitest::Test
|
|
6
|
+
def test_default_options
|
|
7
|
+
assert_equal 5, Honeymaker::Client::OPTIONS[:request][:open_timeout]
|
|
8
|
+
assert_equal 30, Honeymaker::Client::OPTIONS[:request][:read_timeout]
|
|
9
|
+
assert_equal 10, Honeymaker::Client::OPTIONS[:request][:write_timeout]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_authenticated_with_credentials
|
|
13
|
+
client = Honeymaker::Client.new(api_key: "key", api_secret: "secret")
|
|
14
|
+
assert client.send(:authenticated?)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_not_authenticated_without_credentials
|
|
18
|
+
client = Honeymaker::Client.new
|
|
19
|
+
refute client.send(:authenticated?)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_not_authenticated_with_empty_credentials
|
|
23
|
+
client = Honeymaker::Client.new(api_key: "", api_secret: "")
|
|
24
|
+
refute client.send(:authenticated?)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_with_rescue_wraps_success
|
|
28
|
+
client = Honeymaker::Client.new
|
|
29
|
+
result = client.send(:with_rescue) { { "status" => "ok" } }
|
|
30
|
+
assert result.success?
|
|
31
|
+
assert_equal({ "status" => "ok" }, result.data)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_with_rescue_wraps_faraday_error
|
|
35
|
+
client = Honeymaker::Client.new
|
|
36
|
+
result = client.send(:with_rescue) { raise Faraday::TimeoutError, "timeout" }
|
|
37
|
+
assert result.failure?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_with_rescue_wraps_standard_error
|
|
41
|
+
client = Honeymaker::Client.new
|
|
42
|
+
result = client.send(:with_rescue) { raise StandardError, "boom" }
|
|
43
|
+
assert result.failure?
|
|
44
|
+
assert_equal ["boom"], result.errors
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_hmac_sha256
|
|
48
|
+
client = Honeymaker::Client.new
|
|
49
|
+
sig = client.send(:hmac_sha256, "secret", "data")
|
|
50
|
+
expected = OpenSSL::HMAC.hexdigest("sha256", "secret", "data")
|
|
51
|
+
assert_equal expected, sig
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class Honeymaker::Clients::BinanceTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@client = Honeymaker::Clients::Binance.new(api_key: "test_key", api_secret: "test_secret")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_url
|
|
11
|
+
assert_equal "https://api.binance.com", Honeymaker::Clients::Binance::URL
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_exchange_information
|
|
15
|
+
stub_connection(:get, { "symbols" => [{ "symbol" => "BTCUSDT" }] })
|
|
16
|
+
result = @client.exchange_information
|
|
17
|
+
assert result.success?
|
|
18
|
+
assert_equal "BTCUSDT", result.data["symbols"].first["symbol"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_new_order
|
|
22
|
+
stub_connection(:post, { "orderId" => 123, "status" => "FILLED" })
|
|
23
|
+
result = @client.new_order(symbol: "BTCUSDT", side: "BUY", type: "MARKET", quantity: "0.001")
|
|
24
|
+
assert result.success?
|
|
25
|
+
assert_equal 123, result.data["orderId"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_query_order
|
|
29
|
+
stub_connection(:get, { "orderId" => 123, "status" => "FILLED" })
|
|
30
|
+
result = @client.query_order(symbol: "BTCUSDT", order_id: 123)
|
|
31
|
+
assert result.success?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_account_information
|
|
35
|
+
stub_connection(:get, { "balances" => [{ "asset" => "BTC", "free" => "0.5" }] })
|
|
36
|
+
result = @client.account_information
|
|
37
|
+
assert result.success?
|
|
38
|
+
assert_equal "BTC", result.data["balances"].first["asset"]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_cancel_order
|
|
42
|
+
stub_connection(:delete, { "orderId" => 123, "status" => "CANCELED" })
|
|
43
|
+
result = @client.cancel_order(symbol: "BTCUSDT", order_id: 123)
|
|
44
|
+
assert result.success?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_handles_api_error
|
|
48
|
+
connection = stub
|
|
49
|
+
connection.stubs(:get).raises(Faraday::ServerError.new("500", { status: 500, body: "Server Error" }))
|
|
50
|
+
@client.instance_variable_set(:@connection, connection)
|
|
51
|
+
result = @client.exchange_information
|
|
52
|
+
assert result.failure?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_headers_include_api_key
|
|
56
|
+
headers = @client.send(:headers)
|
|
57
|
+
assert_equal "test_key", headers[:"X-MBX-APIKEY"]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_headers_without_auth
|
|
61
|
+
client = Honeymaker::Clients::Binance.new
|
|
62
|
+
headers = client.send(:headers)
|
|
63
|
+
refute headers.key?(:"X-MBX-APIKEY")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_sign_params
|
|
67
|
+
sig = @client.send(:sign_params, { symbol: "BTCUSDT", timestamp: 1234567890 })
|
|
68
|
+
assert sig.is_a?(String)
|
|
69
|
+
assert_equal 64, sig.length
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def stub_connection(method, body)
|
|
75
|
+
response = stub(body: body)
|
|
76
|
+
connection = stub
|
|
77
|
+
connection.stubs(method).returns(response)
|
|
78
|
+
@client.instance_variable_set(:@connection, connection)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class Honeymaker::Clients::BinanceUsTest < Minitest::Test
|
|
6
|
+
def test_inherits_from_binance
|
|
7
|
+
client = Honeymaker::Clients::BinanceUs.new
|
|
8
|
+
assert_kind_of Honeymaker::Clients::Binance, client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_url
|
|
12
|
+
assert_equal "https://api.binance.us", Honeymaker::Clients::BinanceUs::URL
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_exchange_information
|
|
16
|
+
client = Honeymaker::Clients::BinanceUs.new(api_key: "k", api_secret: "s")
|
|
17
|
+
response = stub(body: { "symbols" => [] })
|
|
18
|
+
connection = stub
|
|
19
|
+
connection.stubs(:get).returns(response)
|
|
20
|
+
client.instance_variable_set(:@connection, connection)
|
|
21
|
+
|
|
22
|
+
result = client.exchange_information
|
|
23
|
+
assert result.success?
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class Honeymaker::Clients::BingXTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@client = Honeymaker::Clients::BingX.new(api_key: "test_key", api_secret: "test_secret")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_url
|
|
11
|
+
assert_equal "https://open-api.bingx.com", Honeymaker::Clients::BingX::URL
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_get_symbols
|
|
15
|
+
stub_connection(:get, { "data" => { "symbols" => [{ "symbol" => "BTC-USDT" }] } })
|
|
16
|
+
result = @client.get_symbols
|
|
17
|
+
assert result.success?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_get_ticker
|
|
21
|
+
stub_connection(:get, { "data" => [{ "symbol" => "BTC-USDT" }] })
|
|
22
|
+
result = @client.get_ticker(symbol: "BTC-USDT")
|
|
23
|
+
assert result.success?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_get_balances
|
|
27
|
+
stub_connection(:get, { "data" => { "balances" => [{ "asset" => "BTC" }] } })
|
|
28
|
+
result = @client.get_balances
|
|
29
|
+
assert result.success?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_place_order
|
|
33
|
+
stub_connection(:post, { "data" => { "orderId" => "123" } })
|
|
34
|
+
result = @client.place_order(symbol: "BTC-USDT", side: "BUY", type: "MARKET", quantity: "0.001")
|
|
35
|
+
assert result.success?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_get_order
|
|
39
|
+
stub_connection(:get, { "data" => { "orderId" => "123" } })
|
|
40
|
+
result = @client.get_order(symbol: "BTC-USDT", order_id: "123")
|
|
41
|
+
assert result.success?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_cancel_order
|
|
45
|
+
stub_connection(:post, { "data" => { "orderId" => "123" } })
|
|
46
|
+
result = @client.cancel_order(symbol: "BTC-USDT", order_id: "123")
|
|
47
|
+
assert result.success?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_withdraw
|
|
51
|
+
stub_connection(:post, { "data" => { "id" => "w1" } })
|
|
52
|
+
result = @client.withdraw(coin: "BTC", address: "addr", amount: "0.1")
|
|
53
|
+
assert result.success?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def stub_connection(method, body)
|
|
59
|
+
response = stub(body: body)
|
|
60
|
+
connection = stub
|
|
61
|
+
connection.stubs(method).returns(response)
|
|
62
|
+
@client.instance_variable_set(:@connection, connection)
|
|
63
|
+
end
|
|
64
|
+
end
|