binance-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc14abcbaf6d47284c2adfbb849b57251fe62b5d
4
+ data.tar.gz: d708faac09d2f3e6a9cebb23837233c2b7b7da5f
5
+ SHA512:
6
+ metadata.gz: bd63b319fe53d0c3c60f840afd35daa408766d43390808f7080ca27dcaba147bbb4a87b270a6e02638a73c7b6d3a0e48339788f3e15e01696e36d14ca657a637
7
+ data.tar.gz: 47134301c56bd56d8a4d01feb1cd67190ca8d7ade700a4959c3440cffbc3b25fe3eb2ee768fae16161683fe53060a2a4efd25cb610e46005a7c18ff0f6714bf8
@@ -0,0 +1,51 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ # specify the version you desire here
10
+ - image: circleci/ruby:2.4.1-node-browsers
11
+
12
+ # Specify service dependencies here if necessary
13
+ # CircleCI maintains a library of pre-built images
14
+ # documented at https://circleci.com/docs/2.0/circleci-images/
15
+ # - image: circleci/postgres:9.4
16
+
17
+ working_directory: ~/binance-ruby
18
+
19
+ steps:
20
+ - checkout
21
+
22
+ # Download and cache dependencies
23
+ - restore_cache:
24
+ keys:
25
+ - v1-dependencies-{{ checksum "binance-ruby.gemspec" }}
26
+ # fallback to using the latest cache if no exact match is found
27
+ - v1-dependencies-
28
+
29
+ - run:
30
+ name: install dependencies
31
+ command: |
32
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
33
+
34
+ - save_cache:
35
+ paths:
36
+ - ./vendor/bundle
37
+ key: v1-dependencies-{{ checksum "binance-ruby.gemspec" }}
38
+
39
+ # run tests!
40
+ - run:
41
+ name: run tests
42
+ command: |
43
+ mkdir /tmp/test-results
44
+ bundle exec rspec --format progress
45
+
46
+ # collect reports
47
+ - store_test_results:
48
+ path: /tmp/test-results
49
+ - store_artifacts:
50
+ path: /tmp/test-results
51
+ destination: test-results
@@ -0,0 +1,5 @@
1
+ BINANCE_READ_INFO_API_KEY=example-read-info-key
2
+ BINANCE_TRADING_API_KEY=example-trading-key
3
+ BINANCE_WITHDRAWALS_API_KEY=example-withdrawals-key
4
+ BINANCE_API_KEY=example-api-key
5
+ BINANCE_SECRET_KEY=example-secret-key
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /coverage/
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+
15
+ .env
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.2
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in binance-ruby.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Jake Peterson
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Jake Peterson
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.
@@ -0,0 +1,107 @@
1
+ # Binance::Api [![Circle CI](https://circleci.com/gh/Jakenberg/binance-ruby.svg?style=shield)](https://circleci.com/gh/Jakenberg/binance-ruby) [![codecov](https://codecov.io/gh/Jakenberg/binance-ruby/branch/master/graph/badge.svg)](https://codecov.io/gh/Jakenberg/binance-ruby)
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'binance-ruby'
9
+ ```
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install binance-ruby
18
+
19
+ ## Setup
20
+
21
+ ### Environment Variables
22
+
23
+ At minimum, you must configure the following environment variables:
24
+
25
+ ```bash
26
+ BINANCE_API_KEY
27
+ BINANCE_SECRET_KEY
28
+ ```
29
+
30
+ Additionally, Binance allows granular API key access based on the action being taken. For example, it is possible to use one API key for _only_ trade actions, while using another for withdrawal actions. You can configure this using any of the following keys:
31
+
32
+ ```bash
33
+ BINANCE_READ_INFO_API_KEY
34
+ BINANCE_TRADING_API_KEY
35
+ BINANCE_WITHDRAWALS_API_KEY
36
+ ```
37
+
38
+ If any one of these keys are not defined, `binance-ruby` will fallback to `BINANCE_API_KEY`.
39
+
40
+ ## Usage
41
+
42
+ I highly recommend reading the [official Binance documentation](https://github.com/binance-exchange/binance-official-api-docs) before using this gem. Anything missed here is surely well explained there.
43
+
44
+ ### Binance::Api
45
+
46
+ - [`candlesticks!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#klinecandlestick-data): Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time.
47
+ - [`compressed_aggregate_trades!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list): Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same price will have the quantity aggregated.
48
+ - [`depth!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#order-book): Get your order book.
49
+ - [`exchange_info!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#exchange-information): Current exchange trading rules and symbol information.
50
+ - [`historical_trades!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#old-trade-lookup-market_data): Get older trades.
51
+ - [`ping!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#test-connectivity): Test connectivity to the Rest API.
52
+ - [`ticker!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#24hr-ticker-price-change-statistics): Price change statistics. **Careful** when accessing this with no symbol.
53
+ - [`time!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#check-server-time): Test connectivity to the Rest API and get the current server time.
54
+ - [`trades!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#recent-trades-list): Get recent trades (up to last 500).
55
+
56
+ ### Binance::Api::Account
57
+
58
+ - [`info!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-information-user_data): Get current account information.
59
+ - [`trades!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#account-trade-list-user_data): Get trades for a specific account and symbol.
60
+
61
+ ### Binance::Api::DataStream
62
+
63
+ - [`start!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#start-user-data-stream-user_stream): Start a new user data stream. The stream will close after 60 minutes unless a keepalive is sent.
64
+ - [`keepalive!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#keepalive-user-data-stream-user_stream): Keepalive a user data stream to prevent a time out. User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
65
+ - [`stop!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#close-user-data-stream-user_stream): Close out a user data stream.
66
+
67
+ ### Binance::Api::Order
68
+
69
+ - [`all!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#all-orders-user_data): Get all account orders; active, canceled, or filled.
70
+ - [`all_open!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#current-open-orders-user_data): Get all open orders on a symbol. **Careful** when accessing this with no symbol.
71
+ - [`cancel!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#cancel-order-trade): Cancel an active order.
72
+ - [`create!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#new-order--trade): Send in a new order. Use `test: true` for test orders.
73
+ - [`status!`](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#query-order-user_data): Check an order's status.
74
+
75
+ For more information, please refer to the [official Rest API documentation](https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md) written by the Binance team.
76
+
77
+ ## Author
78
+
79
+ [Jake Peterson](https://jakenberg.io)
80
+
81
+ I drink beer 😉
82
+
83
+ **BTC**: `1EZTj5rEaKE9dEBjR1wiismwma4XpXtLBz`
84
+
85
+ **ETH**: `0xf61195dcb1e89f139114e599cf1dd37dd8b7b96a`
86
+
87
+ **LTC**: `LL3Nf7CmLoFeLENSKN6WhgPNVuxjzgh2eV`
88
+
89
+ **BCH**: [Bcash. LOL](https://www.youtube.com/watch?v=oCOjCEth6xI)
90
+
91
+ ## Development
92
+
93
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
94
+
95
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
96
+
97
+ ## Contributing
98
+
99
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jakenberg/binance-ruby.
100
+
101
+ ### TODO
102
+ - Convert milliseconds to ruby DateTime.
103
+ - CodeCov account & badge.
104
+
105
+ ## License
106
+
107
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "binance/ruby"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,47 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "binance/api/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "binance-ruby"
8
+ spec.version = Binance::Api::VERSION
9
+ spec.authors = ["Jake Peterson"]
10
+ spec.email = ["hello@jakenberg.io"]
11
+
12
+ spec.summary = %q{Ruby gem for the Binance API.}
13
+ spec.description = %q{
14
+ - Official Announcements regarding changes, downtime, etc. to the API and Streams will be reported here: https://t.me/binance_api_announcements
15
+ - Streams, endpoints, parameters, payloads, etc. decscribed in the documents in this repository are considered official and supported.
16
+ }
17
+ spec.homepage = "https://github.com/jakenberg/binance-ruby"
18
+ spec.license = "MIT"
19
+
20
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
21
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
22
+ if spec.respond_to?(:metadata)
23
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
24
+ else
25
+ raise "RubyGems 2.0 or newer is required to protect against " \
26
+ "public gem pushes."
27
+ end
28
+
29
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
30
+ f.match(%r{^(test|spec|features)/})
31
+ end
32
+ spec.bindir = "exe"
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ["lib"]
35
+
36
+ spec.add_development_dependency "bundler", "~> 1.15"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "rspec", "~> 3.0"
39
+ spec.add_development_dependency "webmock", '~> 3.0'
40
+ spec.add_development_dependency 'pry', '~> 0.11.0'
41
+ spec.add_development_dependency 'dotenv-rails', '~> 2.2.0'
42
+ spec.add_development_dependency 'codecov', '~> 0.1'
43
+
44
+ spec.add_dependency 'awrence', '~> 1.0'
45
+ spec.add_dependency 'httparty', '~> 0.15'
46
+ spec.add_dependency 'activesupport-core-ext', '~> 4.0.0'
47
+ end
@@ -0,0 +1,74 @@
1
+ require 'active_support/core_ext/string'
2
+ require 'awrence'
3
+ require 'httparty'
4
+ require 'binance/api/account'
5
+ require 'binance/api/configuration'
6
+ require 'binance/api/data_stream'
7
+ require 'binance/api/error'
8
+ require 'binance/api/order'
9
+ require 'binance/api/request'
10
+ require "binance/api/version"
11
+
12
+ module Binance
13
+ module Api
14
+ class << self
15
+ # Valid limits:[5, 10, 20, 50, 100, 500, 1000]
16
+ def candlesticks!(end_time: nil, interval: nil, limit: 500, start_time: nil, symbol: nil)
17
+ raise Error.new(message: 'interval is required') unless interval
18
+ raise Error.new(message: 'symbol is required') unless symbol
19
+ params = { endTime: end_time, interval: interval, limit: limit, startTime: start_time, symbol: symbol }
20
+ Request.send!(api_key_type: :read_info, path: '/api/v1/klines', params: params)
21
+ end
22
+
23
+ def compressed_aggregate_trades!(end_time: nil, from_id: nil, limit: 500, start_time: nil, symbol: nil)
24
+ raise Error.new(message: "symbol is required") unless symbol
25
+ params = { endTime: end_time, fromId: from_id, limit: limit, startTime: start_time, symbol: symbol }
26
+ Request.send!(api_key_type: :read_info, path: '/api/v1/aggTrades', params: params)
27
+ end
28
+
29
+ def depth!(symbol: nil, limit: 100)
30
+ raise Error.new(message: "symbol is required") unless symbol
31
+ params = { limit: limit, symbol: symbol }
32
+ Request.send!(api_key_type: :read_info, path: '/api/v1/depth', params: params)
33
+ end
34
+
35
+ def exchange_info!
36
+ Request.send!(api_key_type: :read_info, path: '/api/v1/exchangeInfo')
37
+ end
38
+
39
+ def historical_trades!(symbol: nil, limit: 500, from_id: nil)
40
+ raise Error.new(message: "symbol is required") unless symbol
41
+ params = { fromId: from_id, limit: limit, symbol: symbol }
42
+ Request.send!(api_key_type: :read_info, path: '/api/v1/historicalTrades', params: params, security_type: :market_data)
43
+ end
44
+
45
+ def ping!
46
+ Request.send!(path: '/api/v1/ping')
47
+ end
48
+
49
+ def ticker!(symbol: nil, type: nil)
50
+ ticker_type = type&.to_sym
51
+ error_message = "type must be one of: #{ticker_types.join(', ')}. #{type} was provided."
52
+ raise Error.new(message: error_message) unless ticker_types.include? ticker_type
53
+ params = symbol ? { symbol: symbol } : {}
54
+ Request.send!(api_key_type: :read_info, path: "/api/v3/ticker/#{type.to_s.camelcase(:lower)}", params: params)
55
+ end
56
+
57
+ def time!
58
+ Request.send!(path: '/api/v1/time')
59
+ end
60
+
61
+ def trades!(symbol: nil, limit: 500)
62
+ raise Error.new(message: "symbol is required") unless symbol
63
+ params = { limit: limit, symbol: symbol }
64
+ Request.send!(api_key_type: :read_info, path: '/api/v1/trades', params: params)
65
+ end
66
+
67
+ private
68
+
69
+ def ticker_types
70
+ [:daily, :price, :book_ticker].freeze
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,25 @@
1
+ module Binance
2
+ module Api
3
+ class Account
4
+ class << self
5
+ def info!(recv_window: 5000)
6
+ timestamp = Configuration.timestamp
7
+ params = { recvWindow: recv_window, timestamp: timestamp }
8
+ Request.send!(api_key_type: :read_info, path: "/api/v3/account",
9
+ params: params.delete_if { |key, value| value.nil? },
10
+ security_type: :user_data)
11
+ end
12
+
13
+ def trades!(from_id: nil, limit: 500, recv_window: 5000, symbol: nil)
14
+ raise Error.new(message: "max limit is 500") unless limit <= 500
15
+ raise Error.new(message: "symbol is required") if symbol.nil?
16
+ timestamp = Configuration.timestamp
17
+ params = { fromId: from_id, limit: limit, recvWindow: recv_window, symbol: symbol, timestamp: timestamp }
18
+ Request.send!(api_key_type: :read_info, path: "/api/v3/myTrades",
19
+ params: params.delete_if { |key, value| value.nil? },
20
+ security_type: :user_data)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Binance
5
+ module Api
6
+ class Configuration
7
+ class << self
8
+ def api_key(type:)
9
+ raise Error.new(message: "invalid security_type type: #{type}.") unless api_key_types.include?(type)
10
+ ENV["BINANCE_#{type.to_s.humanize.upcase}_API_KEY"] || ENV["BINANCE_API_KEY"]
11
+ end
12
+
13
+ def signed_request_signature(payload:)
14
+ key = ENV['BINANCE_SECRET_KEY']
15
+ raise Error.new(message: "environment variable 'BINANCE_SECRET_KEY' is required "\
16
+ "for signed requests.") unless key
17
+ Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, payload)).strip()
18
+ end
19
+
20
+ def timestamp
21
+ Time.now.to_i
22
+ end
23
+
24
+ private
25
+
26
+ def api_key_types
27
+ [:none, :read_info, :trading, :withdrawals].freeze
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ module Binance
2
+ module Api
3
+ class DataStream
4
+ class << self
5
+ # It's recommended to send a ping about every 30 minutes.
6
+ def keepalive!(listen_key: nil)
7
+ raise Error.new(message: "listen_key is required") if listen_key.nil?
8
+ Request.send!(api_key_type: :none, method: :put, path: "/api/v1/userDataStream",
9
+ params: { listenKey: listen_key }, security_type: :user_stream)
10
+ end
11
+
12
+ def start!
13
+ Request.send!(api_key_type: :none, method: :post, path: "/api/v1/userDataStream",
14
+ security_type: :user_stream)
15
+ end
16
+
17
+ def stop!(listen_key: nil)
18
+ raise Error.new(message: "listen_key is required") if listen_key.nil?
19
+ Request.send!(api_key_type: :none, method: :delete, path: "/api/v1/userDataStream",
20
+ params: { listenKey: listen_key }, security_type: :user_stream)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ module Binance
2
+ module Api
3
+ class Error < StandardError
4
+ attr_reader :code, :msg
5
+
6
+ class << self
7
+ # https://github.com/binance-exchange/binance-official-api-docs/blob/master/errors.md
8
+ def is_error_response?(json:)
9
+ return false if json.is_a? Array
10
+ code = json[:code]&.to_i
11
+ code && code >= 400
12
+ end
13
+ end
14
+
15
+ def initialize(code: nil, json: {}, message: nil)
16
+ @code = code || json[:code]
17
+ @msg = message || json[:msg]
18
+ end
19
+
20
+ def inspect
21
+ message = "Binance::Api::Error"
22
+ message += " (#{code})" unless code.nil?
23
+ message += ": #{msg}"
24
+ message += "\nbacktrace: #{backtrace}"
25
+ end
26
+
27
+ def message
28
+ inspect
29
+ end
30
+
31
+ def to_s
32
+ inspect
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ module Binance
2
+ module Api
3
+ class Order
4
+ class << self
5
+ def all!(limit: 500, order_id: nil, recv_window: 5000, symbol: nil)
6
+ raise Error.new(message: "max limit is 500") unless limit <= 500
7
+ raise Error.new(message: "symbol is required") if symbol.nil?
8
+ timestamp = Configuration.timestamp
9
+ params = { limit: limit, orderId: order_id, recvWindow: recv_window, symbol: symbol, timestamp: timestamp }
10
+ Request.send!(api_key_type: :read_info, path: "/api/v3/allOrders",
11
+ params: params.delete_if { |key, value| value.nil? },
12
+ security_type: :user_data)
13
+ end
14
+
15
+ # Be careful when accessing without a symbol!
16
+ def all_open!(recv_window: 5000, symbol: nil)
17
+ timestamp = Configuration.timestamp
18
+ params = { recvWindow: recv_window, symbol: symbol, timestamp: timestamp }
19
+ Request.send!(api_key_type: :read_info, path: '/api/v3/openOrders',
20
+ params: params, security_type: :user_data)
21
+ end
22
+
23
+ def cancel!(order_id: nil, original_client_order_id: nil, new_client_order_id: nil, recv_window: nil, symbol: nil)
24
+ raise Error.new(message: "symbol is required") if symbol.nil?
25
+ raise Error.new(message: "either order_id or original_client_order_id " \
26
+ "is required") if order_id.nil? && original_client_order_id.nil?
27
+ timestamp = Configuration.timestamp
28
+ params = { orderId: order_id, origClientOrderId: original_client_order_id,
29
+ newClientOrderId: new_client_order_id, recvWindow: recv_window,
30
+ symbol: symbol, timestamp: timestamp }.delete_if { |key, value| value.nil? }
31
+ Request.send!(api_key_type: :trading, method: :delete, path: "/api/v3/order",
32
+ params: params, security_type: :trade)
33
+ end
34
+
35
+ def create!(iceberg_quantity: nil, new_client_order_id: nil, new_order_response_type: nil,
36
+ price: nil, quantity: nil, recv_window: nil, stop_price: nil, symbol: nil,
37
+ side: nil, type: nil, time_in_force: nil, test: false)
38
+ timestamp = Configuration.timestamp
39
+ ensure_required_create_keys!(params: {
40
+ iceberg_quantity: iceberg_quantity, new_client_order_id: new_client_order_id,
41
+ new_order_response_type: new_order_response_type, price: price,
42
+ quantity: quantity, recv_window: recv_window, stop_price: stop_price,
43
+ symbol: symbol, side: side, type: type, time_in_force: time_in_force,
44
+ timestamp: timestamp
45
+ })
46
+ params = {
47
+ icebergQty: iceberg_quantity, newClientOrderId: new_client_order_id,
48
+ newOrderRespType: new_order_response_type, price: price, quantity: quantity,
49
+ recvWindow: recv_window, stopPrice: stop_price, symbol: symbol, side: side,
50
+ type: type, timeInForce: time_in_force, timestamp: timestamp
51
+ }.delete_if { |key, value| value.nil? }
52
+ path = "/api/v3/order#{'/test' if test}"
53
+ Request.send!(api_key_type: :trading, method: :post, path: path,
54
+ params: params, security_type: :trade)
55
+ end
56
+
57
+ def status!(order_id: nil, original_client_order_id: nil, recv_window: nil, symbol: nil)
58
+ raise Error.new(message: "symbol is required") if symbol.nil?
59
+ raise Error.new(message: "either order_id or original_client_order_id " \
60
+ "is required") if order_id.nil? && original_client_order_id.nil?
61
+ timestamp = Configuration.timestamp
62
+ params = {
63
+ orderId: order_id, origClientOrderId: original_client_order_id, recvWindow: recv_window,
64
+ symbol: symbol, timestamp: timestamp
65
+ }.delete_if { |key, value| value.nil? }
66
+ Request.send!(api_key_type: :trading, path: "/api/v3/order",
67
+ params: params, security_type: :user_data)
68
+ end
69
+
70
+ private
71
+
72
+ def additional_required_create_keys(type:)
73
+ case type
74
+ when :limit
75
+ [:price, :time_in_force].freeze
76
+ when :stop_loss, :take_profit
77
+ [:stop_price].freeze
78
+ when :stop_loss_limit, :take_profit_limit
79
+ [:price, :stop_price, :time_in_force].freeze
80
+ when :limit_maker
81
+ [:price].freeze
82
+ else
83
+ [].freeze
84
+ end
85
+ end
86
+
87
+ def ensure_required_create_keys!(params:)
88
+ keys = required_create_keys.dup.concat(additional_required_create_keys(type: params[:type]))
89
+ missing_keys = keys.select { |key| params[key].nil? }
90
+ raise Error.new(message: "required keys are missing: #{missing_keys.join(', ')}") unless missing_keys.empty?
91
+ end
92
+
93
+ def required_create_keys
94
+ [:symbol, :side, :type, :quantity, :timestamp].freeze
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,63 @@
1
+ module Binance
2
+ module Api
3
+ class Request
4
+ include HTTParty
5
+
6
+ base_uri 'https://api.binance.com'
7
+
8
+ class << self
9
+ def send!(api_key_type: :none, headers: {}, method: :get, path: '/', params: {}, security_type: :none)
10
+ raise Error.new(message: "invalid security type #{security_type}") unless security_types.include?(security_type)
11
+ all_headers = default_headers(api_key_type: api_key_type, security_type: security_type)
12
+ if [:trade, :user_data].include?(security_type)
13
+ params.merge!(
14
+ signature: signed_request_signature(params: params),
15
+ timestamp: timestamp
16
+ )
17
+ end
18
+ # send() is insecure so don't use it.
19
+ case method
20
+ when :get
21
+ response = get(path, headers: all_headers, query: params)
22
+ when :post
23
+ response = post(path, body: params, headers: all_headers)
24
+ when :put
25
+ response = put(path, body: params, headers: all_headers)
26
+ when :delete
27
+ response = delete(path, body: params, headers: all_headers)
28
+ else
29
+ raise Error.new(message: "invalid http method used: #{method}")
30
+ end
31
+ process!(response: response || '{}')
32
+ end
33
+
34
+ private
35
+
36
+ def default_headers(api_key_type:, security_type:)
37
+ headers = {}
38
+ headers['X-MBX-APIKEY'] = Configuration.api_key(type: api_key_type) unless security_type == :none
39
+ headers
40
+ end
41
+
42
+ def process!(response: '')
43
+ json = JSON.parse(response, symbolize_names: true)
44
+ raise Error.new(json: json) if Error.is_error_response?(json: json)
45
+ json
46
+ end
47
+
48
+ def security_types
49
+ [:none, :trade, :user_data, :user_stream, :market_data].freeze
50
+ end
51
+
52
+ def signed_request_signature(params:)
53
+ payload = params.map { |key, value| "#{key}=#{value}" }.join('&')
54
+ Configuration.signed_request_signature(payload: payload)
55
+ end
56
+
57
+ def timestamp
58
+ Time.now.to_i
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ module Binance
2
+ module Api
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binance-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jake Peterson
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-01-03 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: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.11.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.11.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.2.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.2.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: codecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: awrence
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: httparty
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.15'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.15'
139
+ - !ruby/object:Gem::Dependency
140
+ name: activesupport-core-ext
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 4.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 4.0.0
153
+ description: "\n - Official Announcements regarding changes, downtime, etc. to
154
+ the API and Streams will be reported here: https://t.me/binance_api_announcements\n
155
+ \ - Streams, endpoints, parameters, payloads, etc. decscribed in the documents
156
+ in this repository are considered official and supported.\n "
157
+ email:
158
+ - hello@jakenberg.io
159
+ executables: []
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - ".circleci/config.yml"
164
+ - ".env.example"
165
+ - ".gitignore"
166
+ - ".rspec"
167
+ - ".travis.yml"
168
+ - Gemfile
169
+ - LICENSE
170
+ - LICENSE.txt
171
+ - README.md
172
+ - Rakefile
173
+ - bin/console
174
+ - bin/setup
175
+ - binance-ruby.gemspec
176
+ - lib/binance/api.rb
177
+ - lib/binance/api/account.rb
178
+ - lib/binance/api/configuration.rb
179
+ - lib/binance/api/data_stream.rb
180
+ - lib/binance/api/error.rb
181
+ - lib/binance/api/order.rb
182
+ - lib/binance/api/request.rb
183
+ - lib/binance/api/version.rb
184
+ homepage: https://github.com/jakenberg/binance-ruby
185
+ licenses:
186
+ - MIT
187
+ metadata:
188
+ allowed_push_host: https://rubygems.org
189
+ post_install_message:
190
+ rdoc_options: []
191
+ require_paths:
192
+ - lib
193
+ required_ruby_version: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ required_rubygems_version: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ requirements: []
204
+ rubyforge_project:
205
+ rubygems_version: 2.5.2
206
+ signing_key:
207
+ specification_version: 4
208
+ summary: Ruby gem for the Binance API.
209
+ test_files: []