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