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.
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Layout/LineLength
4
+ require 'securerandom'
5
+
6
+ require_relative 'market_data_client_core'
7
+ require_relative '../constants'
8
+
9
+ module Cryptomarket
10
+ module Websocket
11
+ # MarketDataClient connects via websocket to cryptomarket to get market information of the exchange.
12
+ class MarketDataClient < MarketDataClientCore
13
+ # subscribe to a feed of trades
14
+ #
15
+ # subscription is for the specified symbols
16
+ #
17
+ # normal subscriptions have one update message per symbol
18
+ #
19
+ # the first notification contains the last n trades, with n defined by the
20
+ # limit argument, the next notifications are updates and correspond to new trades
21
+ #
22
+ # Requires no API key Access Rights
23
+ #
24
+ # https://api.exchange.cryptomkt.com/#subscribe-to-trades
25
+ #
26
+ # ==== Params
27
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of trades indexed by symbol, and the type of notification (either 'snapshot' or 'update')
28
+ # +Array[String]+ +symbols+:: A list of symbol ids
29
+ # +Integer+ +limit+:: Number of historical entries returned in the first feed. Min is 0. Max is 1000. Default is 0
30
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
31
+
32
+ def subscribe_to_trades(callback:, symbols:, limit: nil, result_callback: nil)
33
+ params = { 'symbols' => symbols, 'limit' => limit }
34
+ send_channel_subscription('trades', callback, intercept_result_callback(result_callback), params)
35
+ end
36
+
37
+ # subscribe to a feed of candles
38
+ #
39
+ # subscription is for the specified symbols
40
+ #
41
+ # normal subscriptions have one update message per symbol
42
+ #
43
+ # the first notification are n candles, with n defined by the limit argument,
44
+ # the next notification are updates, with one candle at a time
45
+ #
46
+ # Requires no API key Access Rights
47
+ #
48
+ # https://api.exchange.cryptomkt.com/#subscribe-to-candles
49
+ #
50
+ # ==== Params
51
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of candles indexed by symbol, and the type of notification (either 'snapshot' or 'update')
52
+ # +String+ +period+:: Optional. A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month). Default is 'M30'
53
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
54
+ # +Integer+ +limit+:: Number of historical entries returned in the first feed. Min is 0. Max is 1000. Default is 0
55
+ # +Proc+ +result_callback+:: Optional. A +Proc+ called with a list of subscribed symbols
56
+
57
+ def subscribe_to_candles(callback:, period:, symbols:, limit: nil, result_callback: nil)
58
+ params = { 'symbols' => symbols, 'limit' => limit }
59
+ send_channel_subscription("candles/#{period}", callback,
60
+ intercept_result_callback(result_callback), params)
61
+ end
62
+
63
+ # subscribe to a feed of mini tickers
64
+ #
65
+ # subscription is for all symbols or for the specified symbols
66
+ #
67
+ # normal subscriptions have one update message per symbol
68
+ #
69
+ # Requires no API key Access Rights
70
+ #
71
+ # https://api.exchange.cryptomkt.com/#subscribe-to-mini-ticker
72
+ #
73
+ # ==== Params
74
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of minitickers indexed by symbol, and the type of notification (only 'data')
75
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
76
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
77
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
78
+
79
+ def subscribe_to_mini_ticker(callback:, speed:, symbols: ['*'], result_callback: nil)
80
+ params = { 'symbols' => symbols }
81
+ send_channel_subscription("ticker/price/#{speed}", callback,
82
+ intercept_result_callback(result_callback), params)
83
+ end
84
+
85
+ # subscribe to a feed of mini tickers
86
+ #
87
+ # subscription is for all symbols or for the specified symbols
88
+ #
89
+ # batch subscriptions have a joined update for all symbols
90
+ #
91
+ # Requires no API key Access Rights
92
+ #
93
+ # https://api.exchange.cryptomkt.com/#subscribe-to-mini-ticker-in-batches
94
+ #
95
+ # ==== Params
96
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of minitickers indexed by symbol, and the type of notification (only 'data')
97
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
98
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
99
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
100
+
101
+ def subscribe_to_mini_ticker_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
102
+ params = { 'symbols' => symbols }
103
+ send_channel_subscription("ticker/price/#{speed}/batch", callback,
104
+ intercept_result_callback(result_callback), params)
105
+ end
106
+
107
+ # subscribe to a feed of tickers
108
+ #
109
+ # subscription is for all symbols or for the specified symbols
110
+ #
111
+ # normal subscriptions have one update message per symbol
112
+ #
113
+ # Requires no API key Access Rights
114
+ #
115
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker
116
+ #
117
+ # ==== Params
118
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of tickers indexed by symbol, and the type of notification (only 'data')
119
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
120
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
121
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
122
+
123
+ def subscribe_to_ticker(callback:, speed:, symbols: ['*'], result_callback: nil)
124
+ params = { 'symbols' => symbols }
125
+ send_channel_subscription("ticker/#{speed}", callback, intercept_result_callback(result_callback), params)
126
+ end
127
+
128
+ # subscribe to a feed of tickers
129
+ #
130
+ # subscription is for all symbols or for the specified symbols
131
+ #
132
+ # batch subscriptions have a joined update for all symbols
133
+ #
134
+ # Requires no API key Access Rights
135
+ #
136
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker-in-batches
137
+ #
138
+ # ==== Params
139
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of tickers indexed by symbol, and the type of notification (only 'data')
140
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
141
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
142
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
143
+
144
+ def subscribe_to_ticker_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
145
+ params = { 'symbols' => symbols }
146
+ send_channel_subscription("ticker/#{speed}/batch", callback, intercept_result_callback(result_callback), params)
147
+ end
148
+
149
+ # subscribe to a feed of a full orderbook
150
+ #
151
+ # subscription is for the specified symbols
152
+ #
153
+ # normal subscriptions have one update message per symbol
154
+ #
155
+ # the first notification is a snapshot of the full orderbook, and next
156
+ # notifications are updates to this snapshot
157
+ #
158
+ # Requires no API key Access Rights
159
+ #
160
+ # https://api.exchange.cryptomkt.com/#subscribe-to-full-order-book
161
+ #
162
+ # ==== Params
163
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of full orderbooks indexed by symbol, and the type of notification (either 'snapshot' or 'update')
164
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
165
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
166
+
167
+ def subscribe_to_full_order_book(callback:, symbols:, result_callback: nil)
168
+ params = { 'symbols' => symbols }
169
+ send_channel_subscription('orderbook/full', callback, intercept_result_callback(result_callback), params)
170
+ end
171
+
172
+ # subscribe to a feed of a partial orderbook
173
+ #
174
+ # subscription is for all symbols or for the specified symbols
175
+ #
176
+ # normal subscriptions have one update message per symbol
177
+ #
178
+ # Requires no API key Access Rights
179
+ #
180
+ # https://api.exchange.cryptomkt.com/#subscribe-to-partial-order-book
181
+ #
182
+ # ==== Params
183
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of partial orderbooks indexed by symbol, and the type of notification (only 'data')
184
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
185
+ # +String+ +depth+:: The depth of the partial orderbook
186
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
187
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
188
+
189
+ def subscribe_to_partial_order_book(callback:, depth:, speed:, symbols: ['*'], result_callback: nil)
190
+ params = { 'symbols' => symbols }
191
+ send_channel_subscription("orderbook/#{depth}/#{speed}", callback,
192
+ intercept_result_callback(result_callback), params)
193
+ end
194
+
195
+ # subscribe to a feed of a partial orderbook in batches
196
+ #
197
+ # subscription is for all symbols or for the specified symbols
198
+ #
199
+ # batch subscriptions have a joined update for all symbols
200
+ #
201
+ # https://api.exchange.cryptomkt.com/#subscribe-to-partial-order-book-in-batches
202
+ #
203
+ # ==== Params
204
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of partial orderbooks indexed by symbol, and the type of notification (only 'data')
205
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
206
+ # +String+ +depth+:: The depth of the partial orderbook
207
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
208
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
209
+
210
+ def subscribe_to_partial_order_book_in_batches(callback:, depth:, speed:, symbols: ['*'],
211
+ result_callback: nil)
212
+ params = { 'symbols' => symbols }
213
+ send_channel_subscription("orderbook/#{depth}/#{speed}/batch", callback,
214
+ intercept_result_callback(result_callback), params)
215
+ end
216
+
217
+ # subscribe to a feed of the top of the orderbook
218
+ #
219
+ # subscription is for all symbols or for the specified symbols
220
+ #
221
+ # normal subscriptions have one update message per symbol
222
+ #
223
+ # https://api.exchange.cryptomkt.com/#subscribe-to-top-of-book
224
+ #
225
+ # ==== Params
226
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
227
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
228
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
229
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
230
+
231
+ def subscribe_to_top_of_book(callback:, speed:, symbols: ['*'], result_callback: nil)
232
+ params = { 'symbols' => symbols }
233
+ send_channel_subscription("orderbook/top/#{speed}", callback,
234
+ intercept_result_callback(result_callback), params)
235
+ end
236
+
237
+ # subscribe to a feed of the top of the orderbook
238
+ #
239
+ # subscription is for all symbols or for the specified symbols
240
+ #
241
+ # batch subscriptions have a joined update for all symbols
242
+ #
243
+ # https://api.exchange.cryptomkt.com/#subscribe-to-top-of-book-in-batches
244
+ #
245
+ # ==== Params
246
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
247
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
248
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
249
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
250
+
251
+ def subscribe_to_top_of_book_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
252
+ params = { 'symbols' => symbols }
253
+ send_channel_subscription("orderbook/top/#{speed}/batch", callback,
254
+ intercept_result_callback(result_callback), params)
255
+ end
256
+
257
+ # subscribe to a feed of the top of the orderbook
258
+ #
259
+ # subscription is for all currencies or for the specified currencies
260
+ #
261
+ # https://api.exchange.cryptomkt.com/#subscribe-to-top-of-book-in-batches
262
+ #
263
+ # ==== Params
264
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
265
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
266
+ # +String+ +target_currency+:: Quote currency of the rate
267
+ # +Array[String]+ +currencies+:: Optional. A list of currencies ids
268
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
269
+
270
+ def subscribe_to_price_rates(callback:, speed:, target_currency:, currencies: ['*'], result_callback: nil)
271
+ params = {
272
+ speed: speed, target_currency: target_currency, currencies: currencies
273
+ }
274
+ send_channel_subscription("price/rate/#{speed}", callback, intercept_result_callback(result_callback), params)
275
+ end
276
+
277
+ # subscribe to a feed of the top of the orderbook
278
+ #
279
+ # subscription is for all currencies or for the specified currencies
280
+ #
281
+ # batch subscriptions have a joined update for all currencies
282
+ #
283
+ # https://api.exchange.cryptomkt.com/#subscribe-to-price-rates-in-batches
284
+ #
285
+ # ==== Params
286
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
287
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
288
+ # +String+ +target_currency+:: Quote currency of the rate
289
+ # +Array[String]+ +currencies+:: Optional. A list of currencies ids
290
+ # +Proc+ +result_callback+:: Optional. A +Proc+ of two arguments, An exception and a result, called either with the exception or with the result, a list of subscribed symbols
291
+
292
+ def subscribe_to_price_rates_in_batches(callback:, speed:, target_currency:, currencies: ['*'],
293
+ result_callback: nil)
294
+ params = {
295
+ speed: speed, target_currency: target_currency, currencies: currencies
296
+ }
297
+ send_channel_subscription("price/rate/#{speed}/batch", callback,
298
+ intercept_result_callback(result_callback), params)
299
+ end
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ require_relative 'client_base'
6
+ require_relative '../constants'
7
+
8
+ module Cryptomarket
9
+ module Websocket
10
+ # websocket client able to handle market data subscriptions
11
+ class MarketDataClientCore < ClientBase
12
+ def initialize
13
+ super(
14
+ url: 'wss://api.exchange.cryptomkt.com/api/3/ws/public',
15
+ subscription_keys: {})
16
+ end
17
+
18
+ def send_channel_subscription(channel, callback, result_callback, params = {})
19
+ params = params.compact unless params.nil?
20
+ payload = { 'method' => 'subscribe', 'ch' => channel, 'params' => params }
21
+ @callback_cache.store_subscription_callback(channel, callback)
22
+ unless result_callback.nil?
23
+ id = @callback_cache.store_callback(result_callback)
24
+ payload['id'] = id
25
+ end
26
+ @ws_manager.send(payload)
27
+ end
28
+
29
+ def handle(message)
30
+ if message.key? 'ch'
31
+ handle_ch_notification(message)
32
+ elsif message.key? 'id'
33
+ handle_response(message)
34
+ end
35
+ end
36
+
37
+ def handle_ch_notification(notification)
38
+ key = notification['ch']
39
+ callback = @callback_cache.get_subscription_callback(key)
40
+ return if callback.nil?
41
+
42
+ callback.call(notification['data'], Args::NotificationType::DATA) if notification.key? 'data'
43
+ callback.call(notification['snapshot'], Args::NotificationType::SNAPSHOT) if notification.key? 'snapshot'
44
+ return unless notification.key? 'update'
45
+
46
+ callback.call(notification['update'], Args::NotificationType::UPDATE)
47
+ end
48
+
49
+ def intercept_result_callback(result_callback)
50
+ return result_callback if result_callback.nil?
51
+
52
+ proc { |err, result|
53
+ if result.nil?
54
+ result_callback.call(err, result)
55
+ else
56
+ result_callback.call(err, result['subscriptions'])
57
+ end
58
+ }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,56 +1,38 @@
1
- module Cryptomarket
2
- module Websocket
3
- module Methods
4
- ORDERBOOK = "orderbook"
5
- REPORTS = "reports"
6
- TICKERS = "tickers"
7
- TRADES = "trades"
8
- CANDLES = "candles"
9
- MAP = {
10
- "subscribeReports" => REPORTS,
11
- "unsubscribeReports" => REPORTS,
12
- "activeOrders" => REPORTS,
13
- "report" => REPORTS,
14
-
15
- "subscribeTicker" => TICKERS,
16
- "unsubscribeTicker" => TICKERS,
17
- "ticker" => TICKERS,
18
-
19
- "subscribeOrderbook" => ORDERBOOK,
20
- "unsubscribeOrderbook" => ORDERBOOK,
21
- "snapshotOrderbook" => ORDERBOOK,
22
- "updateOrderbook" => ORDERBOOK,
23
-
24
- "subscribeTrades" => TRADES,
25
- "unsubscribeTrades" => TRADES,
26
- "snapshotTrades" => TRADES,
27
- "updateTrades" => TRADES,
28
-
29
- "subscribeCandles" => CANDLES,
30
- "unsubscribeCandles" => CANDLES,
31
- "snapshotCandles" => CANDLES,
32
- "updateCandles" => CANDLES
33
- }
34
-
35
- def mapping(method)
36
- return MAP[method]
37
- end
1
+ # frozen_string_literal: true
38
2
 
