cryptomarket-sdk 1.0.1 → 3.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.
@@ -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