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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e80ebeeb8222d978465b6fca4f757d13eeae098395f99c2ec2223196c55c2b4b
|
|
4
|
+
data.tar.gz: 5f00b757a6872a409bdce15b5e77c7370148195397b5827064e49b0f57379ea6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 428f23c82dd3d1ae22f5fa05f00cd0036691fd397541b058d541ac7f5ba09936a464959a8c81ff11fa46ccab1c68fbfefe4d8fe7f97f06084fb32aca6e994112
|
|
7
|
+
data.tar.gz: a79cbc1061092903465d37be4f1a0627332a05f583bbbd3289b1f46319e76623ad99563f13d2101dcdb9eb07cabc5038d50ec8a9229dc12c1bc32c719f2dd877
|
|
Binary file
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
require "base64"
|
|
5
|
+
require "securerandom"
|
|
6
|
+
|
|
7
|
+
module Honeymaker
|
|
8
|
+
class Client
|
|
9
|
+
OPTIONS = {
|
|
10
|
+
request: {
|
|
11
|
+
open_timeout: 5,
|
|
12
|
+
read_timeout: 30,
|
|
13
|
+
write_timeout: 10
|
|
14
|
+
}
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
attr_reader :api_key, :api_secret
|
|
18
|
+
|
|
19
|
+
def initialize(api_key: nil, api_secret: nil, proxy: nil, logger: nil)
|
|
20
|
+
@api_key = api_key
|
|
21
|
+
@api_secret = api_secret
|
|
22
|
+
@proxy = proxy
|
|
23
|
+
@logger = logger
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def with_rescue
|
|
29
|
+
Result::Success.new(yield)
|
|
30
|
+
rescue Faraday::Error => e
|
|
31
|
+
body = e.respond_to?(:response_body) ? e.response_body : nil
|
|
32
|
+
error_message = (body && !body.empty?) ? body : e.message.to_s
|
|
33
|
+
error_message = "Unknown API error" if error_message.nil? || error_message.empty?
|
|
34
|
+
status = e.respond_to?(:response_status) ? e.response_status : nil
|
|
35
|
+
Result::Failure.new(error_message, data: { status: status })
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
msg = e.message
|
|
38
|
+
Result::Failure.new((msg && !msg.empty?) ? msg : "Unknown error")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def connection
|
|
42
|
+
@connection ||= build_client_connection(self.class::URL)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def build_client_connection(url, content_type_match: nil)
|
|
46
|
+
Faraday.new(url: url, **OPTIONS) do |config|
|
|
47
|
+
config.proxy = @proxy if @proxy
|
|
48
|
+
config.request :json
|
|
49
|
+
if content_type_match
|
|
50
|
+
config.response :json, content_type: content_type_match
|
|
51
|
+
else
|
|
52
|
+
config.response :json
|
|
53
|
+
end
|
|
54
|
+
config.response :raise_error
|
|
55
|
+
config.response :logger, @logger, headers: false, bodies: false, log_level: :debug if @logger
|
|
56
|
+
config.adapter :net_http_persistent do |http|
|
|
57
|
+
http.idle_timeout = 100
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def authenticated?
|
|
63
|
+
@api_key && !@api_key.empty? && @api_secret && !@api_secret.empty?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def timestamp_ms
|
|
67
|
+
(Time.now.utc.to_f * 1_000).to_i
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def hmac_sha256(secret, data)
|
|
71
|
+
OpenSSL::HMAC.hexdigest("sha256", secret, data)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Honeymaker
|
|
4
|
+
module Clients
|
|
5
|
+
class Binance < Client
|
|
6
|
+
URL = "https://api.binance.com"
|
|
7
|
+
|
|
8
|
+
def exchange_information(symbol: nil, symbols: nil, permissions: nil, show_permission_sets: nil, symbol_status: nil)
|
|
9
|
+
with_rescue do
|
|
10
|
+
response = connection.get do |req|
|
|
11
|
+
req.url "/api/v3/exchangeInfo"
|
|
12
|
+
req.headers = headers
|
|
13
|
+
req.params = {
|
|
14
|
+
symbol: symbol,
|
|
15
|
+
symbols: symbols&.to_json,
|
|
16
|
+
permissions: permissions&.to_json,
|
|
17
|
+
showPermissionSets: show_permission_sets,
|
|
18
|
+
symbolStatus: symbol_status
|
|
19
|
+
}.compact
|
|
20
|
+
end
|
|
21
|
+
response.body
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def symbol_price_ticker(symbol: nil, symbols: nil)
|
|
26
|
+
with_rescue do
|
|
27
|
+
response = connection.get do |req|
|
|
28
|
+
req.url "/api/v3/ticker/price"
|
|
29
|
+
req.headers = headers
|
|
30
|
+
req.params = { symbol: symbol, symbols: symbols&.to_json }.compact
|
|
31
|
+
end
|
|
32
|
+
response.body
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def symbol_order_book_ticker(symbol: nil, symbols: nil)
|
|
37
|
+
with_rescue do
|
|
38
|
+
response = connection.get do |req|
|
|
39
|
+
req.url "/api/v3/ticker/bookTicker"
|
|
40
|
+
req.headers = headers
|
|
41
|
+
req.params = { symbol: symbol, symbols: symbols&.to_json }.compact
|
|
42
|
+
end
|
|
43
|
+
response.body
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def candlestick_data(symbol:, interval:, start_time: nil, end_time: nil, time_zone: 0, limit: 500)
|
|
48
|
+
with_rescue do
|
|
49
|
+
response = connection.get do |req|
|
|
50
|
+
req.url "/api/v3/klines"
|
|
51
|
+
req.headers = headers
|
|
52
|
+
req.params = {
|
|
53
|
+
symbol: symbol, interval: interval,
|
|
54
|
+
startTime: start_time, endTime: end_time,
|
|
55
|
+
timeZone: time_zone, limit: limit
|
|
56
|
+
}.compact
|
|
57
|
+
end
|
|
58
|
+
response.body
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def account_information(omit_zero_balances: false, recv_window: 5000)
|
|
63
|
+
with_rescue do
|
|
64
|
+
response = connection.get do |req|
|
|
65
|
+
req.url "/api/v3/account"
|
|
66
|
+
req.headers = headers
|
|
67
|
+
req.params = {
|
|
68
|
+
omitZeroBalances: omit_zero_balances,
|
|
69
|
+
recvWindow: recv_window,
|
|
70
|
+
timestamp: timestamp_ms
|
|
71
|
+
}.compact
|
|
72
|
+
req.params[:signature] = sign_params(req.params)
|
|
73
|
+
end
|
|
74
|
+
response.body
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def account_trade_list(symbol:, order_id: nil, start_time: nil, end_time: nil, from_id: nil, limit: 500, recv_window: 5000)
|
|
79
|
+
with_rescue do
|
|
80
|
+
response = connection.get do |req|
|
|
81
|
+
req.url "/api/v3/myTrades"
|
|
82
|
+
req.headers = headers
|
|
83
|
+
req.params = {
|
|
84
|
+
symbol: symbol, orderId: order_id,
|
|
85
|
+
startTime: start_time, endTime: end_time,
|
|
86
|
+
fromId: from_id, limit: limit,
|
|
87
|
+
recvWindow: recv_window, timestamp: timestamp_ms
|
|
88
|
+
}.compact
|
|
89
|
+
req.params[:signature] = sign_params(req.params)
|
|
90
|
+
end
|
|
91
|
+
response.body
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def query_order(symbol:, order_id: nil, orig_client_order_id: nil, recv_window: 5000)
|
|
96
|
+
with_rescue do
|
|
97
|
+
response = connection.get do |req|
|
|
98
|
+
req.url "/api/v3/order"
|
|
99
|
+
req.headers = headers
|
|
100
|
+
req.params = {
|
|
101
|
+
symbol: symbol, orderId: order_id,
|
|
102
|
+
origClientOrderId: orig_client_order_id,
|
|
103
|
+
recvWindow: recv_window, timestamp: timestamp_ms
|
|
104
|
+
}.compact
|
|
105
|
+
req.params[:signature] = sign_params(req.params)
|
|
106
|
+
end
|
|
107
|
+
response.body
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def all_orders(symbol:, order_id: nil, start_time: nil, end_time: nil, limit: 500, recv_window: 5000)
|
|
112
|
+
with_rescue do
|
|
113
|
+
response = connection.get do |req|
|
|
114
|
+
req.url "/api/v3/allOrders"
|
|
115
|
+
req.headers = headers
|
|
116
|
+
req.params = {
|
|
117
|
+
symbol: symbol, orderId: order_id,
|
|
118
|
+
startTime: start_time, endTime: end_time,
|
|
119
|
+
limit: limit, recvWindow: recv_window, timestamp: timestamp_ms
|
|
120
|
+
}.compact
|
|
121
|
+
req.params[:signature] = sign_params(req.params)
|
|
122
|
+
end
|
|
123
|
+
response.body
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def new_order(symbol:, side:, type:, time_in_force: nil, quantity: nil, quote_order_qty: nil,
|
|
128
|
+
price: nil, new_client_order_id: nil, strategy_id: nil, strategy_type: nil,
|
|
129
|
+
stop_price: nil, trailing_delta: nil, iceberg_qty: nil, new_order_resp_type: nil,
|
|
130
|
+
self_trade_prevention_mode: nil, recv_window: 5000)
|
|
131
|
+
with_rescue do
|
|
132
|
+
response = connection.post do |req|
|
|
133
|
+
req.url "/api/v3/order"
|
|
134
|
+
req.headers = headers
|
|
135
|
+
req.params = {
|
|
136
|
+
symbol: symbol, side: side, type: type,
|
|
137
|
+
timeInForce: time_in_force, quantity: quantity,
|
|
138
|
+
quoteOrderQty: quote_order_qty, price: price,
|
|
139
|
+
newClientOrderId: new_client_order_id,
|
|
140
|
+
strategyId: strategy_id, strategyType: strategy_type,
|
|
141
|
+
stopPrice: stop_price, trailingDelta: trailing_delta,
|
|
142
|
+
icebergQty: iceberg_qty, newOrderRespType: new_order_resp_type,
|
|
143
|
+
selfTradePreventionMode: self_trade_prevention_mode,
|
|
144
|
+
recvWindow: recv_window, timestamp: timestamp_ms
|
|
145
|
+
}.compact
|
|
146
|
+
req.params[:signature] = sign_params(req.params)
|
|
147
|
+
end
|
|
148
|
+
response.body
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def cancel_order(symbol:, order_id: nil, orig_client_order_id: nil, new_client_order_id: nil,
|
|
153
|
+
cancel_restrictions: nil, recv_window: 5000)
|
|
154
|
+
with_rescue do
|
|
155
|
+
response = connection.delete do |req|
|
|
156
|
+
req.url "/api/v3/order"
|
|
157
|
+
req.headers = headers
|
|
158
|
+
req.params = {
|
|
159
|
+
symbol: symbol, orderId: order_id,
|
|
160
|
+
origClientOrderId: orig_client_order_id,
|
|
161
|
+
newClientOrderId: new_client_order_id,
|
|
162
|
+
cancelRestrictions: cancel_restrictions,
|
|
163
|
+
recvWindow: recv_window, timestamp: timestamp_ms
|
|
164
|
+
}.compact
|
|
165
|
+
req.params[:signature] = sign_params(req.params)
|
|
166
|
+
end
|
|
167
|
+
response.body
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def get_all_coins_information(recv_window: 5000)
|
|
172
|
+
with_rescue do
|
|
173
|
+
response = connection.get do |req|
|
|
174
|
+
req.url "/sapi/v1/capital/config/getall"
|
|
175
|
+
req.headers = headers
|
|
176
|
+
req.params = { recvWindow: recv_window, timestamp: timestamp_ms }
|
|
177
|
+
req.params[:signature] = sign_params(req.params)
|
|
178
|
+
end
|
|
179
|
+
response.body
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def api_description(recv_window: 5000)
|
|
184
|
+
with_rescue do
|
|
185
|
+
response = connection.get do |req|
|
|
186
|
+
req.url "/sapi/v1/account/apiRestrictions"
|
|
187
|
+
req.headers = headers
|
|
188
|
+
req.params = { recvWindow: recv_window, timestamp: timestamp_ms }
|
|
189
|
+
req.params[:signature] = sign_params(req.params)
|
|
190
|
+
end
|
|
191
|
+
response.body
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def get_withdraw_addresses(recv_window: 5000)
|
|
196
|
+
with_rescue do
|
|
197
|
+
response = connection.get do |req|
|
|
198
|
+
req.url "/sapi/v1/capital/withdraw/address/list"
|
|
199
|
+
req.headers = headers
|
|
200
|
+
req.params = { recvWindow: recv_window, timestamp: timestamp_ms }
|
|
201
|
+
req.params[:signature] = sign_params(req.params)
|
|
202
|
+
end
|
|
203
|
+
response.body
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def withdraw(coin:, address:, amount:, network: nil, address_tag: nil, recv_window: 5000)
|
|
208
|
+
with_rescue do
|
|
209
|
+
response = connection.post do |req|
|
|
210
|
+
req.url "/sapi/v1/capital/withdraw/apply"
|
|
211
|
+
req.headers = headers
|
|
212
|
+
req.params = {
|
|
213
|
+
coin: coin, address: address, amount: amount,
|
|
214
|
+
network: network, addressTag: address_tag,
|
|
215
|
+
recvWindow: recv_window, timestamp: timestamp_ms
|
|
216
|
+
}.compact
|
|
217
|
+
req.params[:signature] = sign_params(req.params)
|
|
218
|
+
end
|
|
219
|
+
response.body
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
private
|
|
224
|
+
|
|
225
|
+
def headers
|
|
226
|
+
if authenticated?
|
|
227
|
+
{ "X-MBX-APIKEY": @api_key, Accept: "application/json", "Content-Type": "application/json" }
|
|
228
|
+
else
|
|
229
|
+
{ Accept: "application/json", "Content-Type": "application/json" }
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def sign_params(params)
|
|
234
|
+
return unless @api_secret
|
|
235
|
+
query = Faraday::Utils.build_query(params)
|
|
236
|
+
hmac_sha256(@api_secret, query)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Honeymaker
|
|
4
|
+
module Clients
|
|
5
|
+
class BingX < Client
|
|
6
|
+
URL = "https://open-api.bingx.com"
|
|
7
|
+
|
|
8
|
+
def get_symbols
|
|
9
|
+
get_public("/openApi/spot/v1/common/symbols")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_ticker(symbol: nil)
|
|
13
|
+
get_public("/openApi/spot/v2/market/ticker", { symbol: symbol })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def get_depth(symbol:, limit: nil)
|
|
17
|
+
get_public("/openApi/spot/v1/market/depth", { symbol: symbol, limit: limit })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def get_klines(symbol:, interval:, start_time: nil, end_time: nil, limit: nil)
|
|
21
|
+
get_public("/openApi/spot/v1/market/kline", {
|
|
22
|
+
symbol: symbol, interval: interval,
|
|
23
|
+
startTime: start_time, endTime: end_time, limit: limit
|
|
24
|
+
})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_balances
|
|
28
|
+
get_signed("/openApi/spot/v1/account/balance")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def place_order(symbol:, side:, type:, quantity: nil, quote_order_qty: nil, price: nil,
|
|
32
|
+
time_in_force: nil, client_order_id: nil)
|
|
33
|
+
post_signed("/openApi/spot/v1/trade/order", {
|
|
34
|
+
symbol: symbol, side: side, type: type,
|
|
35
|
+
quantity: quantity, quoteOrderQty: quote_order_qty,
|
|
36
|
+
price: price, timeInForce: time_in_force,
|
|
37
|
+
newClientOrderId: client_order_id
|
|
38
|
+
})
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def get_order(symbol:, order_id: nil, client_order_id: nil)
|
|
42
|
+
get_signed("/openApi/spot/v1/trade/query", {
|
|
43
|
+
symbol: symbol, orderId: order_id, clientOrderID: client_order_id
|
|
44
|
+
})
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def cancel_order(symbol:, order_id: nil, client_order_id: nil)
|
|
48
|
+
post_signed("/openApi/spot/v1/trade/cancel", {
|
|
49
|
+
symbol: symbol, orderId: order_id, clientOrderID: client_order_id
|
|
50
|
+
})
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def withdraw(coin:, address:, amount:, network: nil, wallet_type: nil, tag: nil)
|
|
54
|
+
post_signed("/openApi/wallets/v1/capital/withdraw/apply", {
|
|
55
|
+
coin: coin, address: address, amount: amount,
|
|
56
|
+
network: network, walletType: wallet_type, tag: tag
|
|
57
|
+
})
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def get_public(path, params = {})
|
|
63
|
+
with_rescue do
|
|
64
|
+
response = connection.get do |req|
|
|
65
|
+
req.url path
|
|
66
|
+
req.params = params.compact
|
|
67
|
+
end
|
|
68
|
+
response.body
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def get_signed(path, params = {})
|
|
73
|
+
with_rescue do
|
|
74
|
+
params = params.compact.merge(timestamp: timestamp_ms)
|
|
75
|
+
params[:signature] = hmac_sha256(@api_secret, Faraday::Utils.build_query(params))
|
|
76
|
+
|
|
77
|
+
response = connection.get do |req|
|
|
78
|
+
req.url path
|
|
79
|
+
req.headers = { "X-BX-APIKEY": @api_key }
|
|
80
|
+
req.params = params
|
|
81
|
+
end
|
|
82
|
+
response.body
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def post_signed(path, params = {})
|
|
87
|
+
with_rescue do
|
|
88
|
+
params = params.compact.merge(timestamp: timestamp_ms)
|
|
89
|
+
params[:signature] = hmac_sha256(@api_secret, Faraday::Utils.build_query(params))
|
|
90
|
+
|
|
91
|
+
response = connection.post do |req|
|
|
92
|
+
req.url path
|
|
93
|
+
req.headers = { "X-BX-APIKEY": @api_key, "Content-Type": "application/json" }
|
|
94
|
+
req.params = params
|
|
95
|
+
end
|
|
96
|
+
response.body
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def connection
|
|
101
|
+
@connection ||= build_client_connection(URL, content_type_match: //)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Honeymaker
|
|
4
|
+
module Clients
|
|
5
|
+
class Bitget < Client
|
|
6
|
+
URL = "https://api.bitget.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_coins
|
|
16
|
+
get_public("/api/v2/spot/public/coins")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_symbols
|
|
20
|
+
get_public("/api/v2/spot/public/symbols")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_tickers(symbol: nil)
|
|
24
|
+
get_public("/api/v2/spot/market/tickers", { symbol: symbol })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_orderbook(symbol:, limit: nil)
|
|
28
|
+
get_public("/api/v2/spot/market/orderbook", { symbol: symbol, limit: limit })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get_candles(symbol:, granularity:, start_time: nil, end_time: nil, limit: nil)
|
|
32
|
+
get_public("/api/v2/spot/market/candles", {
|
|
33
|
+
symbol: symbol, granularity: granularity,
|
|
34
|
+
startTime: start_time, endTime: end_time, limit: limit
|
|
35
|
+
})
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get_account_assets(coin: nil)
|
|
39
|
+
get_signed("/api/v2/spot/account/assets", { coin: coin })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def place_order(symbol:, side:, order_type:, size:, price: nil, force: nil, client_oid: nil)
|
|
43
|
+
post_signed("/api/v2/spot/trade/place-order", {
|
|
44
|
+
symbol: symbol, side: side, orderType: order_type,
|
|
45
|
+
size: size, price: price, force: force, clientOid: client_oid
|
|
46
|
+
})
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def get_order(order_id: nil, client_oid: nil)
|
|
50
|
+
get_signed("/api/v2/spot/trade/orderInfo", { orderId: order_id, clientOid: client_oid })
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def cancel_order(symbol:, order_id: nil, client_oid: nil)
|
|
54
|
+
post_signed("/api/v2/spot/trade/cancel-order", {
|
|
55
|
+
symbol: symbol, orderId: order_id, clientOid: client_oid
|
|
56
|
+
})
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def withdraw(coin:, transfer_type:, address:, size:, chain: nil, tag: nil, client_oid: nil)
|
|
60
|
+
post_signed("/api/v2/spot/wallet/withdrawal", {
|
|
61
|
+
coin: coin, transferType: transfer_type, address: address,
|
|
62
|
+
size: size, chain: chain, tag: tag, clientOid: client_oid
|
|
63
|
+
})
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def get_public(path, params = {})
|
|
69
|
+
with_rescue do
|
|
70
|
+
response = connection.get do |req|
|
|
71
|
+
req.url path
|
|
72
|
+
req.headers = unauthenticated_headers
|
|
73
|
+
req.params = params.compact
|
|
74
|
+
end
|
|
75
|
+
response.body
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_signed(path, params = {})
|
|
80
|
+
with_rescue do
|
|
81
|
+
params = params.compact
|
|
82
|
+
query_string = params.empty? ? "" : "?#{Faraday::Utils.build_query(params)}"
|
|
83
|
+
ts = timestamp_ms.to_s
|
|
84
|
+
pre_sign = "#{ts}GET#{path}#{query_string}"
|
|
85
|
+
|
|
86
|
+
response = connection.get do |req|
|
|
87
|
+
req.url path
|
|
88
|
+
req.headers = signed_headers(ts, pre_sign)
|
|
89
|
+
req.params = params
|
|
90
|
+
end
|
|
91
|
+
response.body
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def post_signed(path, body = {})
|
|
96
|
+
with_rescue do
|
|
97
|
+
body = body.compact
|
|
98
|
+
ts = timestamp_ms.to_s
|
|
99
|
+
pre_sign = "#{ts}POST#{path}#{body.to_json}"
|
|
100
|
+
|
|
101
|
+
response = connection.post do |req|
|
|
102
|
+
req.url path
|
|
103
|
+
req.headers = signed_headers(ts, pre_sign)
|
|
104
|
+
req.body = body
|
|
105
|
+
end
|
|
106
|
+
response.body
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def unauthenticated_headers
|
|
111
|
+
{ Accept: "application/json", "Content-Type": "application/json" }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def signed_headers(timestamp, pre_sign)
|
|
115
|
+
mac = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", @api_secret, pre_sign))
|
|
116
|
+
{
|
|
117
|
+
"ACCESS-KEY": @api_key,
|
|
118
|
+
"ACCESS-SIGN": mac,
|
|
119
|
+
"ACCESS-TIMESTAMP": timestamp,
|
|
120
|
+
"ACCESS-PASSPHRASE": @passphrase,
|
|
121
|
+
Accept: "application/json",
|
|
122
|
+
"Content-Type": "application/json",
|
|
123
|
+
locale: "en-US"
|
|
124
|
+
}
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Honeymaker
|
|
4
|
+
module Clients
|
|
5
|
+
class BitMart < Client
|
|
6
|
+
URL = "https://api-cloud.bitmart.com"
|
|
7
|
+
|
|
8
|
+
attr_reader :memo
|
|
9
|
+
|
|
10
|
+
def initialize(api_key: nil, api_secret: nil, memo: nil, proxy: nil, logger: nil)
|
|
11
|
+
super(api_key: api_key, api_secret: api_secret, proxy: proxy, logger: logger)
|
|
12
|
+
@memo = memo
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def get_symbols_details
|
|
16
|
+
get_public("/spot/v1/symbols/details")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_ticker(symbol: nil)
|
|
20
|
+
get_public("/spot/quotation/v3/ticker", { symbol: symbol })
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_depth(symbol:, limit: nil)
|
|
24
|
+
get_public("/spot/quotation/v3/books", { symbol: symbol, limit: limit })
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_klines(symbol:, step:, before: nil, after_time: nil, limit: nil)
|
|
28
|
+
get_public("/spot/quotation/v3/lite-klines", {
|
|
29
|
+
symbol: symbol, step: step, before: before, after: after_time, limit: limit
|
|
30
|
+
})
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_wallet
|
|
34
|
+
get_signed("/spot/v1/wallet")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def submit_order(symbol:, side:, type:, size: nil, notional: nil, price: nil, client_order_id: nil)
|
|
38
|
+
post_signed("/spot/v2/submit_order", {
|
|
39
|
+
symbol: symbol, side: side, type: type,
|
|
40
|
+
size: size, notional: notional, price: price,
|
|
41
|
+
client_order_id: client_order_id
|
|
42
|
+
})
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def get_order(order_id:)
|
|
46
|
+
post_signed("/spot/v2/order_detail", { orderId: order_id })
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cancel_order(symbol:, order_id: nil, client_order_id: nil)
|
|
50
|
+
post_signed("/spot/v3/cancel_order", {
|
|
51
|
+
symbol: symbol, order_id: order_id, client_order_id: client_order_id
|
|
52
|
+
})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def withdraw(currency:, amount:, address:, address_memo: nil, destination: nil)
|
|
56
|
+
post_signed("/account/v1/withdraw/apply", {
|
|
57
|
+
currency: currency, amount: amount,
|
|
58
|
+
destination: destination || "To Digital Address",
|
|
59
|
+
address: address, address_memo: address_memo
|
|
60
|
+
})
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def get_public(path, params = {})
|
|
66
|
+
with_rescue do
|
|
67
|
+
response = connection.get do |req|
|
|
68
|
+
req.url path
|
|
69
|
+
req.params = params.compact
|
|
70
|
+
end
|
|
71
|
+
response.body
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_signed(path, params = {})
|
|
76
|
+
with_rescue do
|
|
77
|
+
ts = timestamp_ms.to_s
|
|
78
|
+
query_string = params.compact.empty? ? "" : "?#{Faraday::Utils.build_query(params.compact)}"
|
|
79
|
+
pre_sign = "#{ts}##{@memo}##{query_string}"
|
|
80
|
+
|
|
81
|
+
response = connection.get do |req|
|
|
82
|
+
req.url path
|
|
83
|
+
req.headers = signed_headers(ts, pre_sign)
|
|
84
|
+
req.params = params.compact
|
|
85
|
+
end
|
|
86
|
+
response.body
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def post_signed(path, body = {})
|
|
91
|
+
with_rescue do
|
|
92
|
+
ts = timestamp_ms.to_s
|
|
93
|
+
body_json = body.compact.to_json
|
|
94
|
+
pre_sign = "#{ts}##{@memo}##{body_json}"
|
|
95
|
+
|
|
96
|
+
response = connection.post do |req|
|
|
97
|
+
req.url path
|
|
98
|
+
req.headers = signed_headers(ts, pre_sign)
|
|
99
|
+
req.body = body.compact
|
|
100
|
+
end
|
|
101
|
+
response.body
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def signed_headers(timestamp, pre_sign)
|
|
106
|
+
signature = hmac_sha256(@api_secret, pre_sign)
|
|
107
|
+
{
|
|
108
|
+
"X-BM-KEY": @api_key,
|
|
109
|
+
"X-BM-SIGN": signature,
|
|
110
|
+
"X-BM-TIMESTAMP": timestamp,
|
|
111
|
+
Accept: "application/json",
|
|
112
|
+
"Content-Type": "application/json"
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|