marcel-binance 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 681a6d991592ad3bdb5d8c2e16c600c83d724ee1ec17946a0063a3cd1563f293
4
+ data.tar.gz: 0d50747b17a57e7cb6bf3210febef89337d60416f29a3be83d174b14aad66527
5
+ SHA512:
6
+ metadata.gz: f00c3b43942185d5ee9ba7c0e1354644b7b62df1e7894128afce666116e9caf90a0f0a4634a0c0622f8455c8b216481ecf8acf54fa8f905d053baa5a0e1b26f7
7
+ data.tar.gz: dfb7da75487d4fec9a83258c84e7d72d4ea04d374bcc347f32581cf8d2e9efd4544c7b76bab3798714a707fc69f64f91abfa6b995ce0cec3257e290bce9154ef
@@ -0,0 +1,106 @@
1
+ require 'faraday_middleware'
2
+
3
+ module Binance
4
+ module Client
5
+ class REST
6
+ BASE_URL = 'https://api.binance.com'.freeze
7
+
8
+ def public_client(adapter)
9
+ Faraday.new(url: "#{BASE_URL}/api") do |conn|
10
+ conn.request :json
11
+ conn.response :json, content_type: /\bjson$/
12
+ conn.adapter adapter
13
+ end
14
+ end
15
+
16
+ def verified_client(api_key, adapter)
17
+ Faraday.new(url: "#{BASE_URL}/api") do |conn|
18
+ conn.response :json, content_type: /\bjson$/
19
+ conn.headers['X-MBX-APIKEY'] = api_key
20
+ conn.adapter adapter
21
+ end
22
+ end
23
+
24
+ def signed_client(api_key, secret_key, adapter)
25
+ Faraday.new(url: "#{BASE_URL}/api") do |conn|
26
+ conn.request :json
27
+ conn.response :json, content_type: /\bjson$/
28
+ conn.headers['X-MBX-APIKEY'] = api_key
29
+ conn.use TimestampRequestMiddleware
30
+ conn.use SignRequestMiddleware, secret_key
31
+ conn.adapter adapter
32
+ end
33
+ end
34
+
35
+ def public_withdraw_client(adapter)
36
+ Faraday.new(url: "#{BASE_URL}/wapi") do |conn|
37
+ conn.request :json
38
+ conn.response :json, content_type: /\bjson$/
39
+ conn.adapter adapter
40
+ end
41
+ end
42
+
43
+ def withdraw_client(api_key, secret_key, adapter)
44
+ Faraday.new(url: "#{BASE_URL}/wapi") do |conn|
45
+ conn.request :url_encoded
46
+ conn.response :json, content_type: /\bjson$/
47
+ conn.headers['X-MBX-APIKEY'] = api_key
48
+ conn.use TimestampRequestMiddleware
49
+ conn.use SignRequestMiddleware, secret_key
50
+ conn.adapter adapter
51
+ end
52
+ end
53
+ end
54
+
55
+ class REST_FUTURE
56
+ BASE_URL = 'https://fapi.binance.com'.freeze
57
+ TEST_BASE_URL = 'https://testnet.binancefuture.com'.freeze
58
+ def public_client(adapter, test_api)
59
+ Faraday.new(url: "#{(test_api)? TEST_BASE_URL : BASE_URL}/fapi") do |conn|
60
+ conn.request :json
61
+ conn.response :json, content_type: /\bjson$/
62
+ conn.adapter adapter
63
+ end
64
+ end
65
+
66
+ def verified_client(api_key, adapter, test_api)
67
+ Faraday.new(url: "#{(test_api)? TEST_BASE_URL : BASE_URL}/fapi") do |conn|
68
+ conn.response :json, content_type: /\bjson$/
69
+ conn.headers['X-MBX-APIKEY'] = api_key
70
+ conn.adapter adapter
71
+ end
72
+ end
73
+
74
+ def signed_client(api_key, secret_key, adapter, test_api)
75
+ Faraday.new(url: "#{(test_api)? TEST_BASE_URL : BASE_URL}/fapi") do |conn|
76
+ conn.request :json
77
+ conn.response :json, content_type: /\bjson$/
78
+ conn.headers['X-MBX-APIKEY'] = api_key
79
+ conn.use TimestampRequestMiddleware
80
+ conn.use SignRequestMiddleware, secret_key
81
+ conn.adapter adapter
82
+ end
83
+ end
84
+
85
+ def public_withdraw_client(adapter, test_api)
86
+ Faraday.new(url: "#{(test_api)? TEST_BASE_URL : BASE_URL}/wapi") do |conn|
87
+ conn.request :json
88
+ conn.response :json, content_type: /\bjson$/
89
+ conn.adapter adapter
90
+ end
91
+ end
92
+
93
+ def withdraw_client(api_key, secret_key, adapter, test_api)
94
+ Faraday.new(url: "#{(test_api)? TEST_BASE_URL : BASE_URL}/wapi") do |conn|
95
+ conn.request :url_encoded
96
+ conn.response :json, content_type: /\bjson$/
97
+ conn.headers['X-MBX-APIKEY'] = api_key
98
+ conn.use TimestampRequestMiddleware
99
+ conn.use SignRequestMiddleware, secret_key
100
+ conn.adapter adapter
101
+ end
102
+ end
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,87 @@
1
+ module Binance
2
+ module Client
3
+ class REST
4
+ ENDPOINTS = {
5
+ # Public API Endpoints
6
+ ping: 'v1/ping',
7
+ time: 'v1/time',
8
+ exchange_info: 'v1/exchangeInfo',
9
+ depth: 'v1/depth',
10
+ trades: 'v1/trades',
11
+ historical_trades: 'v1/historicalTrades',
12
+ agg_trades: 'v1/aggTrades',
13
+ klines: 'v1/klines',
14
+ twenty_four_hour: 'v1/ticker/24hr',
15
+ price: 'v3/ticker/price',
16
+ book_ticker: 'v3/ticker/bookTicker',
17
+
18
+ # Account API Endpoints
19
+ order: 'v3/order',
20
+ test_order: 'v3/order/test',
21
+ open_orders: 'v3/openOrders',
22
+ all_orders: 'v3/allOrders',
23
+ account: 'v3/account',
24
+ my_trades: 'v3/myTrades',
25
+ user_data_stream: 'v1/userDataStream',
26
+
27
+ # Withdraw API Endpoints
28
+ balance: 'v1/balance',
29
+ withdraw: 'v3/withdraw.html',
30
+ deposit_history: 'v3/depositHistory.html',
31
+ withdraw_history: 'v3/withdrawHistory.html',
32
+ deposit_address: 'v3/depositAddress.html',
33
+ account_status: 'v3/accountStatus.html',
34
+ system_status: 'v3/systemStatus.html',
35
+ withdraw_fee: 'v3/withdrawFee.html',
36
+ dust_log: 'v3/userAssetDribbletLog.html'
37
+ }.freeze
38
+ end
39
+
40
+ class REST_FUTURE
41
+ ENDPOINTS = {
42
+ # Public API Endpoints
43
+ ping: 'v1/ping',
44
+ time: 'v1/time',
45
+ exchange_info: 'v1/exchangeInfo',
46
+ depth: 'v1/depth',
47
+ trades: 'v1/trades',
48
+ historical_trades: 'v1/historicalTrades',
49
+ agg_trades: 'v1/aggTrades',
50
+ klines: 'v1/klines',
51
+ twenty_four_hour: 'v1/ticker/24hr',
52
+ price: 'v1/ticker/price',
53
+ book_ticker: 'v1/ticker/bookTicker',
54
+
55
+ # Account API Endpoints
56
+ order: 'v1/order',
57
+ open_orders: 'v1/openOrders',
58
+ all_orders: 'v1/allOrders',
59
+ account: 'v1/account',
60
+ user_trades: 'v1/userTrades',
61
+ test_order: 'v1/order/test',
62
+ user_data_stream: 'v1/userDataStream',
63
+ withdraw: 'v1/withdraw.html',
64
+
65
+ # Withdraw API Endpoints
66
+ balance: 'v1/balance',
67
+ funding_rate: 'v1/fundingRate',
68
+ income: 'v1/income',
69
+ leverage: 'v1/leverage',
70
+ listenKey: 'v1/listenKey',
71
+ position_risk: 'v1/positionRisk',
72
+ premium_index: 'v1/premiumIndex',
73
+
74
+ #not found in Future-API yet
75
+ my_trades: 'v1/myTrades',
76
+ deposit_history: 'v1/depositHistory.html',
77
+ withdraw_history: 'v1/withdrawHistory.html',
78
+ deposit_address: 'v1/depositAddress.html',
79
+ account_status: 'v1/accountStatus.html',
80
+ system_status: 'v1/systemStatus.html',
81
+ withdraw_fee: 'v1/withdrawFee.html',
82
+ dust_log: 'v1/userAssetDribbletLog.html'
83
+ }.freeze
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,245 @@
1
+ module Binance
2
+ module Client
3
+
4
+ class REST
5
+ METHODS = [
6
+ # Public API Methods
7
+ # #ping
8
+ { name: :ping, client: :public,
9
+ action: :get, endpoint: :ping },
10
+ # #time
11
+ { name: :time, client: :public,
12
+ action: :get, endpoint: :time },
13
+ # #exchange_info
14
+ { name: :exchange_info, client: :public,
15
+ action: :get, endpoint: :exchange_info },
16
+ # #depth
17
+ { name: :depth, client: :public,
18
+ action: :get, endpoint: :depth },
19
+ # #trades
20
+ { name: :trades, client: :public,
21
+ action: :get, endpoint: :trades },
22
+ # #historical_trades
23
+ { name: :historical_trades, client: :verified,
24
+ action: :get, endpoint: :historical_trades },
25
+ # #agg_trades
26
+ { name: :agg_trades, client: :public,
27
+ action: :get, endpoint: :agg_trades },
28
+ # #klines
29
+ { name: :klines, client: :public,
30
+ action: :get, endpoint: :klines },
31
+ # #twenty_four_hour
32
+ { name: :twenty_four_hour, client: :public,
33
+ action: :get, endpoint: :twenty_four_hour },
34
+ # #price
35
+ { name: :price, client: :public,
36
+ action: :get, endpoint: :price },
37
+ # #all_prices
38
+ { name: :all_prices, client: :public,
39
+ action: :get, endpoint: :price },
40
+ # #book_ticker
41
+ { name: :book_ticker, client: :public,
42
+ action: :get, endpoint: :book_ticker },
43
+
44
+ # Account API Methods
45
+ # #create_order!
46
+ { name: :create_order!, client: :signed,
47
+ action: :post, endpoint: :order },
48
+ # #create_test_order
49
+ { name: :create_test_order, client: :signed,
50
+ action: :post, endpoint: :test_order },
51
+ # #query_order
52
+ { name: :query_order, client: :signed,
53
+ action: :get, endpoint: :order },
54
+ # #cancel_order!
55
+ { name: :cancel_order!, client: :signed,
56
+ action: :delete, endpoint: :order },
57
+ # #open_orders
58
+ { name: :open_orders, client: :signed,
59
+ action: :get, endpoint: :open_orders },
60
+ # #all_orders
61
+ { name: :all_orders, client: :signed,
62
+ action: :get, endpoint: :all_orders },
63
+ # #account_info
64
+ { name: :account_info, client: :signed,
65
+ action: :get, endpoint: :account },
66
+ # #my_trades
67
+ { name: :my_trades, client: :signed,
68
+ action: :get, endpoint: :my_trades },
69
+ # #listen_key
70
+ { name: :listen_key, client: :verified,
71
+ action: :post, endpoint: :user_data_stream },
72
+ # #keep_alive_stream!
73
+ { name: :keep_alive_stream!, client: :verified,
74
+ action: :put, endpoint: :user_data_stream },
75
+ # #close_stream!
76
+ { name: :close_stream!, client: :verified,
77
+ action: :delete, endpoint: :user_data_stream },
78
+
79
+ # #withdraw!
80
+ { name: :withdraw!, client: :withdraw,
81
+ action: :post, endpoint: :withdraw },
82
+ # #deposit_history
83
+ { name: :deposit_history, client: :withdraw,
84
+ action: :get, endpoint: :deposit_history },
85
+ # #withdraw_history
86
+ { name: :withdraw_history, client: :withdraw,
87
+ action: :get, endpoint: :withdraw_history },
88
+ # #deposit_address
89
+ { name: :deposit_address, client: :withdraw,
90
+ action: :get, endpoint: :deposit_address },
91
+ # #account_status
92
+ { name: :account_status, client: :withdraw,
93
+ action: :get, endpoint: :account_status },
94
+ # #system_status
95
+ { name: :system_status, client: :public_withdraw,
96
+ action: :get, endpoint: :system_status },
97
+ # #withdraw_fee
98
+ { name: :withdraw_fee, client: :withdraw,
99
+ action: :get, endpoint: :withdraw_fee },
100
+ # dust_log
101
+ { name: :dust_log, client: :withdraw,
102
+ action: :get, endpoint: :dust_log }
103
+ ].freeze
104
+ end
105
+
106
+ class REST_FUTURE
107
+ METHODS = [
108
+ # Public API Methods
109
+ # #ping
110
+ { name: :ping, client: :public,
111
+ action: :get, endpoint: :ping },
112
+ # #time
113
+ { name: :time, client: :public,
114
+ action: :get, endpoint: :time },
115
+ # #exchange_info
116
+ { name: :exchange_info, client: :public,
117
+ action: :get, endpoint: :exchange_info },
118
+ # #depth
119
+ { name: :depth, client: :public,
120
+ action: :get, endpoint: :depth },
121
+ # #trades
122
+ { name: :trades, client: :public,
123
+ action: :get, endpoint: :trades },
124
+ # #historical_trades
125
+ { name: :historical_trades, client: :verified,
126
+ action: :get, endpoint: :historical_trades },
127
+ # #agg_trades
128
+ { name: :agg_trades, client: :public,
129
+ action: :get, endpoint: :agg_trades },
130
+ # #klines
131
+ { name: :klines, client: :public,
132
+ action: :get, endpoint: :klines },
133
+ # #twenty_four_hour
134
+ { name: :twenty_four_hour, client: :public,
135
+ action: :get, endpoint: :twenty_four_hour },
136
+ # #price
137
+ { name: :price, client: :public,
138
+ action: :get, endpoint: :price },
139
+ # #all_prices
140
+ { name: :all_prices, client: :public,
141
+ action: :get, endpoint: :price },
142
+ # #book_ticker
143
+ { name: :book_ticker, client: :public,
144
+ action: :get, endpoint: :book_ticker },
145
+
146
+ # Account API Methods
147
+ # #create_order!
148
+ { name: :create_order!, client: :signed,
149
+ action: :post, endpoint: :order },
150
+ # #create_test_order
151
+ { name: :create_test_order, client: :signed,
152
+ action: :post, endpoint: :test_order },
153
+ # #query_order
154
+ { name: :query_order, client: :signed,
155
+ action: :get, endpoint: :order },
156
+ # #cancel_order!
157
+ { name: :cancel_order!, client: :signed,
158
+ action: :delete, endpoint: :order },
159
+ # #cancel_all_open_orders
160
+ { name: :cancel_all, client: :signed,
161
+ action: :delete, endpoint: :all_open_orders },
162
+ # #cancel_batch_orders
163
+ { name: :cancel_orders, client: :signed,
164
+ action: :delete, endpoint: :batch_orders },
165
+ # #open_orders
166
+ { name: :open_orders, client: :signed,
167
+ action: :get, endpoint: :open_orders },
168
+ # #all_orders
169
+ { name: :all_orders, client: :signed,
170
+ action: :get, endpoint: :all_orders },
171
+ # #account_info
172
+ { name: :account_info, client: :signed,
173
+ action: :get, endpoint: :account },
174
+ # #user_trades
175
+ { name: :user_trades, client: :signed,
176
+ action: :get, endpoint: :user_trades },
177
+ # #listen_key
178
+ { name: :listen_key, client: :verified,
179
+ action: :post, endpoint: :user_data_stream },
180
+ # #keep_alive_stream!
181
+ { name: :keep_alive_stream!, client: :verified,
182
+ action: :put, endpoint: :user_data_stream },
183
+ # #close_stream!
184
+ { name: :close_stream!, client: :verified,
185
+ action: :delete, endpoint: :user_data_stream },
186
+
187
+ # Withdraw API Endpoints
188
+ # # funding_rate
189
+ { name: :funding_rate, client: :signed,
190
+ action: :get, endpoint: :funding_rate },
191
+ # # income
192
+ { name: :income, client: :signed,
193
+ action: :get, endpoint: :income },
194
+ # # leverage
195
+ { name: :leverage, client: :signed,
196
+ action: :post, endpoint: :leverage },
197
+ # listenKey
198
+ { name: :listenKey, client: :signed,
199
+ action: :post, endpoint: :listenKey },
200
+ # # listenKey
201
+ { name: :getlistenKey, client: :signed,
202
+ action: :get, endpoint: :listenKey },
203
+ # # position_risk
204
+ { name: :position_risk, client: :signed,
205
+ action: :get, endpoint: :position_risk },
206
+ # # premium_index
207
+ { name: :premium_index, client: :signed,
208
+ action: :get, endpoint: :premium_index },
209
+ # #withdraw!
210
+ { name: :withdraw!, client: :withdraw,
211
+ action: :post, endpoint: :withdraw },
212
+ # #balance
213
+ { name: :balance, client: :signed,
214
+ action: :get, endpoint: :balance },
215
+
216
+ # NOT FOUND IN FUTURE API (yet)
217
+ # #my_trades
218
+ { name: :my_trades, client: :signed,
219
+ action: :get, endpoint: :my_trades },
220
+ # #deposit_history
221
+ { name: :deposit_history, client: :withdraw,
222
+ action: :get, endpoint: :deposit_history },
223
+ # #withdraw_history
224
+ { name: :withdraw_history, client: :withdraw,
225
+ action: :get, endpoint: :withdraw_history },
226
+ # #deposit_address
227
+ { name: :deposit_address, client: :withdraw,
228
+ action: :get, endpoint: :deposit_address },
229
+ # #account_status
230
+ { name: :account_status, client: :withdraw,
231
+ action: :get, endpoint: :account_status },
232
+ # #system_status
233
+ { name: :system_status, client: :public_withdraw,
234
+ action: :get, endpoint: :system_status },
235
+ # #withdraw_fee
236
+ { name: :withdraw_fee, client: :withdraw,
237
+ action: :get, endpoint: :withdraw_fee },
238
+ # dust_log
239
+ { name: :dust_log, client: :withdraw,
240
+ action: :get, endpoint: :dust_log }
241
+ ].freeze
242
+
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,31 @@
1
+ module Binance
2
+ module Client
3
+ class REST
4
+ # Sign the query string using HMAC(sha-256) and appends to query string
5
+ SignRequestMiddleware = Struct.new(:app, :secret_key) do
6
+ def call(env)
7
+ hash = OpenSSL::HMAC.hexdigest(
8
+ OpenSSL::Digest.new('sha256'), secret_key, env.url.query
9
+ )
10
+ env.url.query = REST.add_query_param(env.url.query, 'signature', hash)
11
+
12
+ app.call env
13
+ end
14
+ end
15
+ end
16
+
17
+ class REST_FUTURE
18
+ # Sign the query string using HMAC(sha-256) and appends to query string
19
+ SignRequestMiddleware = Struct.new(:app, :secret_key) do
20
+ def call(env)
21
+ hash = OpenSSL::HMAC.hexdigest(
22
+ OpenSSL::Digest.new('sha256'), secret_key, env.url.query
23
+ )
24
+ env.url.query = REST_FUTURE.add_query_param(env.url.query, 'signature', hash)
25
+
26
+ app.call env
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ require 'date'
2
+
3
+ module Binance
4
+ module Client
5
+ class REST
6
+ # Generate a timestamp in milliseconds and append to query string
7
+ TimestampRequestMiddleware = Struct.new(:app) do
8
+ def call(env)
9
+ date = DateTime.now
10
+ date = Time.at(date.to_time.to_f-$diff).to_datetime if !$diff.nil?
11
+ env.url.query = REST.add_query_param(
12
+ env.url.query, 'timestamp', date.strftime('%Q')
13
+ )
14
+ app.call env
15
+ end
16
+ end
17
+ end
18
+
19
+ class REST_FUTURE
20
+ # Generate a timestamp in milliseconds and append to query string
21
+ TimestampRequestMiddleware = Struct.new(:app) do
22
+ def call(env)
23
+ date = DateTime.now
24
+ date = Time.at(date.to_time.to_f-$diff).to_datetime if !$diff.nil?
25
+ env.url.query = REST_FUTURE.add_query_param(
26
+ env.url.query, 'timestamp', date.strftime('%Q')
27
+ )
28
+ app.call env
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ require 'faraday'
2
+
3
+ require_relative 'rest/sign_request_middleware'
4
+ require_relative 'rest/timestamp_request_middleware'
5
+ require_relative 'rest/clients'
6
+ require_relative 'rest/endpoints'
7
+ require_relative 'rest/methods'
8
+
9
+ module Binance
10
+ module Client
11
+ class REST
12
+ def initialize(api_key: '', secret_key: '',
13
+ adapter: Faraday.default_adapter)
14
+ @clients = {}
15
+ @clients[:public] = public_client adapter
16
+ @clients[:verified] = verified_client api_key, adapter
17
+ @clients[:signed] = signed_client api_key, secret_key, adapter
18
+ @clients[:withdraw] = withdraw_client api_key, secret_key, adapter
19
+ @clients[:public_withdraw] = public_withdraw_client adapter
20
+ end
21
+
22
+ METHODS.each do |method|
23
+ define_method(method[:name]) do |options = {}|
24
+ response = @clients[method[:client]].send(method[:action]) do |req|
25
+ req.url ENDPOINTS[method[:endpoint]]
26
+ req.params.merge! options.map { |k, v| [camelize(k.to_s), v] }.to_h
27
+ end
28
+ response.body
29
+ end
30
+ end
31
+
32
+ def self.add_query_param(query, key, value)
33
+ query = query.to_s
34
+ query << '&' unless query.empty?
35
+ query << "#{Faraday::Utils.escape key}=#{Faraday::Utils.escape value}"
36
+ end
37
+
38
+ def camelize(str)
39
+ str.split('_')
40
+ .map.with_index { |word, i| i.zero? ? word : word.capitalize }.join
41
+ end
42
+ end
43
+
44
+ class REST_FUTURE
45
+ def initialize(api_key: '', secret_key: '',
46
+ adapter: Faraday.default_adapter, test_api: false)
47
+ @clients = {}
48
+ @clients[:public] = public_client adapter, test_api
49
+ @clients[:verified] = verified_client api_key, adapter, test_api
50
+ @clients[:signed] = signed_client api_key, secret_key, adapter, test_api
51
+ @clients[:withdraw] = withdraw_client api_key, secret_key, adapter, test_api
52
+ @clients[:public_withdraw] = public_withdraw_client adapter, test_api
53
+ end
54
+
55
+ METHODS.each do |method|
56
+ define_method(method[:name]) do |options = {}|
57
+ response = @clients[method[:client]].send(method[:action]) do |req|
58
+ req.url ENDPOINTS[method[:endpoint]]
59
+ req.params.merge! options.map { |k, v| [camelize(k.to_s), v] }.to_h
60
+ end
61
+ response.body
62
+ end
63
+ end
64
+
65
+ def self.add_query_param(query, key, value)
66
+ query = query.to_s
67
+ query << '&' unless query.empty?
68
+ query << "#{Faraday::Utils.escape key}=#{Faraday::Utils.escape value}"
69
+ end
70
+
71
+ def camelize(str)
72
+ str.split('_')
73
+ .map.with_index { |word, i| i.zero? ? word : word.capitalize }.join
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,430 @@
1
+ require 'faye/websocket'
2
+
3
+ module Binance
4
+ module Client
5
+ # Public: Client with methods mirroring the Binance WebSocket API
6
+ class WebSocket
7
+ # Public: String base url for WebSocket client to use
8
+ BASE_URL = 'wss://stream.binance.com:9443'.freeze
9
+
10
+ # Public: Create a single WebSocket stream
11
+ #
12
+ # :stream - The Hash used to define the stream
13
+ # :symbol - The String symbol to listen to
14
+ # :type - The String type of stream to listen to
15
+ # :level - The String level to use for the depth stream (optional)
16
+ # :interval - The String interval to use for the kline stream (optional)
17
+ #
18
+ # :methods - The Hash which contains the event handler methods to pass to
19
+ # the WebSocket client
20
+ # :open - The Proc called when a stream is opened (optional)
21
+ # :message - The Proc called when a stream receives a message
22
+ # :error - The Proc called when a stream receives an error (optional)
23
+ # :close - The Proc called when a stream is closed (optional)
24
+ def single(stream:, methods:)
25
+ create_stream("#{BASE_URL}/ws/#{stream_url(stream)}",
26
+ methods: methods)
27
+ end
28
+
29
+ # Public: Create multiple WebSocket streams
30
+ #
31
+ # :streams - The Array of Hashes used to define the stream. Each Hash can
32
+ # have the following keys:
33
+ # :symbol - The String symbol the stream will listen to
34
+ # :type - The String type of stream to listen to
35
+ # :level - The String level to use for the depth stream (optional)
36
+ # :interval - The String interval to use for the kline stream (optional)
37
+ #
38
+ # :methods - The Hash which contains the event handler methods to pass to
39
+ # the WebSocket client
40
+ # :open - The Proc called when a stream is opened (optional)
41
+ # :message - The Proc called when a stream receives a message
42
+ # :error - The Proc called when a stream receives an error (optional)
43
+ # :close - The Proc called when a stream is closed (optional)
44
+ def multi(streams:, methods:)
45
+ names = streams.map { |stream| stream_url(stream) }
46
+ create_stream("#{BASE_URL}/stream?streams=#{names.join('/')}",
47
+ methods: methods)
48
+ end
49
+
50
+ # Public: Create an Aggregate Trade stream
51
+ #
52
+ # :symbol - The String symbol the stream will listen to
53
+ #
54
+ # :methods - The Hash which contains the event handler methods to pass to
55
+ # the WebSocket client
56
+ # :open - The Proc called when a stream is opened (optional)
57
+ # :message - The Proc called when a stream receives a message
58
+ # :error - The Proc called when a stream receives an error (optional)
59
+ # :close - The Proc called when a stream is closed (optional)
60
+ def agg_trade(symbol:, methods:)
61
+ single stream: { symbol: symbol, type: 'aggTrade' }, methods: methods
62
+ end
63
+
64
+ # Public: Create a Trade stream
65
+ #
66
+ # :symbol - The String symbol the stream will listen to
67
+ #
68
+ # :methods - The Hash which contains the event handler methods to pass to
69
+ # the WebSocket client
70
+ # :open - The Proc called when a stream is opened (optional)
71
+ # :message - The Proc called when a stream receives a message
72
+ # :error - The Proc called when a stream receives an error (optional)
73
+ # :close - The Proc called when a stream is closed (optional)
74
+ def trade(symbol:, methods:)
75
+ single stream: { symbol: symbol, type: 'trade' }, methods: methods
76
+ end
77
+
78
+ # Public: Create an Kline stream
79
+ #
80
+ # :symbol - The String symbol the stream will listen to
81
+ #
82
+ # :interval - The String interval the stream will update with. The
83
+ # intervals that may be used can be found in the Binance API
84
+ # docs.
85
+ #
86
+ # :methods - The Hash which contains the event handler methods to pass to
87
+ # the WebSocket client
88
+ # :open - The Proc called when a stream is opened (optional)
89
+ # :message - The Proc called when a stream receives a message
90
+ # :error - The Proc called when a stream receives an error (optional)
91
+ # :close - The Proc called when a stream is closed (optional)
92
+ def kline(symbol:, interval:, methods:)
93
+ single stream: { symbol: symbol, type: 'kline', interval: interval },
94
+ methods: methods
95
+ end
96
+
97
+ # Public: Create a Ticker stream
98
+ #
99
+ # :symbol - The String symbol the stream will listen to
100
+ #
101
+ # :methods - The Hash which contains the event handler methods to pass to
102
+ # the WebSocket client
103
+ # :open - The Proc called when a stream is opened (optional)
104
+ # :message - The Proc called when a stream receives a message
105
+ # :error - The Proc called when a stream receives an error (optional)
106
+ # :close - The Proc called when a stream is closed (optional)
107
+ def ticker(symbol:, methods:)
108
+ single stream: { symbol: symbol, type: 'ticker' }, methods: methods
109
+ end
110
+
111
+ # Public: Create a Ticker stream for all symbols
112
+ #
113
+ # :methods - The Hash which contains the event handler methods to pass to
114
+ # the WebSocket client
115
+ # :open - The Proc called when a stream is opened (optional)
116
+ # :message - The Proc called when a stream receives a message
117
+ # :error - The Proc called when a stream receives an error (optional)
118
+ # :close - The Proc called when a stream is closed (optional)
119
+ def all_market_ticker(methods:)
120
+ single stream: { symbol: '!ticker', type: 'arr' }, methods: methods
121
+ end
122
+
123
+ # Public: Create an Partial Book Depth stream
124
+ #
125
+ # :symbol - The String symbol the stream will listen to
126
+ #
127
+ # :level - The String interval the stream will update with. The intervals
128
+ # that may be used can be found in the Binance API docs.
129
+ #
130
+ # :methods - The Hash which contains the event handler methods to pass to
131
+ # the WebSocket client
132
+ # :open - The Proc called when a stream is opened (optional)
133
+ # :message - The Proc called when a stream receives a message
134
+ # :error - The Proc called when a stream receives an error (optional)
135
+ # :close - The Proc called when a stream is closed (optional)
136
+ def partial_book_depth(symbol:, level:, methods:)
137
+ single stream: { symbol: symbol, type: 'depth', level: level },
138
+ methods: methods
139
+ end
140
+
141
+ # Public: Create a Diff Depth stream
142
+ #
143
+ # :symbol - The String symbol the stream will listen to
144
+ #
145
+ # :methods - The Hash which contains the event handler methods to pass to
146
+ # the WebSocket client
147
+ # :open - The Proc called when a stream is opened (optional)
148
+ # :message - The Proc called when a stream receives a message
149
+ # :error - The Proc called when a stream receives an error (optional)
150
+ # :close - The Proc called when a stream is closed (optional)
151
+ def diff_depth(symbol:, methods:)
152
+ single stream: { symbol: symbol, type: 'depth' }, methods: methods
153
+ end
154
+
155
+ # Public: Create a User Data stream
156
+ #
157
+ # listen_key - The String key the stream will listen to, attained by
158
+ # interacting with the REST API userDataStream endpoint
159
+ #
160
+ # :methods - The Hash which contains the event handler methods to pass to
161
+ # the WebSocket client
162
+ # :open - The Proc called when a stream is opened (optional)
163
+ # :message - The Proc called when a stream receives a message
164
+ # :error - The Proc called when a stream receives an error (optional)
165
+ # :close - The Proc called when a stream is closed (optional)
166
+ def user_data(listen_key:, methods:)
167
+ create_stream "#{BASE_URL}/ws/#{listen_key}", methods: methods
168
+ end
169
+
170
+ private
171
+
172
+ # Internal: Create a valid URL for a WebSocket to use
173
+ #
174
+ # :symbol - The String symbol to listen to
175
+ # :type - The String type the stream will listen to
176
+ # :level - The String level to use for the depth stream (optional)
177
+ # :interval - The String interval to use for the kline stream (optional)
178
+ def stream_url(symbol:, type:, level: '', interval: '')
179
+ "#{symbol.downcase}@#{type}".tap do |url|
180
+ url << level
181
+ url << "_#{interval}" unless interval.empty?
182
+ end
183
+ end
184
+
185
+ # Internal: Initialize and return a Faye::WebSocket::Client
186
+ #
187
+ # url - The String url that the WebSocket should try to connect to
188
+ #
189
+ # :methods - The Hash which contains the event handler methods to pass to
190
+ # the WebSocket client
191
+ # :open - The Proc called when a stream is opened (optional)
192
+ # :message - The Proc called when a stream receives a message
193
+ # :error - The Proc called when a stream receives an error (optional)
194
+ # :close - The Proc called when a stream is closed (optional)
195
+ def create_stream(url, methods:)
196
+ Faye::WebSocket::Client.new(url)
197
+ .tap { |ws| attach_methods(ws, methods) }
198
+ end
199
+
200
+ # Internal: Iterate through methods passed and add them to the WebSocket
201
+ #
202
+ # websocket - The Faye::WebSocket::Client to apply methods to
203
+ #
204
+ # methods - The Hash which contains the event handler methods to pass to
205
+ # the WebSocket client
206
+ # :open - The Proc called when a stream is opened (optional)
207
+ # :message - The Proc called when a stream receives a message
208
+ # :error - The Proc called when a stream receives an error (optional)
209
+ # :close - The Proc called when a stream is closed (optional)
210
+ def attach_methods(websocket, methods)
211
+ methods.each_pair do |key, method|
212
+ websocket.on(key) { |event| method.call(event) }
213
+ end
214
+ end
215
+ end
216
+
217
+ class WebSocketFuture
218
+ # Public: String base url for WebSocket client to use
219
+ BASE_URL = 'wss://fstream.binance.com'.freeze
220
+
221
+ # Public: Create a single WebSocket stream
222
+ #
223
+ # :stream - The Hash used to define the stream
224
+ # :symbol - The String symbol to listen to
225
+ # :type - The String type of stream to listen to
226
+ # :level - The String level to use for the depth stream (optional)
227
+ # :interval - The String interval to use for the kline stream (optional)
228
+ #
229
+ # :methods - The Hash which contains the event handler methods to pass to
230
+ # the WebSocket client
231
+ # :open - The Proc called when a stream is opened (optional)
232
+ # :message - The Proc called when a stream receives a message
233
+ # :error - The Proc called when a stream receives an error (optional)
234
+ # :close - The Proc called when a stream is closed (optional)
235
+ def single(stream:, methods:)
236
+ create_stream("#{BASE_URL}/ws/#{stream_url(stream)}",
237
+ methods: methods)
238
+ end
239
+
240
+ # Public: Create multiple WebSocket streams
241
+ #
242
+ # :streams - The Array of Hashes used to define the stream. Each Hash can
243
+ # have the following keys:
244
+ # :symbol - The String symbol the stream will listen to
245
+ # :type - The String type of stream to listen to
246
+ # :level - The String level to use for the depth stream (optional)
247
+ # :interval - The String interval to use for the kline stream (optional)
248
+ #
249
+ # :methods - The Hash which contains the event handler methods to pass to
250
+ # the WebSocket client
251
+ # :open - The Proc called when a stream is opened (optional)
252
+ # :message - The Proc called when a stream receives a message
253
+ # :error - The Proc called when a stream receives an error (optional)
254
+ # :close - The Proc called when a stream is closed (optional)
255
+ def multi(streams:, methods:)
256
+ names = streams.map { |stream| stream_url(stream) }
257
+ create_stream("#{BASE_URL}/stream?streams=#{names.join('/')}",
258
+ methods: methods)
259
+ end
260
+
261
+ # Public: Create an Aggregate Trade stream
262
+ #
263
+ # :symbol - The String symbol the stream will listen to
264
+ #
265
+ # :methods - The Hash which contains the event handler methods to pass to
266
+ # the WebSocket client
267
+ # :open - The Proc called when a stream is opened (optional)
268
+ # :message - The Proc called when a stream receives a message
269
+ # :error - The Proc called when a stream receives an error (optional)
270
+ # :close - The Proc called when a stream is closed (optional)
271
+ def agg_trade(symbol:, methods:)
272
+ single stream: { symbol: symbol, type: 'aggTrade' }, methods: methods
273
+ end
274
+
275
+ # Public: Create a Trade stream
276
+ #
277
+ # :symbol - The String symbol the stream will listen to
278
+ #
279
+ # :methods - The Hash which contains the event handler methods to pass to
280
+ # the WebSocket client
281
+ # :open - The Proc called when a stream is opened (optional)
282
+ # :message - The Proc called when a stream receives a message
283
+ # :error - The Proc called when a stream receives an error (optional)
284
+ # :close - The Proc called when a stream is closed (optional)
285
+ def trade(symbol:, methods:)
286
+ single stream: { symbol: symbol, type: 'trade' }, methods: methods
287
+ end
288
+
289
+ # Public: Create an Kline stream
290
+ #
291
+ # :symbol - The String symbol the stream will listen to
292
+ #
293
+ # :interval - The String interval the stream will update with. The
294
+ # intervals that may be used can be found in the Binance API
295
+ # docs.
296
+ #
297
+ # :methods - The Hash which contains the event handler methods to pass to
298
+ # the WebSocket client
299
+ # :open - The Proc called when a stream is opened (optional)
300
+ # :message - The Proc called when a stream receives a message
301
+ # :error - The Proc called when a stream receives an error (optional)
302
+ # :close - The Proc called when a stream is closed (optional)
303
+ def kline(symbol:, interval:, methods:)
304
+ single stream: { symbol: symbol, type: 'kline', interval: interval },
305
+ methods: methods
306
+ end
307
+
308
+ # Public: Create a Ticker stream
309
+ #
310
+ # :symbol - The String symbol the stream will listen to
311
+ #
312
+ # :methods - The Hash which contains the event handler methods to pass to
313
+ # the WebSocket client
314
+ # :open - The Proc called when a stream is opened (optional)
315
+ # :message - The Proc called when a stream receives a message
316
+ # :error - The Proc called when a stream receives an error (optional)
317
+ # :close - The Proc called when a stream is closed (optional)
318
+ def ticker(symbol:, methods:)
319
+ single stream: { symbol: symbol, type: 'ticker' }, methods: methods
320
+ end
321
+
322
+ # Public: Create a Ticker stream for all symbols
323
+ #
324
+ # :methods - The Hash which contains the event handler methods to pass to
325
+ # the WebSocket client
326
+ # :open - The Proc called when a stream is opened (optional)
327
+ # :message - The Proc called when a stream receives a message
328
+ # :error - The Proc called when a stream receives an error (optional)
329
+ # :close - The Proc called when a stream is closed (optional)
330
+ def all_market_ticker(methods:)
331
+ single stream: { symbol: '!ticker', type: 'arr' }, methods: methods
332
+ end
333
+
334
+ # Public: Create an Partial Book Depth stream
335
+ #
336
+ # :symbol - The String symbol the stream will listen to
337
+ #
338
+ # :level - The String interval the stream will update with. The intervals
339
+ # that may be used can be found in the Binance API docs.
340
+ #
341
+ # :methods - The Hash which contains the event handler methods to pass to
342
+ # the WebSocket client
343
+ # :open - The Proc called when a stream is opened (optional)
344
+ # :message - The Proc called when a stream receives a message
345
+ # :error - The Proc called when a stream receives an error (optional)
346
+ # :close - The Proc called when a stream is closed (optional)
347
+ def partial_book_depth(symbol:, level:, methods:)
348
+ single stream: { symbol: symbol, type: 'depth', level: level },
349
+ methods: methods
350
+ end
351
+
352
+ # Public: Create a Diff Depth stream
353
+ #
354
+ # :symbol - The String symbol the stream will listen to
355
+ #
356
+ # :methods - The Hash which contains the event handler methods to pass to
357
+ # the WebSocket client
358
+ # :open - The Proc called when a stream is opened (optional)
359
+ # :message - The Proc called when a stream receives a message
360
+ # :error - The Proc called when a stream receives an error (optional)
361
+ # :close - The Proc called when a stream is closed (optional)
362
+ def diff_depth(symbol:, methods:)
363
+ single stream: { symbol: symbol, type: 'depth' }, methods: methods
364
+ end
365
+
366
+ # Public: Create a User Data stream
367
+ #
368
+ # listen_key - The String key the stream will listen to, attained by
369
+ # interacting with the REST API userDataStream endpoint
370
+ #
371
+ # :methods - The Hash which contains the event handler methods to pass to
372
+ # the WebSocket client
373
+ # :open - The Proc called when a stream is opened (optional)
374
+ # :message - The Proc called when a stream receives a message
375
+ # :error - The Proc called when a stream receives an error (optional)
376
+ # :close - The Proc called when a stream is closed (optional)
377
+ def user_data(listen_key:, methods:)
378
+ create_stream "#{BASE_URL}/ws/#{listen_key}", methods: methods
379
+ end
380
+
381
+ private
382
+
383
+ # Internal: Create a valid URL for a WebSocket to use
384
+ #
385
+ # :symbol - The String symbol to listen to
386
+ # :type - The String type the stream will listen to
387
+ # :level - The String level to use for the depth stream (optional)
388
+ # :interval - The String interval to use for the kline stream (optional)
389
+ def stream_url(symbol:, type:, level: '', interval: '')
390
+ "#{symbol.downcase}@#{type}".tap do |url|
391
+ url << level
392
+ url << "_#{interval}" unless interval.empty?
393
+ end
394
+ end
395
+
396
+ # Internal: Initialize and return a Faye::WebSocket::Client
397
+ #
398
+ # url - The String url that the WebSocket should try to connect to
399
+ #
400
+ # :methods - The Hash which contains the event handler methods to pass to
401
+ # the WebSocket client
402
+ # :open - The Proc called when a stream is opened (optional)
403
+ # :message - The Proc called when a stream receives a message
404
+ # :error - The Proc called when a stream receives an error (optional)
405
+ # :close - The Proc called when a stream is closed (optional)
406
+ def create_stream(url, methods:)
407
+ Faye::WebSocket::Client.new(url)
408
+ .tap { |ws| attach_methods(ws, methods) }
409
+ end
410
+
411
+ # Internal: Iterate through methods passed and add them to the WebSocket
412
+ #
413
+ # websocket - The Faye::WebSocket::Client to apply methods to
414
+ #
415
+ # methods - The Hash which contains the event handler methods to pass to
416
+ # the WebSocket client
417
+ # :open - The Proc called when a stream is opened (optional)
418
+ # :message - The Proc called when a stream receives a message
419
+ # :error - The Proc called when a stream receives an error (optional)
420
+ # :close - The Proc called when a stream is closed (optional)
421
+ def attach_methods(websocket, methods)
422
+ methods.each_pair do |key, method|
423
+ websocket.on(key) { |event| method.call(event) }
424
+ end
425
+ end
426
+
427
+
428
+ end
429
+ end
430
+ end
@@ -0,0 +1,3 @@
1
+ module Binance
2
+ VERSION = '1.3.0'.freeze
3
+ end
data/lib/binance.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'binance/version'
2
+ require 'binance/client/rest'
3
+ require 'binance/client/websocket'
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marcel-binance
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Marcel Bonnet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.12'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday_middleware
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.12'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faye-websocket
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ description:
98
+ email:
99
+ - marcel.social@protonmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - lib/binance.rb
105
+ - lib/binance/client/rest.rb
106
+ - lib/binance/client/rest/clients.rb
107
+ - lib/binance/client/rest/endpoints.rb
108
+ - lib/binance/client/rest/methods.rb
109
+ - lib/binance/client/rest/sign_request_middleware.rb
110
+ - lib/binance/client/rest/timestamp_request_middleware.rb
111
+ - lib/binance/client/websocket.rb
112
+ - lib/binance/version.rb
113
+ homepage: https://github.com/marcelbonnet/binance
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubygems_version: 3.1.2
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: API Wrapper for the Binance cryptocurrency exchange.
136
+ test_files: []