39
- def orderbookFeed(method)
40
- return MAP[method] == ORDERBOOK
41
- end
42
-
43
- def tradesFeed(method)
44
- return MAP[method] == TRADES
45
- end
46
-
47
- def candlesFeed(method)
48
- return MAP[method] == CANDLES
49
- end
50
-
51
- def reportsFeed(method)
52
- return MAP[method] == REPORTS
53
- end
54
- end
3
+ module Cryptomarket
4
+ module Websocket
5
+ module Methods
6
+ ORDERBOOK = 'orderbook'
7
+ REPORTS = 'reports'
8
+ TICKERS = 'tickers'
9
+ TRADES = 'trades'
10
+ CANDLES = 'candles'
11
+ MAP = {
12
+ 'subscribeReports' => REPORTS,
13
+ 'unsubscribeReports' => REPORTS,
14
+ 'activeOrders' => REPORTS,
15
+ 'report' => REPORTS,
16
+
17
+ 'subscribeTicker' => TICKERS,
18
+ 'unsubscribeTicker' => TICKERS,
19
+ 'ticker' => TICKERS,
20
+
21
+ 'subscribeOrderbook' => ORDERBOOK,
22
+ 'unsubscribeOrderbook' => ORDERBOOK,
23
+ 'snapshotOrderbook' => ORDERBOOK,
24
+ 'updateOrderbook' => ORDERBOOK,
25
+
26
+ 'subscribeTrades' => TRADES,
27
+ 'unsubscribeTrades' => TRADES,
28
+ 'snapshotTrades' => TRADES,
29
+ 'updateTrades' => TRADES,
30
+
31
+ 'subscribeCandles' => CANDLES,
32
+ 'unsubscribeCandles' => CANDLES,
33
+ 'snapshotCandles' => CANDLES,
34
+ 'updateCandles' => CANDLES
35
+ }.freeze
55
36
  end
56
- end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cryptomarket
4
+ module Websocket
5
+ # A wrapper for a callback, enable reuse of a callback up to an n number of times, and signals when is done reusing.
6
+ class ReusableCallback
7
+ def initialize(callback, call_count)
8
+ @call_count = call_count
9
+ @callback = callback
10
+ end
11
+
12
+ def get_callback # rubocop:disable Naming/AccessorMethodName
13
+ return [nil, false] if @call_count < 1
14
+
15
+ @call_count -= 1
16
+ done_using = @call_count < 1
17
+ [@callback, done_using]
18
+ end
19
+ end
20
+ end
21
+ end