bitsor 0.1.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 +7 -0
- data/.circleci/config.yml +61 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +45 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +74 -0
- data/Rakefile +9 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/bitsor.gemspec +33 -0
- data/lib/bitsor/client/account_status.rb +14 -0
- data/lib/bitsor/client/available_books.rb +14 -0
- data/lib/bitsor/client/balance.rb +14 -0
- data/lib/bitsor/client/bitcoin_withdrawal.rb +12 -0
- data/lib/bitsor/client/debit_card_withdrawal.rb +12 -0
- data/lib/bitsor/client/ether_withdrawal.rb +12 -0
- data/lib/bitsor/client/fees.rb +14 -0
- data/lib/bitsor/client/funding.rb +14 -0
- data/lib/bitsor/client/funding_destination.rb +14 -0
- data/lib/bitsor/client/kyc_documents.rb +12 -0
- data/lib/bitsor/client/ledger.rb +38 -0
- data/lib/bitsor/client/mx_bank_codes.rb +12 -0
- data/lib/bitsor/client/open_orders.rb +14 -0
- data/lib/bitsor/client/order_book.rb +12 -0
- data/lib/bitsor/client/order_trades.rb +12 -0
- data/lib/bitsor/client/orders.rb +22 -0
- data/lib/bitsor/client/phone_number.rb +12 -0
- data/lib/bitsor/client/phone_number_withdrawal.rb +12 -0
- data/lib/bitsor/client/phone_verification.rb +12 -0
- data/lib/bitsor/client/spei_withdrawal.rb +12 -0
- data/lib/bitsor/client/ticker.rb +14 -0
- data/lib/bitsor/client/trades.rb +14 -0
- data/lib/bitsor/client/user_trades.rb +14 -0
- data/lib/bitsor/client/withdrawals.rb +12 -0
- data/lib/bitsor/client.rb +86 -0
- data/lib/bitsor/concerns/authorizable.rb +10 -0
- data/lib/bitsor/concerns/configurable.rb +41 -0
- data/lib/bitsor/concerns/connection.rb +86 -0
- data/lib/bitsor/concerns/rate_limit.rb +18 -0
- data/lib/bitsor/default.rb +32 -0
- data/lib/bitsor/error.rb +96 -0
- data/lib/bitsor/normalizer.rb +138 -0
- data/lib/bitsor/version.rb +20 -0
- data/lib/bitsor.rb +33 -0
- metadata +148 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
class Client
|
5
|
+
module Trades
|
6
|
+
def trades(book:, marker: nil, sort: :desc, limit: 25)
|
7
|
+
normalize_response.with(:trade) do
|
8
|
+
get('/v3/trades/', book: book, marker: marker, sort: sort, limit: limit)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
class Client
|
5
|
+
module UserTrades
|
6
|
+
def user_trades(book:, marker: nil, sort: :desc, limit: 25)
|
7
|
+
normalize_response.with(:user_trade) do
|
8
|
+
get('/v3/user_trades/', book: book, marker: marker, sort: sort, limit: limit)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bitsor/error'
|
4
|
+
require 'bitsor/normalizer'
|
5
|
+
|
6
|
+
require 'bitsor/concerns/configurable'
|
7
|
+
require 'bitsor/concerns/rate_limit'
|
8
|
+
require 'bitsor/concerns/connection'
|
9
|
+
require 'bitsor/concerns/authorizable'
|
10
|
+
|
11
|
+
require 'bitsor/client/account_status'
|
12
|
+
require 'bitsor/client/available_books'
|
13
|
+
require 'bitsor/client/balance'
|
14
|
+
require 'bitsor/client/bitcoin_withdrawal'
|
15
|
+
require 'bitsor/client/debit_card_withdrawal'
|
16
|
+
require 'bitsor/client/ether_withdrawal'
|
17
|
+
require 'bitsor/client/fees'
|
18
|
+
require 'bitsor/client/funding'
|
19
|
+
require 'bitsor/client/funding_destination'
|
20
|
+
require 'bitsor/client/kyc_documents'
|
21
|
+
require 'bitsor/client/ledger'
|
22
|
+
require 'bitsor/client/mx_bank_codes'
|
23
|
+
require 'bitsor/client/open_orders'
|
24
|
+
require 'bitsor/client/order_book'
|
25
|
+
require 'bitsor/client/order_trades'
|
26
|
+
require 'bitsor/client/orders'
|
27
|
+
require 'bitsor/client/phone_number'
|
28
|
+
require 'bitsor/client/phone_number_withdrawal'
|
29
|
+
require 'bitsor/client/phone_verification'
|
30
|
+
require 'bitsor/client/spei_withdrawal'
|
31
|
+
require 'bitsor/client/ticker'
|
32
|
+
require 'bitsor/client/trades'
|
33
|
+
require 'bitsor/client/user_trades'
|
34
|
+
require 'bitsor/client/withdrawals'
|
35
|
+
|
36
|
+
module Bitsor
|
37
|
+
class Client
|
38
|
+
include Bitsor::Configurable
|
39
|
+
include Bitsor::Connection
|
40
|
+
include Bitsor::Authorizable
|
41
|
+
|
42
|
+
include Bitsor::Client::AccountStatus
|
43
|
+
include Bitsor::Client::AvailableBooks
|
44
|
+
include Bitsor::Client::Balance
|
45
|
+
include Bitsor::Client::BitcoinWithdrawal
|
46
|
+
include Bitsor::Client::DebitCardWithdrawal
|
47
|
+
include Bitsor::Client::EtherWithdrawal
|
48
|
+
include Bitsor::Client::Fees
|
49
|
+
include Bitsor::Client::Funding
|
50
|
+
include Bitsor::Client::FundingDestination
|
51
|
+
include Bitsor::Client::KycDocuments
|
52
|
+
include Bitsor::Client::Ledger
|
53
|
+
include Bitsor::Client::MxBankCodes
|
54
|
+
include Bitsor::Client::OpenOrders
|
55
|
+
include Bitsor::Client::OrderBook
|
56
|
+
include Bitsor::Client::OrderTrades
|
57
|
+
include Bitsor::Client::Orders
|
58
|
+
include Bitsor::Client::PhoneNumber
|
59
|
+
include Bitsor::Client::PhoneNumberWithdrawal
|
60
|
+
include Bitsor::Client::PhoneVerification
|
61
|
+
include Bitsor::Client::SpeiWithdrawal
|
62
|
+
include Bitsor::Client::Ticker
|
63
|
+
include Bitsor::Client::Trades
|
64
|
+
include Bitsor::Client::UserTrades
|
65
|
+
include Bitsor::Client::Withdrawals
|
66
|
+
|
67
|
+
attr_writer :client_id
|
68
|
+
attr_writer :api_key
|
69
|
+
attr_writer :api_secret
|
70
|
+
|
71
|
+
def initialize(options = {})
|
72
|
+
Bitsor::Configurable.keys.each do |key|
|
73
|
+
instance_variable_set(:"@#{key}", options[key] || Bitsor.instance_variable_get(:"@#{key}"))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def inspect
|
78
|
+
"Bitsor::Client(client_id: ****#{@client_id[4..-1]} api_key: ******#{@api_key[6..-1]}, object_id: #{format('0x00%x', (object_id << 1))})"
|
79
|
+
end
|
80
|
+
|
81
|
+
def normalize_response
|
82
|
+
@normalizer ||= Normalizer.new
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
module Configurable
|
5
|
+
attr_accessor :client_id, :api_key, :api_secret
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def keys
|
9
|
+
@keys ||= [
|
10
|
+
:client_id,
|
11
|
+
:api_key,
|
12
|
+
:api_secret,
|
13
|
+
]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure
|
18
|
+
yield self
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset!
|
22
|
+
Bitsor::Configurable.keys.each do |key|
|
23
|
+
instance_variable_set(:"@#{key}", Bitsor::Default.options[key])
|
24
|
+
end
|
25
|
+
@last_response = nil
|
26
|
+
self
|
27
|
+
end
|
28
|
+
alias setup reset!
|
29
|
+
|
30
|
+
def api_endpoint
|
31
|
+
File.join(@api_endpoint, '')
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def options
|
37
|
+
Hash[Bitsor::Configurable.keys.map { |key| [key, instance_variable_get(:"@#{key}")] }]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'json'
|
5
|
+
require 'openssl'
|
6
|
+
require 'typhoeus'
|
7
|
+
|
8
|
+
require 'bitsor/error'
|
9
|
+
|
10
|
+
module Bitsor
|
11
|
+
module Connection
|
12
|
+
def get(url, options = {})
|
13
|
+
request :get, url, nil, parse_query(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def post(url, options = {})
|
17
|
+
request :post, url, parse_body(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def put(url, options = {})
|
21
|
+
request :put, url, parse_body(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def patch(url, options = {})
|
25
|
+
request :patch, url, parse_body(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(url, options = {})
|
29
|
+
request :delete, url, parse_body(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def last_response
|
33
|
+
@last_response if defined? @last_response
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def endpoint
|
39
|
+
Bitsor::Default.api_endpoint
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def request(method, path, body = nil, params = nil)
|
45
|
+
nonce = DateTime.now.strftime('%Q')
|
46
|
+
message = nonce + method.to_s.upcase + path + params.to_s + body.to_s
|
47
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), api_secret, message)
|
48
|
+
|
49
|
+
url = "#{endpoint}#{path}#{params}"
|
50
|
+
request_options = {
|
51
|
+
method: method,
|
52
|
+
headers: {
|
53
|
+
Authorization: "Bitso #{api_key}:#{nonce}:#{signature}",
|
54
|
+
'Content-Type': 'application/json',
|
55
|
+
},
|
56
|
+
}
|
57
|
+
request_options[:body] = body
|
58
|
+
response = Typhoeus::Request.new(url, request_options).run
|
59
|
+
@last_response = response
|
60
|
+
|
61
|
+
complete_request(response)
|
62
|
+
end
|
63
|
+
|
64
|
+
def complete_request(response)
|
65
|
+
if error = Bitsor::Error.from_response(response)
|
66
|
+
raise error
|
67
|
+
end
|
68
|
+
|
69
|
+
JSON.parse(response.body, symbolize_names: true)[:payload]
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_query(options)
|
73
|
+
return nil if options.empty? || !options
|
74
|
+
|
75
|
+
options = options.select { |_key, value| !value.nil? || (value && !value.empty?) }
|
76
|
+
"?#{URI.encode_www_form(options)}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_body(options)
|
80
|
+
return '' if options.nil? || options.empty?
|
81
|
+
options = (options || {}).delete_if { |_k, v| v.nil? }
|
82
|
+
options.to_json
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
class RateLimit < Struct.new(:limit, :remaining, :resets_at, :resets_in)
|
5
|
+
def self.from_response(response)
|
6
|
+
info = new
|
7
|
+
unless response&.headers.nil?
|
8
|
+
info.limit = (response.headers['X-RateLimit-Limit'] || 1).to_i
|
9
|
+
info.remaining = (response.headers['X-RateLimit-Remaining'] || 1).to_i
|
10
|
+
info.resets_at = Time.at((response.headers['X-RateLimit-Reset'] || Time.now).to_i)
|
11
|
+
info.resets_in = [(info.resets_at - Time.now).to_i, 0].max
|
12
|
+
end
|
13
|
+
|
14
|
+
info
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bitsor/version'
|
4
|
+
|
5
|
+
module Bitsor
|
6
|
+
module Default
|
7
|
+
API_ENDPOINT = 'https://api.bitso.com'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def options
|
11
|
+
Hash[Bitsor::Configurable.keys.map { |key| [key, send(key)] }]
|
12
|
+
end
|
13
|
+
|
14
|
+
def client_id
|
15
|
+
ENV['CLIENT_ID']
|
16
|
+
end
|
17
|
+
|
18
|
+
def api_key
|
19
|
+
ENV['API_KEY']
|
20
|
+
end
|
21
|
+
|
22
|
+
def api_secret
|
23
|
+
ENV['API_SECRET']
|
24
|
+
end
|
25
|
+
|
26
|
+
def api_endpoint
|
27
|
+
ENV['API_ENDPOINT'] || API_ENDPOINT
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/bitsor/error.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
class Error < StandardError
|
5
|
+
def self.from_response(response)
|
6
|
+
status = response.response_code
|
7
|
+
|
8
|
+
if klass = case status
|
9
|
+
when 400 then Bitsor::BadRequest
|
10
|
+
when 401 then Bitsor::Forbidden
|
11
|
+
when 403 then Bitsor::Forbidden
|
12
|
+
when 404 then Bitsor::NotFound
|
13
|
+
when 405 then Bitsor::MethodNotAllowed
|
14
|
+
when 406 then Bitsor::NotAcceptable
|
15
|
+
when 422 then Bitsor::UnprocessableEntity
|
16
|
+
when 400..499 then Bitsor::ClientError
|
17
|
+
when 500 then Bitsor::InternalServerError
|
18
|
+
when 501 then Bitsor::NotImplemented
|
19
|
+
when 502 then Bitsor::BadGateway
|
20
|
+
when 503 then Bitsor::ServiceUnavailable
|
21
|
+
when 500..599 then Bitsor::ServerError
|
22
|
+
end
|
23
|
+
klass.new(response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(response = nil)
|
28
|
+
@response = response
|
29
|
+
@request = response.request
|
30
|
+
@body = { error: {} }
|
31
|
+
|
32
|
+
begin
|
33
|
+
if response.body && !response.body.empty?
|
34
|
+
@body = JSON.parse(response.body, symbolize_names: true)
|
35
|
+
end
|
36
|
+
rescue JSON::ParserError => e
|
37
|
+
@body = { error: { code: response.response_code, message: 'Internal Server Error: An Error Was Encountered' } }
|
38
|
+
end
|
39
|
+
|
40
|
+
super(build_error_message)
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_error_message
|
44
|
+
return nil if @response.nil?
|
45
|
+
message = ["#{@request.options[:method].to_s.upcase} "]
|
46
|
+
message << @response.options[:effective_url].to_s + "\n"
|
47
|
+
message << "Code #{@body[:error][:code]}: #{@body[:error][:message]} \n"
|
48
|
+
message.join
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_accessor :response, :request, :body
|
52
|
+
end
|
53
|
+
|
54
|
+
# Raised on errors in the 400-499 range
|
55
|
+
class ClientError < Error; end
|
56
|
+
|
57
|
+
# Raised when 400 HTTP status code
|
58
|
+
class BadRequest < ClientError; end
|
59
|
+
|
60
|
+
# Raised when 401 HTTP status code
|
61
|
+
class Unauthorized < ClientError; end
|
62
|
+
|
63
|
+
# Raised when 403 HTTP status code
|
64
|
+
class Forbidden < ClientError; end
|
65
|
+
|
66
|
+
# Raised when 403 HTTP status code
|
67
|
+
class TooManyRequests < Forbidden; end
|
68
|
+
|
69
|
+
# Raised when 404 HTTP status code
|
70
|
+
class NotFound < ClientError; end
|
71
|
+
|
72
|
+
# Raised when 405 HTTP status code
|
73
|
+
class MethodNotAllowed < ClientError; end
|
74
|
+
|
75
|
+
# Raised when 406 HTTP status code
|
76
|
+
class NotAcceptable < ClientError; end
|
77
|
+
|
78
|
+
# Raised when 422 HTTP status code
|
79
|
+
class UnprocessableEntity < ClientError; end
|
80
|
+
|
81
|
+
# Raised on errors in the 500-599 range
|
82
|
+
class ServerError < Error; end
|
83
|
+
|
84
|
+
# Raised when 500 HTTP status code
|
85
|
+
class InternalServerError < ServerError; end
|
86
|
+
|
87
|
+
# Raised when 501 HTTP status code
|
88
|
+
class NotImplemented < ServerError; end
|
89
|
+
|
90
|
+
# Raised when 502 HTTP status code
|
91
|
+
class BadGateway < ServerError; end
|
92
|
+
|
93
|
+
# Raised when 503 HTTP status code
|
94
|
+
class ServiceUnavailable < ServerError; end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Bitsor
|
6
|
+
class Normalizer
|
7
|
+
SCHEMAS = {
|
8
|
+
account_balances: 'normalize_account_balances',
|
9
|
+
account_fees: 'normalize_account_fees',
|
10
|
+
account_status: 'normalize_account',
|
11
|
+
book: 'normalize_book',
|
12
|
+
funding: 'normalize_funding',
|
13
|
+
ledger: 'normalize_ledger',
|
14
|
+
order: 'normalize_order',
|
15
|
+
ticker: 'normalize_ticker',
|
16
|
+
trade: 'normalize_trade',
|
17
|
+
user_trade: 'normalize_user_trade',
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def with(type)
|
21
|
+
method = SCHEMAS[type.to_sym] || :null_normalizer
|
22
|
+
|
23
|
+
response = yield
|
24
|
+
|
25
|
+
if response.class == Array
|
26
|
+
return response.map do |response_element|
|
27
|
+
send method, response_element
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
send method, response
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def null_normalizer(response)
|
37
|
+
response
|
38
|
+
end
|
39
|
+
|
40
|
+
def normalize_account(response_object)
|
41
|
+
response_object[:client_id] = response_object[:client_id].to_i
|
42
|
+
response_object[:daily_limit] = response_object[:daily_limit].to_i
|
43
|
+
response_object[:monthly_limit] = response_object[:monthly_limit].to_i
|
44
|
+
response_object[:daily_remaining] = response_object[:daily_remaining].to_f
|
45
|
+
response_object[:monthly_remaining] = response_object[:monthly_remaining].to_f
|
46
|
+
response_object
|
47
|
+
end
|
48
|
+
|
49
|
+
def normalize_account_balances(response_object)
|
50
|
+
response_object[:balances] = response_object[:balances].map do |balance|
|
51
|
+
balance[:available] = balance[:available].to_f
|
52
|
+
balance[:locked] = balance[:locked].to_f
|
53
|
+
balance[:total] = balance[:total].to_f
|
54
|
+
balance[:pending_deposit] = balance[:pending_deposit].to_f
|
55
|
+
balance[:pending_withdrawal] = balance[:pending_withdrawal].to_f
|
56
|
+
balance
|
57
|
+
end
|
58
|
+
response_object
|
59
|
+
end
|
60
|
+
|
61
|
+
def normalize_book(response_object)
|
62
|
+
response_object[:minimum_price] = response_object[:minimum_price].to_f
|
63
|
+
response_object[:maximum_price] = response_object[:maximum_price].to_f
|
64
|
+
response_object[:minimum_amount] = response_object[:minimum_amount].to_f
|
65
|
+
response_object[:maximum_amount] = response_object[:maximum_amount].to_f
|
66
|
+
response_object[:minimum_value] = response_object[:minimum_value].to_f
|
67
|
+
response_object[:maximum_value] = response_object[:maximum_value].to_f
|
68
|
+
response_object
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize_account_fees(response_object)
|
72
|
+
response_object[:fees] = response_object[:fees].map do |fee|
|
73
|
+
fee[:fee_percent] = fee[:fee_percent].to_f
|
74
|
+
fee[:fee_decimal] = fee[:fee_decimal].to_f
|
75
|
+
fee
|
76
|
+
end
|
77
|
+
response_object[:withdrawal_fees][:btc] = response_object[:withdrawal_fees][:btc].to_f
|
78
|
+
response_object[:withdrawal_fees][:eth] = response_object[:withdrawal_fees][:eth].to_f
|
79
|
+
response_object
|
80
|
+
end
|
81
|
+
|
82
|
+
def normalize_funding(response_object)
|
83
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
84
|
+
response_object[:amount] = response_object[:amount].to_f
|
85
|
+
response_object
|
86
|
+
end
|
87
|
+
|
88
|
+
def normalize_order(response_object)
|
89
|
+
response_object[:original_amount] = response_object[:original_amount].to_f
|
90
|
+
response_object[:unfilled_amount] = response_object[:unfilled_amount].to_f
|
91
|
+
response_object[:original_value] = response_object[:original_value].to_f
|
92
|
+
response_object[:price] = response_object[:price].to_f
|
93
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
94
|
+
response_object[:updated_at] = DateTime.parse(response_object[:updated_at])
|
95
|
+
response_object
|
96
|
+
end
|
97
|
+
|
98
|
+
def normalize_ledger(response_object)
|
99
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
100
|
+
response_object[:balance_updates] = response_object[:balance_updates].map do |balance|
|
101
|
+
balance[:amount] = balance[:amount].to_f
|
102
|
+
balance
|
103
|
+
end
|
104
|
+
response_object
|
105
|
+
end
|
106
|
+
|
107
|
+
def normalize_ticker(response_object)
|
108
|
+
response_object[:volume] = response_object[:volume].to_f
|
109
|
+
response_object[:high] = response_object[:high].to_f
|
110
|
+
response_object[:last] = response_object[:last].to_f
|
111
|
+
response_object[:low] = response_object[:low].to_f
|
112
|
+
response_object[:vwap] = response_object[:vwap].to_f
|
113
|
+
response_object[:ask] = response_object[:ask].to_f
|
114
|
+
response_object[:bid] = response_object[:bid].to_f
|
115
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
116
|
+
response_object
|
117
|
+
end
|
118
|
+
|
119
|
+
def normalize_trade(response_object)
|
120
|
+
response_object[:amount] = response_object[:amount].to_f
|
121
|
+
response_object[:price] = response_object[:price].to_f
|
122
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
123
|
+
response_object
|
124
|
+
end
|
125
|
+
|
126
|
+
def normalize_user_trade(response_object)
|
127
|
+
response_object[:major] = response_object[:major].to_f
|
128
|
+
response_object[:minor] = response_object[:minor].to_f
|
129
|
+
response_object[:amount] = response_object[:amount].to_f
|
130
|
+
response_object[:fees_amount] = response_object[:fees_amount].to_f
|
131
|
+
response_object[:price] = response_object[:price].to_f
|
132
|
+
response_object[:tid] = response_object[:tid].to_i
|
133
|
+
response_object[:created_at] = DateTime.parse(response_object[:created_at])
|
134
|
+
response_object
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bitsor
|
4
|
+
# Current major release.
|
5
|
+
# @return [Integer]
|
6
|
+
MAJOR = 0
|
7
|
+
|
8
|
+
# Current minor release.
|
9
|
+
# @return [Integer]
|
10
|
+
MINOR = 1
|
11
|
+
|
12
|
+
# Current patch level.
|
13
|
+
# @return [Integer]
|
14
|
+
PATCH = 0
|
15
|
+
|
16
|
+
# Full release version.
|
17
|
+
# @return [String]
|
18
|
+
VERSION = [MAJOR, MINOR, PATCH].join('.').freeze
|
19
|
+
end
|
20
|
+
|
data/lib/bitsor.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bitsor/client'
|
4
|
+
require 'bitsor/default'
|
5
|
+
require 'bitsor/error'
|
6
|
+
|
7
|
+
module Bitsor
|
8
|
+
class << self
|
9
|
+
include Bitsor::Configurable
|
10
|
+
|
11
|
+
def client
|
12
|
+
return @client if defined?(@client)
|
13
|
+
@client = Bitsor::Client.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def respond_to_missing?(method_name, include_private = false)
|
19
|
+
client.respond_to?(method_name, include_private)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method_name, *args, &block)
|
23
|
+
if client.respond_to?(method_name)
|
24
|
+
return client.send(method_name, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Bitsor.setup
|
33
|
+
|