cryptomarket-sdk 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,239 @@
1
+ require "securerandom"
2
+
3
+ require_relative "wsClientBase"
4
+ require_relative"../utils"
5
+ require_relative "methods"
6
+
7
+
8
+
9
+
10
+ module Cryptomarket
11
+ module Websocket
12
+ # PublicClient connects via websocket to cryptomarket to get market information of the exchange.
13
+ #
14
+ # +Proc+ +callback+:: Optional. A +Proc+ to call with the client once the connection is established. if an error ocurrs is return as the fist parameter of the callback: callback(err, client)
15
+
16
+ class PublicClient < ClientBase
17
+ include Utils
18
+ include Methods
19
+
20
+ def initialize()
21
+ @OBCache = OrderbookCache.new
22
+ super url:"wss://api.exchange.cryptomkt.com/api/2/ws/public"
23
+ end
24
+
25
+ def handleNotification(notification)
26
+ method = notification['method']
27
+ params = notification['params']
28
+ key = buildKey(method, params)
29
+ callback = @callbackCache.getSubscriptionCallback(key)
30
+ if callback.nil?
31
+ return
32
+ end
33
+ if orderbookFeed(method)
34
+ @OBCache.update(method, key, params)
35
+ if @OBCache.orderbookBroken(key)
36
+ storeAndSend('subscribeOrderbook', {'symbol' => params['symbol']}, nil)
37
+ @OBCache.waitOrderbook(key)
38
+ return
39
+ end
40
+ if @OBCache.orderbookWating(key)
41
+ return
42
+ end
43
+ params = @OBCache.getOrderbook(key)
44
+ end
45
+ if candlesFeed(method) or tradesFeed(method)
46
+ params = params["data"]
47
+ end
48
+ callback.call(params)
49
+ end
50
+
51
+ def buildKey(method, params)
52
+ methodKey = mapping(method)
53
+
54
+ symbol = ''
55
+ if params.has_key? 'symbol'
56
+ symbol = params['symbol']
57
+ end
58
+ period = ''
59
+ if params.has_key? 'period'
60
+ period = params['period']
61
+ end
62
+ key = methodKey + ':' + symbol + ':' + period
63
+ return key.upcase
64
+ end
65
+
66
+ # Get a list all available currencies on the exchange
67
+ #
68
+ # https://api.exchange.cryptomkt.com/#get-currencies
69
+ #
70
+ # +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| ...}
71
+
72
+ def getCurrencies(callback)
73
+ sendById("getCurrencies", callback)
74
+ end
75
+
76
+ # Get the data of a currency
77
+ #
78
+ # https://api.exchange.cryptomkt.com/#get-currencies
79
+ #
80
+ # +String+ +currency+:: A currency id
81
+ # +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| ...}
82
+
83
+ def getCurrency(currency, callback)
84
+ sendById('getCurrency', callback, {'currency' => currency})
85
+ end
86
+
87
+ # Get a list of the specified symbols or all of them if no symbols are specified
88
+ #
89
+ # A symbol is the combination of the base currency (first one) and quote currency (second one)
90
+ #
91
+ # https://api.exchange.cryptomkt.com/#get-symbols
92
+ #
93
+ # +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| ...}
94
+
95
+ def getSymbols(callback)
96
+ sendById('getSymbols', callback)
97
+ end
98
+
99
+ # Get a symbol by its id
100
+ #
101
+ # A symbol is the combination of the base currency (first one) and quote currency (second one)
102
+ #
103
+ # https://api.exchange.cryptomkt.com/#get-symbols
104
+ #
105
+ #
106
+ # +String+ +symbol+:: A symbol id
107
+ # +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| ...}
108
+
109
+ def getSymbol(symbol, callback)
110
+ sendById('getSymbol', callback, {'symbol' => symbol})
111
+ end
112
+
113
+ # Subscribe to a ticker of a symbol
114
+ #
115
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker
116
+ #
117
+ # +String+ +symbol+:: A symbol to subscribe
118
+ # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. The ticker feed
119
+ # +Proc+ +resultCallback+:: Optional. A function to call with the subscription result. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
120
+
121
+ def subscribeToTicker(symbol, callback, resultCallback=nil)
122
+ sendSubscription('subscribeTicker', callback, {'symbol' => symbol}, resultCallback)
123
+ end
124
+
125
+ # Unsubscribe to a ticker of a symbol
126
+ #
127
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker
128
+ #
129
+ #
130
+ # +String+ +symbol+:: The symbol to stop the ticker subscribption
131
+ # +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| ...}
132
+
133
+ def unsubscribeToTicker(symbol, callback=nil)
134
+ sendUnsubscription('unsubscribeTicker', callback, {'symbol' => symbol})
135
+ end
136
+
137
+ # Subscribe to the order book of a symbol
138
+ #
139
+ # An Order Book is an electronic list of buy and sell orders for a specific symbol, structured by price level
140
+ #
141
+ # https://api.exchange.cryptomkt.com/#subscribe-to-order-book
142
+ #
143
+ # +String+ +symbol+:: The symbol of the orderbook
144
+ # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. the order book feed
145
+ # +Proc+ +resultCallback+:: A function to call with the subscription result. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
146
+
147
+ def subscribeToOrderbook(symbol, callback, resultCallback=nil)
148
+ sendSubscription('subscribeOrderbook', callback, {'symbol' => symbol}, resultCallback)
149
+ end
150
+
151
+ # Unsubscribe to an order book of a symbol
152
+ #
153
+ # An Order Book is an electronic list of buy and sell orders for a specific symbol, structured by price level
154
+ #
155
+ # https://api.exchange.cryptomkt.com/#subscribe-to-order-book
156
+ #
157
+ # +String+ +symbol+:: The symbol of the orderbook
158
+ # +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| ...}
159
+
160
+ def unsubscribeToOrderbook(symbol, callback=nil)
161
+ sendUnsubscription('unsubscribeOrderbook', callback, {'symbol' => symbol})
162
+ end
163
+
164
+ # Subscribe to the trades of a symbol
165
+ #
166
+ # https://api.exchange.cryptomkt.com/#subscribe-to-trades
167
+ #
168
+ # +String+ +symbol+:: The symbol of the trades
169
+ # +Integer+ [limit] Optional. Maximum number of trades in the first feed, the nexts feeds have one trade
170
+ # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. the trades feed
171
+ # +Proc+ +resultCallback+:: Optional. A function to call with the subscription result. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
172
+
173
+ def subscribeToTrades(symbol, callback, limit=nil, resultCallback=nil)
174
+ params = {'symbol' => symbol}
175
+ sendSubscription('subscribeTrades', callback, params, resultCallback)
176
+ end
177
+
178
+ # Unsubscribe to a trades of a symbol
179
+ #
180
+ # https://api.exchange.cryptomkt.com/#subscribe-to-trades
181
+ #
182
+ # +String+ +symbol+:: The symbol of the trades
183
+ # +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| ...}
184
+
185
+ def unsubscribeToTrades(symbol, callback=nil)
186
+ sendUnsubscription('unsubscribeTrades', callback, {'symbol' => symbol})
187
+ end
188
+
189
+
190
+ # Get trades of the specified symbol
191
+ #
192
+ # https://api.exchange.cryptomkt.com/#get-trades
193
+ #
194
+ # +String+ +symbol+:: The symbol to get the trades
195
+ # +String+ +sort+:: Optional. Sort direction. 'ASC' or 'DESC'. Default is 'DESC'
196
+ # +String+ +from+:: Optional. Initial value of the queried interval.
197
+ # +String+ +till+:: Optional. Last value of the queried interval.
198
+ # +Integer+ +limit+:: Optional. Trades per query. Defaul is 100. Max is 1000
199
+ # +Integer+ +offset+:: Optional. Default is 0. Max is 100000
200
+ # +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| ...}
201
+
202
+ def getTrades(symbol, callback, from:nil, till:nil, limit:nil, offset:nil)
203
+ params = {'symbol' => symbol}
204
+ extend_hash_with_pagination! params, from:from, till:till, limit:limit, offset:offset
205
+ sendById('getTrades', callback, params)
206
+ end
207
+
208
+ # Subscribe to the candles of a symbol, at the given period
209
+ #
210
+ # Candels are used for OHLC representation
211
+ #
212
+ #
213
+ # https://api.exchange.cryptomkt.com/#subscribe-to-candles
214
+ #
215
+ # +String+ +symbol+:: A symbol to recieve a candle feed
216
+ # +String+ period A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month)
217
+ # +Integer+ +limit+:: Optional. Maximum number of candles in the first feed. The rest of the feeds have one candle
218
+ # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. recieves the candle feed
219
+ # +Proc+ +resultCallback+:: Optional. A callable to call with the subscription result. It takes two arguments, err and result. err is None for successful calls, result is None for calls with error: Proc.new {|err, result| ...}
220
+
221
+ def subscribeToCandles(symbol, period, limit, callback, resultCallback=nil)
222
+ params = {'symbol' => symbol, 'period' => period}
223
+ sendSubscription('subscribeCandles', callback, params, resultCallback)
224
+ end
225
+
226
+ # Unsubscribe to the candles of a symbol at a given period
227
+ #
228
+ # https://api.exchange.cryptomkt.com/#subscribe-to-candles
229
+ #
230
+ # +String+ +symbol+:: The symbol of the candles
231
+ # +String+ period 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month)
232
+ # +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| ...}
233
+
234
+ def unsubscribeToCandles(symbol, period, callback=nil)
235
+ sendUnsubscription('unsubscribeCandles', callback, {'symbol'=> symbol, 'period' => period})
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,123 @@
1
+ require_relative "authClient"
2
+ require_relative"../utils"
3
+
4
+ module Cryptomarket
5
+ module Websocket
6
+
7
+ # TradingClient connects via websocket to cryptomarket to enable the user to manage orders. 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 TradingClient < AuthClient
14
+ include Utils
15
+ # Creates a new client
16
+ def initialize(apiKey:, apiSecret:)
17
+ super(url:"wss://api.exchange.cryptomkt.com/api/2/ws/trading", apiKey:apiKey, apiSecret:apiSecret)
18
+ end
19
+
20
+ # Subscribe to a feed of trading events of the account
21
+ #
22
+ # Requires authentication
23
+ #
24
+ # https://api.exchange.cryptomkt.com/#subscribe-to-reports
25
+ #
26
+ # +Proc+ +callback+:: A +Proc+ to call with the result data. It takes one argument. a feed of reports
27
+ # +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| ...}
28
+
29
+ def subscribeToReports(callback, resultCallback=nil)
30
+ sendSubscription('subscribeReports', callback, {}, resultCallback)
31
+ end
32
+
33
+ # Create a new order
34
+ #
35
+ # Requires authentication
36
+ #
37
+ # https://api.exchange.cryptomkt.com/#place-new-order
38
+ #
39
+ # +String+ +clientOrderId+:: If given must be unique within the trading day, including all active orders. If not given, is generated by the server
40
+ # +String+ +symbol+:: Trading symbol
41
+ # +String+ +side+:: 'buy' or 'sell'
42
+ # +String+ +quantity+:: Order quantity
43
+ # +String+ +type+:: Optional. 'limit', 'market', 'stopLimit' or 'stopMarket'. Default is 'limit'
44
+ # +String+ +timeInForce+:: Optional. 'GTC', 'IOC', 'FOK', 'Day', 'GTD'
45
+ # +String+ +price+:: Required for 'limit' and 'stopLimit'. limit price of the order
46
+ # +String+ +stopPrice+:: Required for 'stopLimit' and 'stopMarket' orders. stop price of the order
47
+ # +String+ +expireTime+:: Required for orders with timeInForce = 'GDT'
48
+ # +bool+ +strictValidate+:: Optional. If False, the server rounds half down for tickerSize and quantityIncrement. Example of ETHBTC: tickSize = '0.000001', then price '0.046016' is valid, '0.0460165' is invalid
49
+ # +bool+ +postOnly+:: Optional. If True, your postOnly order causes a match with a pre-existing order as a taker, then the order will be cancelled
50
+ # +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| ...}
51
+
52
+ def createOrder(clientOrderId:, symbol:, side:, quantity:, type:nil, timeInForce:nil, price:nil, stopPrice:nil, expireTime:nil, strictValidate:nil, postOnly:nil, callback:nil)
53
+ params = {'symbol' => symbol, 'side' => side, 'quantity' => quantity, 'clientOrderId' => clientOrderId}
54
+ extend_hash_with_order_params! params, type:type, timeInForce:timeInForce, price:price, stopPrice:stopPrice, expireTime:expireTime, strictValidate:strictValidate, postOnly:postOnly
55
+ sendById('newOrder', callback, params)
56
+ end
57
+
58
+ # Cancel the order with ClientOrderId
59
+ #
60
+ # Requires authentication
61
+ #
62
+ # https://api.exchange.cryptomkt.com/#cancel-order
63
+ #
64
+ # +String+ +clientOrderId+:: The client order id of the order to cancel
65
+ # +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| ...}
66
+
67
+ def cancelOrder(clientOrderId, callback:nil)
68
+ sendById('cancelOrder', callback, {'clientOrderId' => clientOrderId})
69
+ end
70
+
71
+ # Rewrites an order, canceling it or replacing it
72
+ #
73
+ # The Cancel/Replace request is used to change the parameters of an existing order and to change the quantity or price attribute of an open order
74
+ #
75
+ # Do not use this request to cancel the quantity remaining in an outstanding order. Use the cancel_order for this purpose
76
+ #
77
+ # It is stipulated that a newly entered order cancels a prior order that has been entered, but not yet executed
78
+ #
79
+ # Requires authentication
80
+ #
81
+ # https://api.exchange.cryptomkt.com/#cancel-replace-order
82
+ #
83
+ # +String+ +clientOrderId+:: The client id of the order to modify
84
+ # +String+ +requestClientId+:: The new id for the modified order
85
+ # +String+ +quantity+:: The new quantity of the order
86
+ # +String+ +price+:: The new price of the order
87
+ # +bool+ +strictValidate+:: Optional. If False, the server rounds half down for tickerSize and quantityIncrement. Example of ETHBTC: tickSize = '0.000001', then price '0.046016' is valid, '0.0460165' is invalid
88
+ # +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| ...}
89
+
90
+ def replaceOrder(clientOrderId:, requestClientId:, quantity:, price:, strictValidate:nil, callback:nil)
91
+ params = {'clientOrderId' => clientOrderId, 'requestClientId' => requestClientId, 'quantity' => quantity, 'price' => price}
92
+ if not strictValidate.nil?
93
+ params['strictValidate'] = strictValidate
94
+ end
95
+ sendById('cancelReplaceOrder', callback, params)
96
+ end
97
+
98
+ # Get the account active orders
99
+ #
100
+ # Requires authentication
101
+ #
102
+ # https://api.exchange.cryptomkt.com/#get-active-orders-2
103
+ #
104
+ # +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| ...}
105
+
106
+ def getActiveOrders(callback)
107
+ sendById('getOrders', callback)
108
+ end
109
+
110
+ # Get the user trading balance
111
+ #
112
+ # Requires authentication
113
+ #
114
+ # https://api.exchange.cryptomkt.com/#get-trading-balance
115
+ #
116
+ # +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| ...}
117
+
118
+ def getTradingBalance(callback)
119
+ sendById('getTradingBalance', callback)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,157 @@
1
+ require_relative "callbackCache"
2
+ require_relative "methods"
3
+ require_relative "orderbookCache"
4
+ require_relative "wsManager"
5
+ require_relative '../exceptions'
6
+
7
+ module Cryptomarket
8
+ module Websocket
9
+ class ClientBase
10
+ include Methods
11
+
12
+ def initialize(url:)
13
+ @callbackCache = CallbackCache.new
14
+ @wsmanager = WSManager.new self, url:url
15
+ @onconnect = ->{}
16
+ @onerror = ->(error){}
17
+ @onclose = ->{}
18
+ end
19
+
20
+ def connected?
21
+ return @wsmanager.connected?
22
+ end
23
+
24
+ def close()
25
+ @wsmanager.close()
26
+ end
27
+
28
+ # connects via websocket to the exchange, it blocks until the connection is stablished
29
+ def connect()
30
+ @wsmanager.connect()
31
+ while (not @wsmanager.connected?)
32
+ sleep(1)
33
+ end
34
+ end
35
+
36
+ def on_open()
37
+ @onconnect.call()
38
+ end
39
+
40
+ def onconnect=(callback=nil, &block)
41
+ callback = callback || block
42
+ @onconnect = callback
43
+ end
44
+
45
+ def onconnect()
46
+ @onconnect.call()
47
+ end
48
+
49
+ def onerror=(callback=nil, &block)
50
+ callback = callback || block
51
+ @onerror = callback
52
+ end
53
+
54
+ def onerror(error)
55
+ @onerror.call(error)
56
+ end
57
+
58
+ def onclose=(callback=nil, &block)
59
+ callback = callback || block
60
+ @onclose = callback
61
+ end
62
+
63
+ def onclose()
64
+ @onclose.call()
65
+ end
66
+
67
+ def sendSubscription(method, callback, params, resultCallback)
68
+ key = buildKey(method, params)
69
+ @callbackCache.storeSubscriptionCallback(key, callback)
70
+ storeAndSend(method, params, resultCallback)
71
+ end
72
+
73
+ def sendUnsubscription(method, callback, params)
74
+ key = buildKey(method, params)
75
+ @callbackCache.deleteSubscriptionCallback(key)
76
+ storeAndSend(method, params, callback)
77
+ end
78
+
79
+ def sendById(method, callback, params={})
80
+ storeAndSend(method, params, callback)
81
+ end
82
+
83
+ def storeAndSend(method, params, callbackToStore=nil)
84
+ payload = {'method' => method, 'params' => params}
85
+ if not callbackToStore.nil?
86
+ id = @callbackCache.storeCallback(callbackToStore)
87
+ payload['id'] = id
88
+ end
89
+ @wsmanager.send(payload)
90
+ end
91
+
92
+ def handle(message)
93
+ if message.has_key? 'method'
94
+ handleNotification(message)
95
+ elsif message.has_key? 'id'
96
+ handleResponse(message)
97
+ end
98
+ end
99
+
100
+ def handleNotification(notification)
101
+ key = "subscription"
102
+ callback = @callbackCache.getSubscriptionCallback(key)
103
+ if callback.nil?
104
+ return
105
+ end
106
+ callback.call(notification["params"])
107
+ end
108
+
109
+ def buildKey(method=nil, params=nil)
110
+ return "subscription"
111
+ end
112
+
113
+ def handleResponse(response)
114
+ id = response['id']
115
+ if id.nil?
116
+ return
117
+ end
118
+ callback = @callbackCache.popCallback(id)
119
+ if callback.nil?
120
+ return
121
+ end
122
+ if response.has_key? 'error'
123
+ callback.call(Cryptomarket::APIException.new(response['error']), nil)
124
+ return
125
+ elsif
126
+ result = response['result']
127
+ if result.is_a?(Hash) and result.has_key? 'data'
128
+ callback.call(nil, result['data'])
129
+ else
130
+ callback.call(nil, result)
131
+ end
132
+ end
133
+ end
134
+
135
+ def handleNotification(notification)
136
+ key = "subscription"
137
+ callback = @callbackCache.getSubscriptionCallback(key)
138
+ if callback.nil?
139
+ return
140
+ end
141
+ if notification["params"].kind_of?(Array)
142
+ notification["params"].each{|feed| callback.call(feed)}
143
+ else
144
+ callback.call(notification["params"])
145
+ end
146
+ end
147
+
148
+ def buildKey(method=nil, params=nil)
149
+ return "subscription"
150
+ end
151
+
152
+ def close()
153
+ @wsmanager.close()
154
+ end
155
+ end
156
+ end
157
+ end