cryptomarket-sdk 1.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,75 +0,0 @@
1
- require 'net/http'
2
- require 'uri'
3
- require 'json'
4
- require 'base64'
5
- require 'rest-client'
6
- require_relative 'exceptions'
7
-
8
- module Cryptomarket
9
- class HttpManager
10
- @@apiUrl = 'https://api.exchange.cryptomkt.com'
11
- @@apiVersion = '/api/2/'
12
-
13
-
14
- def initialize(apiKey:, apiSecret:)
15
- @apiKey = apiKey
16
- @apiSecret = apiSecret
17
- end
18
-
19
- def getCredential(httpMethod, method, params)
20
- timestamp = Time.now.to_i.to_s
21
- msg = httpMethod + timestamp + @@apiVersion + method
22
- if not params.nil? and params.keys.any?
23
- if httpMethod.upcase == 'GET' or httpMethod.upcase == 'PUT'
24
- msg += '?'
25
- end
26
- msg += URI.encode_www_form params
27
- end
28
- digest = OpenSSL::Digest.new 'sha256'
29
- signature = OpenSSL::HMAC.hexdigest digest, @apiSecret, msg
30
- encoded = Base64.encode64(@apiKey + ':' + timestamp + ':' + signature).delete "\n"
31
- return 'HS256 ' + encoded
32
- end
33
-
34
- def makeRequest(method:, endpoint:, params:nil, public:false)
35
- uri = URI(@@apiUrl + @@apiVersion + endpoint)
36
- if not params.nil?
37
- params = Hash[params.sort_by {|key, val| key.to_s }]
38
- end
39
- headers = Hash.new
40
- if not public
41
- headers['Authorization'] = getCredential(method.upcase, endpoint, params)
42
- end
43
- if (method.upcase == 'GET' or method.upcase =='PUT') and not params.nil?
44
- uri.query = URI.encode_www_form params
45
- params = nil
46
- end
47
- begin
48
- response = RestClient::Request.execute(
49
- method: method.downcase.to_sym,
50
- url: uri.to_s,
51
- payload: params,
52
- headers: headers)
53
- return handleResponse(response)
54
- rescue RestClient::ExceptionWithResponse => e
55
- response = e.response
56
- return handleResponse(response)
57
- end
58
- end
59
-
60
- def handleResponse(response)
61
- result = response.body
62
- parsed_result = JSON.parse result
63
- if response.code != 200 and not parsed_result['error'].nil?
64
- error = parsed_result['error']
65
- msg = "(code=#{error['code']}): #{error['message']}"
66
- if not error['description'].nil?
67
- msg += ": #{error['description']}"
68
- end
69
- exception = Cryptomarket::APIException.new error
70
- raise exception, msg
71
- end
72
- return parsed_result
73
- end
74
- end
75
- end
@@ -1,57 +0,0 @@
1
- module Cryptomarket
2
- module Utils
3
- def extend_hash_with_pagination!(hash, sort: nil, by:nil, from: nil, till: nil, limit: nil, offset: nil)
4
- if not sort.nil?
5
- hash['sort'] = sort
6
- end
7
- if not by.nil?
8
- hash['by'] = by
9
- end
10
- if not from.nil?
11
- hash['from'] = from
12
- end
13
- if not till.nil?
14
- hash['till'] = till
15
- end
16
- if not limit.nil?
17
- hash['limit'] = limit
18
- end
19
- if not offset.nil?
20
- hash['offset'] = offset
21
- end
22
- end
23
-
24
- def extend_hash_with_order_params! hash, symbol:nil, side:nil, quantity:nil, type:nil, timeInForce:nil, price:nil, stopPrice:nil, expireTime:nil, strictValidate:nil, postOnly:nil
25
- if not symbol.nil?
26
- hash['symbol'] = symbol
27
- end
28
- if not side.nil?
29
- hash['side'] = side
30
- end
31
- if not quantity.nil?
32
- hash['quantity'] = quantity
33
- end
34
- if not type.nil?
35
- hash['type'] = type
36
- end
37
- if not timeInForce.nil?
38
- hash['timeInForce'] = timeInForce
39
- end
40
- if not price.nil?
41
- hash['price'] = price
42
- end
43
- if not stopPrice.nil?
44
- hash['stopPrice'] = stopPrice
45
- end
46
- if not expireTime.nil?
47
- hash['expireTime'] = expireTime
48
- end
49
- if not strictValidate.nil?
50
- hash['strictValidate'] = strictValidate
51
- end
52
- if not postOnly.nil?
53
- hash['postOnly'] = postOnly
54
- end
55
- end
56
- end
57
- end
@@ -1,150 +0,0 @@
1
- require_relative "authClient"
2
- require_relative"../utils"
3
-
4
- module Cryptomarket
5
- module Websocket
6
-
7
- # AccountClient connects via websocket to cryptomarket to get account information of the user. uses SHA256 as auth method and authenticates automatically.
8
- #
9
- # +string+ +apiKey+:: the user api key
10
- # +string+ +apiSecret+:: the user api secret
11
- # +Proc+ +callback+:: Optional. A +Proc+ to call with the client once the connection is established and the authentication is successful. if an error ocurrs is return as the fist parameter of the callback: callback(err, client)
12
-
13
- class AccountClient < AuthClient
14
- include Utils
15
-
16
- # Creates a new client and authenticates it to the server
17
- def initialize(apiKey:, apiSecret:)
18
- transaction = "transaction"
19
- balance = "balance"
20
- super(
21
- url:"wss://api.exchange.cryptomkt.com/api/2/ws/account",
22
- apiKey:apiKey,
23
- apiSecret:apiSecret,
24
- subscriptionKeys:{
25
- "unsubscribeTransactions" => transaction,
26
- "subscribeTransactions" => transaction,
27
- "updateTransaction" => transaction,
28
-
29
- "unsubscribeBalance" => balance,
30
- "subscribeBalance" => balance,
31
- "balance" => balance,
32
- })
33
- end
34
-
35
- # get the account balance as a list of balances. non-zero balances only
36
- #
37
- # https://api.exchange.cryptomarket.com/#request-balance
38
-
39
- def getAccountBalance(callback)
40
- sendById('getBalance', callback)
41
- end
42
-
43
- # Get a list of transactions of the account. Accepts only filtering by Datetime
44
- #
45
- # https://api.exchange.cryptomarket.com/#find-transactions
46
- #
47
- # Parameters:
48
- # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
49
- # +string+ +currency+:: Optional. Currency to filter transactions by.
50
- # +string+ +sort+:: Optional. sort direction. 'ASC' or 'DESC' default is 'DESC'
51
- # +string+ +from+:: Optional. Initial value of the queried interval
52
- # +string+ +till+:: Optional. Last value of the queried interval
53
- # +integer+ +limit+:: Optional. Trades per query. Defaul is 100. Max is 1000
54
- # +integer+ +offset+:: Optional. Default is 0. Max is 100000
55
- # +bool+ +showSenders+:: Optional. If true incluedes senders addresses. Default is false.
56
-
57
- def findTransactions(callback, currency:nil, sort:nil, from:nil, till:nil, limit:nil, offset:nil, showSenders:nil)
58
- params = Hash.new
59
- if not currency.nil?
60
- params['currency'] = currency
61
- end
62
- if not showSenders.nil?
63
- params['showSenders'] = showSenders
64
- end
65
- extend_hash_with_pagination! params, sort:sort, from:from, till:till, limit:limit, offset:offset
66
- sendById('findTransactions', callback, params)
67
- end
68
-
69
- # LoadTransactions gets a list of transactions of the account. Accepts only filtering by Index
70
- #
71
- # https://api.exchange.cryptomarket.com/#find-transactions
72
- #
73
- # Parameters:
74
- # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
75
- # +string+ +currency+:: Optional. Currency to filter transactions by.
76
- # +string+ +sort+:: Optional. sort direction. 'ASC' or 'DESC' default is 'ASC'
77
- # +string+ +from+:: Optional. Initial value of the queried interval (Included)
78
- # +string+ +till+:: Optional. Last value of the queried interval (Excluded)
79
- # +integer+ +limit+:: Optional. Trades per query. Defaul is 100. Max is 1000
80
- # +integer+ +offset+:: Optional. Default is 0. Max is 100000
81
- # +bool+ +showSenders+:: Optional. If true incluedes senders addresses. Default is false.
82
-
83
- def loadTransactions(callback, currency:nil, sort:nil, from:nil, till:nil, limit:nil, offset:nil, showSenders:nil)
84
- params = Hash.new
85
- if not currency.nil?
86
- params['currency'] = currency
87
- end
88
- if not showSenders.nil?
89
- params['showSenders'] = showSenders
90
- end
91
- extend_hash_with_pagination! params, sort:sort, from:from, till:till, limit:limit, offset:offset
92
- sendById('loadTransactions', callback, params)
93
- end
94
-
95
- # subscribes to a feed of transactions
96
- #
97
- # A transaction notification occurs each time the transaction has been changed:
98
- # such as creating a transaction, updating the pending state (for example the hash assigned)
99
- # or completing a transaction. This is the easiest way to track deposits or develop real-time asset monitoring.
100
- #
101
- # A combination of the recovery mechanism and transaction subscription provides reliable and consistent information
102
- # regarding transactions. For that, you should store the latest processed index and
103
- # requested possible gap using a "loadTransactions" method after connecting or reconnecting the Websocket.
104
- #
105
- # https://api.exchange.cryptomarket.com/#subscription-to-the-transactions
106
- #
107
- # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. a feed of reports
108
- # +Proc+ +resultCallback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
109
-
110
- def subscribeToTransactions(callback, resultCallback:nil)
111
- sendSubscription('subscribeTransactions', callback, {}, resultCallback)
112
- end
113
-
114
- # unsubscribe to the transaction feed.
115
- #
116
- # https://api.exchange.cryptomkt.com/#subscription-to-the-transactions
117
- #
118
- # +Proc+ +callback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
119
-
120
- def unsubscribeToTransactions(callback:nil)
121
- sendUnsubscription('unsubscribeTransactions', callback, {})
122
- end
123
-
124
- # subscribes to a feed of balances
125
- #
126
- # This subscription aims to provide an easy way to be informed of the current balance state.
127
- # If the state has been changed or potentially changed the "balance" event will come with the actual state.
128
- # Please be aware that only non-zero values present.
129
- #
130
- # https://api.exchange.cryptomkt.com/#subscription-to-the-balance
131
- #
132
- # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. a feed of balances
133
- # +Proc+ +resultCallback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
134
-
135
- def subscribeToBalance(callback, resultCallback:nil)
136
- sendSubscription('subscribeBalance', callback, {}, resultCallback)
137
- end
138
-
139
- # unsubscribe to the balance feed.
140
- #
141
- # https://api.exchange.cryptomkt.com/#subscription-to-the-balance
142
- #
143
- # +Proc+ +callback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
144
-
145
- def unsubscribeToBalance(callback:nil)
146
- sendUnsubscription('unsubscribeBalance', callback, {})
147
- end
148
- end
149
- end
150
- end
@@ -1,53 +0,0 @@
1
- require "securerandom"
2
- require_relative "wsClientBase"
3
-
4
- module Cryptomarket
5
- module Websocket
6
- class AuthClient < ClientBase
7
- # Creates a new client
8
- def initialize(url:, apiKey:, apiSecret:, subscriptionKeys:)
9
- @apiKey = apiKey
10
- @apiSecret = apiSecret
11
- super url:url, subscriptionKeys:subscriptionKeys
12
- @authed = false
13
- end
14
-
15
- def connected?
16
- return (super.connected? and @authed)
17
- end
18
-
19
- # connects via websocket to the exchange and authenticates it.
20
- def connect
21
- super
22
- authenticate(Proc.new {|err, result|
23
- if not err.nil?
24
- raise err
25
- end
26
- @authed = true
27
- })
28
- while not @authed
29
- sleep(1)
30
- end
31
- end
32
-
33
- # Authenticates the websocket
34
- #
35
- # https://api.exchange.cryptomkt.com/#socket-session-authentication
36
- #
37
- # +Proc+ +callback+:: Optional. A +Proc+ to call with the result data. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
38
-
39
- def authenticate(callback=nil)
40
- nonce = SecureRandom.hex
41
- digest = OpenSSL::Digest.new 'sha256'
42
- signature = OpenSSL::HMAC.hexdigest digest, @apiSecret, nonce
43
- params = {
44
- 'algo'=> 'HS256',
45
- 'pKey'=> @apiKey,
46
- 'nonce'=> nonce,
47
- 'signature'=> signature
48
- }
49
- return sendById('login', callback, params)
50
- end
51
- end
52
- end
53
- end
@@ -1,51 +0,0 @@
1
- module Cryptomarket
2
- module Websocket
3
- class CallbackCache
4
- def initialize()
5
- @callbacks = Hash.new
6
- @nextId = 1
7
- end
8
-
9
- def getNextId
10
- _nextId = @nextId
11
- @nextId+= 1
12
- if @nextId < 0
13
- @nextId = 1
14
- end
15
- return _nextId
16
- end
17
-
18
- def storeCallback(callback)
19
- id = getNextId()
20
- @callbacks[id] = callback
21
- return id
22
- end
23
-
24
- def popCallback(id)
25
- if not @callbacks.has_key? id
26
- return nil
27
- end
28
- callback = @callbacks[id]
29
- @callbacks.delete(id)
30
- return callback
31
- end
32
-
33
- def storeSubscriptionCallback(key, callback)
34
- @callbacks[key] = callback
35
- end
36
-
37
- def getSubscriptionCallback(key)
38
- if not @callbacks.has_key? key
39
- return nil
40
- end
41
- return @callbacks[key]
42
- end
43
-
44
- def deleteSubscriptionCallback(key)
45
- if @callbacks.has_key? key
46
- @callbacks.delete(key)
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,123 +0,0 @@
1
- require "bigdecimal"
2
-
3
- module Cryptomarket
4
- module Websocket
5
- class OrderbookCache
6
-
7
- # orderbook states
8
- @@UPDATING = 0
9
- @@WAITING = 1
10
- @@BROKEN = 2
11
- # order book side ordering direction
12
- @@ASCENDING = 3
13
- @@DESCENDING = 4
14
-
15
- def initialize()
16
- @orderbooks = Hash.new
17
- @orderbooks_states = Hash.new
18
- end
19
-
20
- def update(method, key, updateData)
21
- case method
22
- when 'snapshotOrderbook'
23
- @orderbooks_states[key] = @@UPDATING
24
- @orderbooks[key] = updateData
25
- return @orderbooks[key]
26
- when 'updateOrderbook'
27
- if @orderbooks_states[key] != @@UPDATING
28
- return
29
- end
30
- oldOrderbook = @orderbooks[key]
31
- if updateData['sequence'] - oldOrderbook['sequence'] != 1
32
- @orderbooks_states[key] = @@BROKEN
33
- return
34
- end
35
- oldOrderbook['sequence'] = updateData['sequence']
36
- oldOrderbook['timestamp'] = updateData['timestamp']
37
- if updateData.has_key? 'ask'
38
- oldOrderbook['ask'] = updateBookSide(oldOrderbook['ask'], updateData['ask'], @@ASCENDING)
39
- end
40
- if updateData.has_key? 'bid'
41
- oldOrderbook['bid'] = updateBookSide(oldOrderbook['bid'], updateData['bid'], @@DESCENDING)
42
- end
43
- end
44
- end
45
-
46
- def updateBookSide(oldList, updateList, sortDirection)
47
- newList = Array.new
48
- oldIdx = 0
49
- updateIdx = 0
50
- while (oldIdx < oldList.length && updateIdx < updateList.length)
51
- updateEntry = updateList[updateIdx]
52
- oldEntry = oldList[oldIdx]
53
- order = priceOrder(oldEntry, updateEntry, sortDirection)
54
- if (order == 0)
55
- if not zeroSize(updateEntry)
56
- newList.push(updateEntry)
57
- end
58
- updateIdx+= 1
59
- oldIdx+= 1
60
- elsif (order == 1)
61
- newList.push(oldEntry)
62
- oldIdx+= 1
63
- else
64
- newList.push(updateEntry)
65
- updateIdx+= 1
66
- end
67
- end
68
- if updateIdx == updateList.length
69
- for idx in oldIdx..oldList.length-1
70
- oldEntry = oldList[idx]
71
- newList.push(oldEntry)
72
- end
73
- end
74
- if (oldIdx == oldList.length)
75
- for idx in updateIdx..updateList.length-1
76
- updateEntry = updateList[idx]
77
- if not zeroSize(updateEntry)
78
- newList.push(updateEntry)
79
- end
80
- end
81
- end
82
- return newList
83
- end
84
-
85
- def zeroSize(entry)
86
- size = BigDecimal(entry['size'])
87
- return size == BigDecimal("0.00")
88
- end
89
-
90
- def priceOrder(oldEntry, updateEntry, sortDirection)
91
- oldPrice = BigDecimal(oldEntry['price'])
92
- updatePrice = BigDecimal(updateEntry['price'])
93
- # puts oldEntry.to_s() +"\t" + updateEntry.to_s()
94
- direction = 1
95
- if oldPrice > updatePrice
96
- direction = -1
97
- end
98
- if oldPrice == updatePrice
99
- direction = 0
100
- end
101
- if sortDirection == @@ASCENDING
102
- return direction
103
- end
104
- return -direction
105
- end
106
-
107
- def getOrderbook(key)
108
- return Marshal.load(Marshal.dump(@orderbooks[key]))
109
- end
110
-
111
- def orderbookBroken(key)
112
- return @orderbooks_states[key] == @@BROKEN
113
- end
114
- def orderbookWating(key)
115
- return @orderbooks_states[key] == @@WAITING
116
- end
117
-
118
- def waitOrderbook(key)
119
- @orderbooks_states[key] = @@WAITING
120
- end
121
- end
122
- end
123
- end