binance-connector 1.0.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: 73d340255608f6f2d79cc473c6372a536fe0e38d3cde79683d2acc73de339795
4
+ data.tar.gz: 8b366e6f5fd8dcc03c75fe3b77d907291f6b5d71b712bbbd3d73907fa17dac07
5
+ SHA512:
6
+ metadata.gz: 38538d24affa5bd891a0ec42bbb83664f906272bedcdd60600295b83435bde730e06013f8d06fcb7457a6c6a7ed5ab291964644edca28a7fe1ffae2f20aeb865
7
+ data.tar.gz: 166eac302591ae1545151d996aa532352d311366e7f9e61a987e9f02fcfbc29ce376245ca5482053a2ca148d08c9a4578b6407cea36b92c1974070f1ebbcb421
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+ ### Added
5
+ - First release, please find details from `README.md`
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Binance
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # Binance Connector Ruby
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/binance-connector.svg)](https://badge.fury.io/rb/binance-connector)
4
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ This is a lightweight library that works as a connector to [Binance public API](https://github.com/binance/binance-spot-api-docs). It’s designed to be simple, clean, and easy to use with minimal dependencies.
8
+
9
+ - Supported APIs:
10
+ - `/api/*`
11
+ - `/sapi/*`
12
+ - Spot Websocket Market Stream
13
+ - Spot User Data Stream
14
+ - Inclusion of test cases and examples
15
+ - Customizable base URL, request timeout
16
+ - Response metadata can be displayed
17
+ - Customizable Logger
18
+
19
+ ## Installation
20
+
21
+ 1. Include the library in Gemfile and then install it when execute the bundler.
22
+
23
+ Add this line in the Gemfile.
24
+
25
+ ```ruby
26
+ gem 'binance-connector'
27
+ ```
28
+
29
+ And then execute the bundler via CLI:
30
+
31
+ $ bundle
32
+
33
+ 2. Install it with CLI:
34
+
35
+ $ gem install binance-connector
36
+
37
+ ## Restful APIs
38
+
39
+ ```ruby
40
+ require 'binance'
41
+
42
+ # Create a new client instance.
43
+ # If the APIs do not require the keys, (e.g. market data), key and secret can be omitted.
44
+ client = Binance::Spot.new(key: key, secret: secret)
45
+
46
+ # Send a request to query server time
47
+ puts client.time
48
+
49
+ # Send a request to query BTCUSDT ticker
50
+ puts client.ticker_24hr(symbol: 'BTCUSDT')
51
+
52
+ # Send a request to get account information
53
+ puts client.account
54
+
55
+ # Place an order
56
+ response = client.new_order(symbol: 'BNBUSDT', side: 'BUY', price: 20, quantity: 1, type: 'LIMIT', timeInForce: 'GTC')
57
+ ```
58
+
59
+
60
+ Please find `examples` folder to check for more endpoints.
61
+
62
+
63
+ ### Testnet
64
+
65
+ While `/sapi/*` endpoints don't have testnet environment yet, `/api/*` endpoints can be tested in
66
+ [Spot Testnet](https://testnet.binance.vision/). You can use it by changing the base URL:
67
+
68
+ ```ruby
69
+ client = Binance::Spot.new(base_url: 'https://testnet.binance.vision')
70
+ puts client.time
71
+ ```
72
+
73
+ ### Base URL
74
+
75
+ If `base_url` is not provided, it defaults to `api.binance.com`.
76
+
77
+ It's recommended to pass in the `base_url` parameter, even in production as Binance provides alternative URLs in case of performance issues:
78
+
79
+ - `https://api1.binance.com`
80
+ - `https://api2.binance.com`
81
+ - `https://api3.binance.com`
82
+
83
+ ### RecvWindow
84
+
85
+ From Binance API, recvWindow is available for all endpoints require signature. By default, it's 5000ms.
86
+ You are allowed to set this parameter to any value less than 60000, number beyond this limit will receive error from Binance server.
87
+ ```ruby
88
+
89
+ response = client.account(recvWindow: 2_000)
90
+
91
+ ```
92
+
93
+ ### Optional parameters
94
+
95
+ For the optional parameters in the endpoint, pass exactly the field name from API document into method.
96
+ e.g
97
+
98
+ ```ruby
99
+ client = Binance::Spot.new
100
+
101
+ # correct
102
+ response = client.cancel_order(symbol: 'BNBUSDT', orderId: 25)
103
+
104
+ # this is incorrect
105
+ response = client.cancel_order(symbol: 'BNBUSDT', order_id: 25)
106
+ ```
107
+
108
+ ### Timeout
109
+
110
+ Timeout (unit: second) can be specified when initializing a client instance. If `timeout` is not set, the default is **no timeout**.
111
+
112
+ ```ruby
113
+ client = Binance::Spot.new(timeout: 2)
114
+ ```
115
+
116
+ ### Response Metadata
117
+
118
+ The Binance API server provides weight usages in the headers of each response. This information can be fetched from `headers` property. `x-mbx-used-weight` and `x-mbx-used-weight-1m` show the total weight consumed within 1 minute. This is very useful to indentify the current usage.
119
+ To display this value, specify `show_weight_usage: true` when intializing a new client instance.
120
+
121
+ ```ruby
122
+ client = Binance::Spot.new(show_weight_usage: true)
123
+ ```
124
+
125
+ Then, take server time API (`GET /api/v3/time`) as an example, the response data is shown as below:
126
+
127
+ ```ruby
128
+ {:data=>{:serverTime=>1589860878546}, :weight_usage=>{"x-mbx-used-weight"=>"1", "x-mbx-used-weight-1m"=>"1"}}
129
+ ```
130
+
131
+ When `show_header: true`, the library has the ability to print out all response headers, which may be very helpful for debugging the program.
132
+
133
+ ```ruby
134
+ client = Binance::Spot.new(show_header: true)
135
+ ```
136
+
137
+ Then, take the same example as above, the response data becomes:
138
+
139
+ ```ruby
140
+ {:data=>{:serverTime=>1589863539220}, :header=>{"content-type"=>"application/json;charset=utf-8",...}}
141
+ ```
142
+
143
+ ### Custom Logger Integration
144
+
145
+ The client class accepts a [Logger](https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html) instance as an input parameter.
146
+
147
+ ```ruby
148
+ logger = Logger.new(STDOUT)
149
+ client = Binance::Spot.new(logger: logger)
150
+ logger.info(client.time)
151
+ ```
152
+
153
+ ### Exception
154
+
155
+ There are 3 types of exceptions:
156
+ - `Binance::RequiredParameterError`
157
+ - When missing required param
158
+ - Not sending out the request
159
+ - `Binance::ClientError`
160
+ - This is thrown when API server returns `4XX`, it's an issue from client side.
161
+ - The following properties may be helpful to resolve the issue:
162
+ - Response header - Please refer to `Response Metadata` section for more details.
163
+ - HTTP status code
164
+ - Error code - Server's error code, e.g. `-1102`
165
+ - Error message - Server's error message, e.g. `Unknown order sent.`
166
+ - Request config - Configuration send to the server, which can include URL, request method and headers.
167
+ - `Binance::ServerError`
168
+ - When API server returning 5XX
169
+ - sending out the request
170
+
171
+ They all inherit from `Binance::Error`
172
+
173
+ ```ruby
174
+ begin
175
+ response = client.time
176
+ rescue Binance::ClientError => e
177
+ e.response[:status]
178
+ e.response[:headers]
179
+ e.response[:body]
180
+ end
181
+ ```
182
+
183
+ ## Websocket
184
+
185
+ ```ruby
186
+ require 'binance'
187
+ require 'eventmachine'
188
+
189
+ client = Binance::Spot::WebSocket.new
190
+
191
+ EM.run do
192
+ onopen = proc { logger.info('connected to server') }
193
+ onmessage = proc { |msg, _type| logger.info(msg) }
194
+ onerror = proc { |e| logger.error(e) }
195
+ onclose = proc { logger.info('connection closed') }
196
+
197
+ callbacks = {
198
+ onopen: onopen,
199
+ onmessage: onmessage,
200
+ onerror: onerror,
201
+ onclose: onclose
202
+ }
203
+
204
+ client.kline(symbol: 'btcusdt', interval: '30m', callbacks: callbacks)
205
+ end
206
+ ```
207
+
208
+ More websocket examples are available in the `examples` folder
209
+
210
+ ### Auto response
211
+ Binance requires `pong` for heartbeat, response is sent automatically.
212
+
213
+ ## Limitation
214
+
215
+ Futures and Vanilla Options APIs are not supported:
216
+
217
+ - `/fapi/*`
218
+ - `/dapi/*`
219
+ - `/vapi/*`
220
+ - Associated Websocket Market and User Data Streams
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Binance
4
+ # Authentication response to API key and signature
5
+ class Authentication
6
+ attr_accessor :key, :secret
7
+
8
+ def initialize(key, secret)
9
+ @key = key
10
+ @secret = secret
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Binance
4
+ class Error < StandardError; end
5
+
6
+ # Client error from 400 - 499
7
+ class ClientError < Error
8
+ attr_reader :response
9
+
10
+ def initialize(response = nil)
11
+ @response = response
12
+ super(response)
13
+ end
14
+ end
15
+
16
+ # Server side error for 5xx
17
+ class ServerError < Error
18
+ end
19
+
20
+ # Error when missing required params
21
+ class RequiredParameterError < Error
22
+ def initialize(param_name, param_value)
23
+ super(
24
+ "ValidationFailed: #{param_name} is required, but provided value: #{param_value}"
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'binance/utils/faraday/middleware'
5
+ require 'binance/utils/faraday/custom_params_encoder'
6
+
7
+ module Binance
8
+ # Session has the http request connection
9
+ class Session
10
+ include Binance::Utils::Faraday::Middleware
11
+
12
+ def initialize(options = {})
13
+ @base_url = options[:base_url] || 'https://api.binance.com'
14
+ @auth = Authentication.new(options[:key], options[:secret])
15
+ @logger = options[:logger]
16
+ @show_weight_usage = options[:show_weight_usage] || false
17
+ @show_header = options[:show_header] || false
18
+ @timeout = options[:timeout]
19
+ end
20
+
21
+ def public_request(path: '/', params: {})
22
+ process_request(public_conn, :get, path, params)
23
+ end
24
+
25
+ def limit_request(method: :get, path: '/', params: {})
26
+ process_request(limit_conn, method, path, params)
27
+ end
28
+
29
+ def sign_request(method, path, params: {})
30
+ process_request(signed_conn, method, path, params)
31
+ end
32
+
33
+ private
34
+
35
+ def process_request(conn, method, path, params)
36
+ response = conn.send(method, path_with_query(path, params.compact), nil)
37
+ extract_response(response)
38
+ rescue Faraday::ClientError => e
39
+ raise Binance::ClientError, e.response
40
+ rescue Faraday::ServerError => e
41
+ raise Binance::ServerError, e
42
+ end
43
+
44
+ def extract_response(response)
45
+ begin
46
+ data = JSON.parse(response.body, symbolize_names: true)
47
+ rescue JSON::ParserError
48
+ data = response.body
49
+ end
50
+
51
+ return data if !@show_header && !@show_weight_usage
52
+
53
+ res = { data: data }
54
+ res[:header] = response.headers if @show_header
55
+ res[:weight_usage] = response.headers.select { |k, _| weight_usage?(k) } if @show_weight_usage
56
+ res
57
+ end
58
+
59
+ def weight_usage?(key)
60
+ key.start_with?('x-mbx-used-weight') || key.start_with?('x-sapi-used')
61
+ end
62
+
63
+ def path_with_query(path, params)
64
+ "#{path}?#{Binance::Utils::Url.build_query(params)}"
65
+ end
66
+
67
+ def public_conn
68
+ build_connection
69
+ end
70
+
71
+ def limit_conn
72
+ build_connection do |conn|
73
+ conn.headers['X-MBX-APIKEY'] = @auth.key
74
+ end
75
+ end
76
+
77
+ def signed_conn
78
+ build_connection do |conn|
79
+ conn.headers['X-MBX-APIKEY'] = @auth.key
80
+ conn.use Timestamp
81
+ conn.use Signature, @auth.secret
82
+ end
83
+ end
84
+
85
+ def build_connection
86
+ Faraday.new(url: @base_url) do |client|
87
+ prepare_headers(client)
88
+ client.options.timeout = @timeout
89
+ client.options.params_encoder = Binance::Utils::Faraday::CustomParamsEncoder
90
+ yield client if block_given?
91
+ client.use Faraday::Response::RaiseError
92
+ logger_response(client)
93
+ client.adapter Faraday.default_adapter
94
+ end
95
+ end
96
+
97
+ def logger_response(client)
98
+ client.response :logger, @logger if @logger
99
+ end
100
+
101
+ def prepare_headers(client)
102
+ client.headers['Content-Type'] = 'application/json'
103
+ client.headers['User-Agent'] = "binance-connector-ruby/#{Binance::VERSION}"
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Binance
4
+ class Spot
5
+ # BLVT endpoints
6
+ # @see https://binance-docs.github.io/apidocs/spot/en/#blvt-endpoints
7
+ module Blvt
8
+ # Get BLVT Info (MARKET_DATA)
9
+ #
10
+ # GET /sapi/v1/blvt/tokenInfo
11
+ #
12
+ # @param tokenName [String]
13
+ # @see https://binance-docs.github.io/apidocs/spot/en/#get-blvt-info-market_data
14
+ def token_info(tokenName: nil)
15
+ @session.public_request(
16
+ path: '/sapi/v1/blvt/tokenInfo',
17
+ params: { tokenName: tokenName }
18
+ )
19
+ end
20
+
21
+ # Subscribe BLVT (USER_DATA)
22
+ #
23
+ # POST /sapi/v1/blvt/subscribe
24
+ #
25
+ # @param tokenName [String]
26
+ # @param cost [Float]
27
+ # @param kwargs [Hash]
28
+ # @option kwargs [Integer] :recvWindow The value cannot be greater than 60000
29
+ # @see https://binance-docs.github.io/apidocs/spot/en/#subscribe-blvt-user_data
30
+ def subscribe(tokenName:, cost:, **kwargs)
31
+ Binance::Utils::Validation.require_param('tokenName', tokenName)
32
+ Binance::Utils::Validation.require_param('cost', cost)
33
+
34
+ @session.sign_request(:post, '/sapi/v1/blvt/subscribe', params: kwargs.merge(
35
+ tokenName: tokenName,
36
+ cost: cost
37
+ ))
38
+ end
39
+
40
+ # Query Subscription Record (USER_DATA)
41
+ #
42
+ # GET /sapi/v1/blvt/subscribe/record
43
+ #
44
+ # @param kwargs [Hash]
45
+ # @option kwargs [String] :tokenName
46
+ # @option kwargs [Integer] :id
47
+ # @option kwargs [Integer] :startTime
48
+ # @option kwargs [Integer] :endTime
49
+ # @option kwargs [Integer] :limit
50
+ # @option kwargs [Integer] :recvWindow The value cannot be greater than 60000
51
+ # @see https://binance-docs.github.io/apidocs/spot/en/#query-subscription-record-user_data
52
+ def get_subscribe_record(**kwargs)
53
+ @session.sign_request(:get, '/sapi/v1/blvt/subscribe/record', params: kwargs)
54
+ end
55
+
56
+ # Redeem BLVT (USER_DATA)
57
+ #
58
+ # POST /sapi/v1/blvt/redeem
59
+ #
60
+ # @param tokenName [String]
61
+ # @param amount [Float]
62
+ # @param kwargs [Hash]
63
+ # @option kwargs [Integer] :recvWindow The value cannot be greater than 60000
64
+ # @see https://binance-docs.github.io/apidocs/spot/en/#redeem-blvt-user_data
65
+ def redeem(tokenName:, amount:, **kwargs)
66
+ Binance::Utils::Validation.require_param('tokenName', tokenName)
67
+ Binance::Utils::Validation.require_param('amount', amount)
68
+
69
+ @session.sign_request(:post, '/sapi/v1/blvt/redeem', params: kwargs.merge(
70
+ tokenName: tokenName,
71
+ amount: amount
72
+ ))
73
+ end
74
+
75
+ # Query Redemption Record (USER_DATA)
76
+ #
77
+ # GET /sapi/v1/blvt/redeem/record
78
+ #
79
+ # @param kwargs [Hash]
80
+ # @option kwargs [String] :tokenName
81
+ # @option kwargs [Integer] :id
82
+ # @option kwargs [Integer] :startTime
83
+ # @option kwargs [Integer] :endTime
84
+ # @option kwargs [Integer] :limit
85
+ # @option kwargs [Integer] :recvWindow The value cannot be greater than 60000
86
+ # @see https://binance-docs.github.io/apidocs/spot/en/#query-redemption-record-user_data
87
+ def get_redeem_record(**kwargs)
88
+ @session.sign_request(:get, '/sapi/v1/blvt/redeem/record', params: kwargs)
89
+ end
90
+
91
+ # Get BLVT User Limit Info (USER_DATA)
92
+ #
93
+ # GET /sapi/v1/blvt/userLimit
94
+ #
95
+ # @param kwargs [Hash]
96
+ # @option kwargs [String] :tokenName
97
+ # @option kwargs [Integer] :recvWindow The value cannot be greater than 60000
98
+ # @see https://binance-docs.github.io/apidocs/spot/en/#get-blvt-user-limit-info-user_data
99
+ def user_limit(**kwargs)
100
+ @session.sign_request(:get, '/sapi/v1/blvt/userLimit', params: kwargs)
101
+ end
102
+ end
103
+ end
104
+ end