binance-connector 1.0.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 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