honeymaker 0.12.5-aarch64-linux → 0.12.6-aarch64-linux
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/lib/honeymaker/3.4/honeymaker_native.so +0 -0
- data/lib/honeymaker/4.0/honeymaker_native.so +0 -0
- data/lib/honeymaker/exchanges/bingx.rb +3 -1
- data/lib/honeymaker/exchanges/bitget.rb +31 -2
- data/lib/honeymaker/exchanges/hyperliquid.rb +1 -6
- data/lib/honeymaker/exchanges/kraken.rb +1 -20
- data/lib/honeymaker/floors.rb +59 -0
- data/lib/honeymaker/version.rb +1 -1
- data/lib/honeymaker.rb +1 -0
- data/test/honeymaker/exchanges/bingx_test.rb +1 -1
- data/test/honeymaker/exchanges/bitget_test.rb +52 -0
- data/test/honeymaker/exchanges/kraken_test.rb +12 -0
- data/test/honeymaker/floors_test.rb +37 -0
- data/test/parity/kraken_exchange_parity_test.rb +26 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: facaf702a43fc739fe970a71f72017dd240617a8938a53934adb892c968f91cf
|
|
4
|
+
data.tar.gz: f7076b3470b45e3250f5794894f8e7e6a93cbcf034c76a67e117eea52649e5d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b19a598c52226ea8b503c9b887e0d091cc387937799475af8b65473907c8ce3e5546126cdaa73f1c0610d6c5bcf36f46f181c190a01b14e9c7f8c85d297a637
|
|
7
|
+
data.tar.gz: 7363a8ca3f95e42abd6dbb6584db23bcb80c6dc2872067e23a930c75d51ff80f737df96a50ec01547051591a4a2725b137d56b5690c0a9f54fe496070180856a
|
|
Binary file
|
|
Binary file
|
|
@@ -18,7 +18,9 @@ module Honeymaker
|
|
|
18
18
|
ticker: ticker,
|
|
19
19
|
base: parts[0],
|
|
20
20
|
quote: parts[1],
|
|
21
|
-
|
|
21
|
+
# minQty is deprecated and far above what BingX accepts (~15 USDT on BTC-USDT against a
|
|
22
|
+
# 0.5 minNotional); the notional is the venue's only real floor.
|
|
23
|
+
minimum_base_size: "0",
|
|
22
24
|
minimum_quote_size: product["minNotional"]&.to_s,
|
|
23
25
|
maximum_base_size: product["maxQty"]&.to_s,
|
|
24
26
|
maximum_quote_size: product["maxNotional"]&.to_s,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "bigdecimal/util"
|
|
4
|
+
|
|
3
5
|
module Honeymaker
|
|
4
6
|
module Exchanges
|
|
5
7
|
class Bitget < Exchange
|
|
@@ -8,14 +10,16 @@ module Honeymaker
|
|
|
8
10
|
def get_tickers_info
|
|
9
11
|
with_rescue do
|
|
10
12
|
response = connection.get("/api/v2/spot/public/symbols")
|
|
13
|
+
products = response.body["data"]
|
|
14
|
+
prices = products.any? { |p| p["quoteCoin"] != "USDT" } ? usdt_prices : {}
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
products.filter_map do |product|
|
|
13
17
|
{
|
|
14
18
|
ticker: product["symbol"],
|
|
15
19
|
base: product["baseCoin"],
|
|
16
20
|
quote: product["quoteCoin"],
|
|
17
21
|
minimum_base_size: product["minTradeAmount"],
|
|
18
|
-
minimum_quote_size: product["minTradeUSDT"],
|
|
22
|
+
minimum_quote_size: quote_minimum(product["quoteCoin"], product["minTradeUSDT"], prices),
|
|
19
23
|
maximum_base_size: product["maxTradeAmount"],
|
|
20
24
|
maximum_quote_size: nil,
|
|
21
25
|
base_decimals: product["quantityPrecision"].to_i,
|
|
@@ -44,6 +48,31 @@ module Honeymaker
|
|
|
44
48
|
|
|
45
49
|
private
|
|
46
50
|
|
|
51
|
+
# minTradeUSDT is a USDT figure on every pair, whatever its quote
|
|
52
|
+
# (https://www.bitget.com/docs/catalog/classic-spot-market/classic-spot-market#get-symbol-info), so
|
|
53
|
+
# on ETHBTC its 1 meant a 1 BTC minimum. Converted at the quote's own USDT price (never the
|
|
54
|
+
# traded pair's); with no price to convert at, the minimum is left to the venue (0) rather than
|
|
55
|
+
# guessed. Same rule as deltabadger's Exchanges::Bitget#quote_minimum.
|
|
56
|
+
def quote_minimum(quote, usdt_minimum, prices)
|
|
57
|
+
minimum = usdt_minimum.to_s.to_d
|
|
58
|
+
return usdt_minimum if quote == "USDT" || minimum.zero?
|
|
59
|
+
|
|
60
|
+
if (price = prices["#{quote}USDT"].to_d).positive?
|
|
61
|
+
(minimum / price).to_s("F")
|
|
62
|
+
elsif (price = prices["USDT#{quote}"].to_d).positive?
|
|
63
|
+
(minimum * price).to_s("F")
|
|
64
|
+
else
|
|
65
|
+
"0"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# symbol => lastPr for the whole market; {} when the read fails, so conversions fall back to 0.
|
|
70
|
+
def usdt_prices
|
|
71
|
+
connection.get("/api/v2/spot/market/tickers").body["data"].to_h { |t| [t["symbol"], t["lastPr"]] }
|
|
72
|
+
rescue StandardError
|
|
73
|
+
{}
|
|
74
|
+
end
|
|
75
|
+
|
|
47
76
|
def connection
|
|
48
77
|
@connection ||= build_connection(BASE_URL)
|
|
49
78
|
end
|
|
@@ -5,11 +5,6 @@ module Honeymaker
|
|
|
5
5
|
class Hyperliquid < Exchange
|
|
6
6
|
BASE_URL = "https://api.hyperliquid.xyz"
|
|
7
7
|
|
|
8
|
-
# Hyperliquid enforces a hard 10-USDC minimum order value on every spot pair (spotMeta exposes
|
|
9
|
-
# no per-token base floor). Surfaced as minimum_quote_size so consumers skip/reject sub-10
|
|
10
|
-
# orders up front instead of having the exchange reject them.
|
|
11
|
-
MINIMUM_QUOTE_SIZE = 10
|
|
12
|
-
|
|
13
8
|
def get_tickers_info
|
|
14
9
|
with_rescue do
|
|
15
10
|
response = connection.post("/info") do |req|
|
|
@@ -30,7 +25,7 @@ module Honeymaker
|
|
|
30
25
|
base: base_token["name"],
|
|
31
26
|
quote: quote_token["name"],
|
|
32
27
|
minimum_base_size: nil,
|
|
33
|
-
minimum_quote_size:
|
|
28
|
+
minimum_quote_size: Floors.minimum_quote(venue: "hyperliquid", quote: quote_token["name"]),
|
|
34
29
|
maximum_base_size: nil,
|
|
35
30
|
maximum_quote_size: nil,
|
|
36
31
|
base_decimals: base_token["szDecimals"] || 0,
|
|
@@ -27,25 +27,6 @@ module Honeymaker
|
|
|
27
27
|
}
|
|
28
28
|
].freeze
|
|
29
29
|
|
|
30
|
-
REAL_COSTMIN = {
|
|
31
|
-
"AUD" => 10,
|
|
32
|
-
"CAD" => 5,
|
|
33
|
-
"CHF" => 5,
|
|
34
|
-
"DAI" => 5,
|
|
35
|
-
"ETH" => 0.002,
|
|
36
|
-
"EUR" => 0.5,
|
|
37
|
-
"GBP" => 5,
|
|
38
|
-
"JPY" => 500,
|
|
39
|
-
"PYUSD" => 5,
|
|
40
|
-
"RLUSD" => 5,
|
|
41
|
-
"USD" => 5,
|
|
42
|
-
"USDC" => 5,
|
|
43
|
-
"USDQ" => 5,
|
|
44
|
-
"USDR" => 5,
|
|
45
|
-
"USDT" => 5,
|
|
46
|
-
"XBT" => 0.00005
|
|
47
|
-
}.freeze
|
|
48
|
-
|
|
49
30
|
def get_tickers_info
|
|
50
31
|
with_rescue do
|
|
51
32
|
# aclass_base=all, not a bare call: the default response carries only the "currency" class,
|
|
@@ -74,7 +55,7 @@ module Honeymaker
|
|
|
74
55
|
base: base,
|
|
75
56
|
quote: quote,
|
|
76
57
|
minimum_base_size: info["ordermin"],
|
|
77
|
-
minimum_quote_size: (
|
|
58
|
+
minimum_quote_size: Floors.minimum_quote(venue: "kraken", quote: quote, published: info["costmin"] || 0).to_s,
|
|
78
59
|
maximum_base_size: nil,
|
|
79
60
|
maximum_quote_size: nil,
|
|
80
61
|
base_decimals: info["lot_decimals"],
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bigdecimal"
|
|
4
|
+
|
|
5
|
+
module Honeymaker
|
|
6
|
+
# Minimum order values venues enforce but do not publish (or publish too low), found by test
|
|
7
|
+
# orders. A ticker's minimum_quote_size is max(published, floor): a floor never lowers a minimum
|
|
8
|
+
# the venue itself raised. Consumed by the venue parsers here and by data-api for venues it
|
|
9
|
+
# builds itself (Alpaca crypto).
|
|
10
|
+
module Floors
|
|
11
|
+
ANY_QUOTE = :any
|
|
12
|
+
|
|
13
|
+
# [venue, asset_class] => { quote => floor }. A nil asset class covers every class the venue
|
|
14
|
+
# lists; ANY_QUOTE covers every quote.
|
|
15
|
+
MINIMUM_QUOTE = {
|
|
16
|
+
# Kraken's AssetPairs costmin is below what AddOrder accepts ("EOrder:Cost minimum not met");
|
|
17
|
+
# these are the per-quote costs it actually enforces. The native core mirrors this table
|
|
18
|
+
# (crates/honeymaker/src/kraken/normalize.rs REAL_COSTMIN; parity-tested).
|
|
19
|
+
["kraken", nil] => {
|
|
20
|
+
"AUD" => 10,
|
|
21
|
+
"CAD" => 5,
|
|
22
|
+
"CHF" => 5,
|
|
23
|
+
"DAI" => 5,
|
|
24
|
+
"ETH" => 0.002,
|
|
25
|
+
"EUR" => 0.5,
|
|
26
|
+
"GBP" => 5,
|
|
27
|
+
"JPY" => 500,
|
|
28
|
+
"PYUSD" => 5,
|
|
29
|
+
"RLUSD" => 5,
|
|
30
|
+
"USD" => 5,
|
|
31
|
+
"USDC" => 5,
|
|
32
|
+
"USDQ" => 5,
|
|
33
|
+
"USDR" => 5,
|
|
34
|
+
"USDT" => 5,
|
|
35
|
+
"XBT" => 0.00005
|
|
36
|
+
},
|
|
37
|
+
# "Order must have minimum value of 10 USDC." on every spot pair; spotMeta publishes no
|
|
38
|
+
# minimum. The value is measured in USDC whatever the pair's quote, so it covers all quotes.
|
|
39
|
+
["hyperliquid", nil] => { ANY_QUOTE => 10 },
|
|
40
|
+
# "cost basis must be >= minimal amount of order 10" on crypto; the assets API publishes only
|
|
41
|
+
# min_order_size (base). Stocks are not floored here (notional orders from $1).
|
|
42
|
+
["alpaca", "crypto"] => { "USD" => 10 }
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# The minimum quote size to store: max(published, floor). Returns published when no floor
|
|
46
|
+
# applies (nil when neither exists), and the floor when published is missing or not a number.
|
|
47
|
+
# Whichever wins is returned as given, so callers keep their own formatting.
|
|
48
|
+
def self.minimum_quote(venue:, quote:, asset_class: nil, published: nil)
|
|
49
|
+
quotes = MINIMUM_QUOTE[[venue.to_s, asset_class&.to_s]] || MINIMUM_QUOTE[[venue.to_s, nil]] || {}
|
|
50
|
+
floor = quotes.fetch(quote.to_s) { quotes[ANY_QUOTE] }
|
|
51
|
+
return published if floor.nil?
|
|
52
|
+
return floor if published.nil?
|
|
53
|
+
|
|
54
|
+
BigDecimal(published.to_s) > BigDecimal(floor.to_s) ? published : floor
|
|
55
|
+
rescue ArgumentError
|
|
56
|
+
floor
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/honeymaker/version.rb
CHANGED
data/lib/honeymaker.rb
CHANGED
|
@@ -7,6 +7,7 @@ require "json"
|
|
|
7
7
|
require_relative "honeymaker/version"
|
|
8
8
|
require_relative "honeymaker/result"
|
|
9
9
|
require_relative "honeymaker/utils"
|
|
10
|
+
require_relative "honeymaker/floors"
|
|
10
11
|
require_relative "honeymaker/exchange"
|
|
11
12
|
require_relative "honeymaker/client"
|
|
12
13
|
require_relative "honeymaker/native"
|
|
@@ -23,7 +23,7 @@ class Honeymaker::Exchanges::BingXTest < Minitest::Test
|
|
|
23
23
|
assert_equal "BTC-USDT", ticker[:ticker]
|
|
24
24
|
assert_equal "BTC", ticker[:base]
|
|
25
25
|
assert_equal "USDT", ticker[:quote]
|
|
26
|
-
assert_equal "0
|
|
26
|
+
assert_equal "0", ticker[:minimum_base_size] # deprecated minQty (0.00001) ignored
|
|
27
27
|
assert_equal "1", ticker[:minimum_quote_size]
|
|
28
28
|
assert_equal "500", ticker[:maximum_base_size]
|
|
29
29
|
assert_equal 5, ticker[:base_decimals]
|
|
@@ -54,8 +54,60 @@ class Honeymaker::Exchanges::BitgetTest < Minitest::Test
|
|
|
54
54
|
assert_equal BigDecimal("67125.67"), result.data[:ask]
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
def test_usdt_minimum_on_a_usdt_pair_is_not_converted_and_no_prices_are_read
|
|
58
|
+
connection = stub
|
|
59
|
+
connection.expects(:get).with("/api/v2/spot/public/symbols").returns(stub(body: load_fixture("bitget_symbols.json")))
|
|
60
|
+
@exchange.instance_variable_set(:@connection, connection)
|
|
61
|
+
|
|
62
|
+
assert_equal "5", @exchange.get_tickers_info.data.first[:minimum_quote_size]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_non_usdt_quote_converted_at_the_quotes_own_usdt_price
|
|
66
|
+
tickers = [{ "symbol" => "BTCUSDT", "lastPr" => "50000" },
|
|
67
|
+
{ "symbol" => "ETHBTC", "lastPr" => "0.05" }] # the traded pair's price: never used
|
|
68
|
+
data = quote_minimums({ "ETHBTC" => "BTC" }, tickers)
|
|
69
|
+
assert_equal BigDecimal("0.0001"), BigDecimal(data["ETHBTC"])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_inverse_usdt_quote_pair_multiplies
|
|
73
|
+
data = quote_minimums({ "BTCTRY" => "TRY" }, [{ "symbol" => "USDTTRY", "lastPr" => "40" }])
|
|
74
|
+
assert_equal BigDecimal("200"), BigDecimal(data["BTCTRY"])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_missing_price_leaves_the_minimum_to_the_venue
|
|
78
|
+
data = quote_minimums({ "ETHBTC" => "BTC", "XEUR" => "EUR" },
|
|
79
|
+
[{ "symbol" => "BTCUSDT", "lastPr" => "0" }, { "symbol" => "ETHBTC", "lastPr" => "0.05" }])
|
|
80
|
+
assert_equal "0", data["ETHBTC"]
|
|
81
|
+
assert_equal "0", data["XEUR"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_failed_price_read_falls_back_like_a_missing_price
|
|
85
|
+
data = quote_minimums({ "ETHBTC" => "BTC", "BTCUSDT" => "USDT" }, Faraday::ServerError.new("boom"))
|
|
86
|
+
assert_equal "0", data["ETHBTC"]
|
|
87
|
+
assert_equal "5", data["BTCUSDT"]
|
|
88
|
+
end
|
|
89
|
+
|
|
57
90
|
private
|
|
58
91
|
|
|
92
|
+
# symbol => quote rows, each with minTradeUSDT 5; tickers is the market's ticker list or the
|
|
93
|
+
# error its read raises. Returns symbol => minimum_quote_size.
|
|
94
|
+
def quote_minimums(pairs, tickers)
|
|
95
|
+
products = pairs.map do |symbol, quote|
|
|
96
|
+
load_fixture("bitget_symbols.json")["data"].first.merge("symbol" => symbol, "quoteCoin" => quote, "minTradeUSDT" => "5")
|
|
97
|
+
end
|
|
98
|
+
connection = stub
|
|
99
|
+
connection.stubs(:get).with("/api/v2/spot/public/symbols").returns(stub(body: { "data" => products }))
|
|
100
|
+
if tickers.is_a?(Exception)
|
|
101
|
+
connection.stubs(:get).with("/api/v2/spot/market/tickers").raises(tickers)
|
|
102
|
+
else
|
|
103
|
+
connection.stubs(:get).with("/api/v2/spot/market/tickers").returns(stub(body: { "data" => tickers }))
|
|
104
|
+
end
|
|
105
|
+
@exchange.instance_variable_set(:@connection, connection)
|
|
106
|
+
result = @exchange.get_tickers_info
|
|
107
|
+
assert result.success?, result.errors.inspect
|
|
108
|
+
result.data.to_h { |t| [t[:ticker], t[:minimum_quote_size]] }
|
|
109
|
+
end
|
|
110
|
+
|
|
59
111
|
def stub_connection(body)
|
|
60
112
|
response = stub(body: body)
|
|
61
113
|
connection = stub
|
|
@@ -123,6 +123,18 @@ class Honeymaker::Exchanges::KrakenTest < Minitest::Test
|
|
|
123
123
|
assert_equal "5", ticker[:minimum_quote_size]
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
def test_cost_floor_is_a_max_of_published_and_floor
|
|
127
|
+
body = load_fixture("kraken_asset_pairs.json")
|
|
128
|
+
key, info = body["result"].find { |_, i| i["wsname"]&.end_with?("/USDT") }
|
|
129
|
+
body["result"] = { key => info.merge("costmin" => "0.5") }
|
|
130
|
+
stub_request(body)
|
|
131
|
+
assert_equal "5", @exchange.get_tickers_info.data.first[:minimum_quote_size]
|
|
132
|
+
|
|
133
|
+
body["result"] = { key => info.merge("costmin" => "12.5") }
|
|
134
|
+
stub_request(body)
|
|
135
|
+
assert_equal "12.5", @exchange.get_tickers_info.data.first[:minimum_quote_size]
|
|
136
|
+
end
|
|
137
|
+
|
|
126
138
|
def test_get_tickers_info_handles_api_error
|
|
127
139
|
body = { "error" => ["EGeneral:Internal error"], "result" => {} }
|
|
128
140
|
stub_request(body)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class Honeymaker::FloorsTest < Minitest::Test
|
|
6
|
+
F = Honeymaker::Floors
|
|
7
|
+
|
|
8
|
+
def test_max_of_published_and_floor
|
|
9
|
+
assert_equal 5, F.minimum_quote(venue: "kraken", quote: "USD", published: "0.5")
|
|
10
|
+
assert_equal "12.5", F.minimum_quote(venue: "kraken", quote: "USD", published: "12.5")
|
|
11
|
+
assert_equal 5, F.minimum_quote(venue: "kraken", quote: "USD", published: "5.0") # tie: the floor
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_missing_or_unreadable_published_gives_the_floor
|
|
15
|
+
assert_equal 5, F.minimum_quote(venue: "kraken", quote: "USD")
|
|
16
|
+
assert_equal 5, F.minimum_quote(venue: "kraken", quote: "USD", published: "abc")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_no_floor_keeps_published
|
|
20
|
+
assert_equal "0.1", F.minimum_quote(venue: "kraken", quote: "FOO", published: "0.1")
|
|
21
|
+
assert_equal "3", F.minimum_quote(venue: "binance", quote: "USDT", published: "3")
|
|
22
|
+
assert_nil F.minimum_quote(venue: "binance", quote: "USDT")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_alpaca_floor_is_keyed_by_asset_class
|
|
26
|
+
assert_equal 10, F.minimum_quote(venue: "alpaca", quote: "USD", asset_class: "crypto", published: "1")
|
|
27
|
+
assert_equal 10, F.minimum_quote(venue: :alpaca, quote: "USD", asset_class: :crypto)
|
|
28
|
+
assert_equal "1", F.minimum_quote(venue: "alpaca", quote: "USD", asset_class: "stock", published: "1")
|
|
29
|
+
assert_nil F.minimum_quote(venue: "alpaca", quote: "USD", asset_class: "stock")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_hyperliquid_floor_covers_every_quote
|
|
33
|
+
assert_equal 10, F.minimum_quote(venue: "hyperliquid", quote: "USDC")
|
|
34
|
+
assert_equal 10, F.minimum_quote(venue: "hyperliquid", quote: "USDT0", published: "1")
|
|
35
|
+
assert_equal "25", F.minimum_quote(venue: "hyperliquid", quote: "USDC", published: "25")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -43,6 +43,32 @@ class KrakenExchangeParityTest < Minitest::Test
|
|
|
43
43
|
[500, JSON_CT, "{}"]].each { |reply| assert_parity(reply, &:get_tickers_info) }
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# The native REAL_COSTMIN mirrors Honeymaker::Floors: every floored quote, published below,
|
|
47
|
+
# above, equal to, missing and unreadable, plus an unfloored quote.
|
|
48
|
+
def test_cost_floors_match_the_shared_table
|
|
49
|
+
floors = Honeymaker::Floors::MINIMUM_QUOTE[["kraken", nil]]
|
|
50
|
+
pairs = {}
|
|
51
|
+
(floors.keys + ["FOO"]).each do |quote|
|
|
52
|
+
floor = floors[quote] || 1
|
|
53
|
+
[(BigDecimal(floor.to_s) / 10).to_s("F"), (BigDecimal(floor.to_s) * 10).to_s("F"), floor.to_s, nil, "abc", floor * 3].each_with_index do |costmin, i|
|
|
54
|
+
ws = "B#{i}/#{quote}"
|
|
55
|
+
pairs[ws] = { "altname" => ws, "wsname" => ws, "costmin" => costmin }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
reply = [200, JSON_CT, { "error" => [], "result" => pairs }.to_json]
|
|
59
|
+
assert_parity(reply, &:get_tickers_info)
|
|
60
|
+
|
|
61
|
+
d = VenueDouble.new([reply])
|
|
62
|
+
e = Honeymaker::Native::KrakenExchange.new
|
|
63
|
+
e.instance_variable_set(:@connection, e.send(:build_connection, d.url))
|
|
64
|
+
got = e.get_tickers_info.data.to_h { |t| [t[:ticker], t[:minimum_quote_size]] }
|
|
65
|
+
assert_equal floors["USD"].to_s, got["B0/USD"]
|
|
66
|
+
assert_equal "50.0", got["B1/USD"]
|
|
67
|
+
assert_equal "0.1", got["B0/FOO"]
|
|
68
|
+
ensure
|
|
69
|
+
d&.close
|
|
70
|
+
end
|
|
71
|
+
|
|
46
72
|
def test_one_malformed_row_fails_the_whole_catalogue_like_legacy
|
|
47
73
|
replies = [false, 1, { "x" => 1 }].map do |bad|
|
|
48
74
|
pairs = { "XXBTZUSD" => { "altname" => "XBTUSD", "wsname" => "XBT/USD", "status" => "online" },
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: honeymaker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.12.
|
|
4
|
+
version: 0.12.6
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Deltabadger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -131,6 +131,7 @@ files:
|
|
|
131
131
|
- lib/honeymaker/exchanges/kraken.rb
|
|
132
132
|
- lib/honeymaker/exchanges/kucoin.rb
|
|
133
133
|
- lib/honeymaker/exchanges/mexc.rb
|
|
134
|
+
- lib/honeymaker/floors.rb
|
|
134
135
|
- lib/honeymaker/native.rb
|
|
135
136
|
- lib/honeymaker/native/kraken.rb
|
|
136
137
|
- lib/honeymaker/result.rb
|
|
@@ -204,6 +205,7 @@ files:
|
|
|
204
205
|
- test/honeymaker/exchanges/kraken_test.rb
|
|
205
206
|
- test/honeymaker/exchanges/kucoin_test.rb
|
|
206
207
|
- test/honeymaker/exchanges/mexc_test.rb
|
|
208
|
+
- test/honeymaker/floors_test.rb
|
|
207
209
|
- test/honeymaker/honeymaker_test.rb
|
|
208
210
|
- test/honeymaker/result_test.rb
|
|
209
211
|
- test/honeymaker/utils_test.rb
|