cryptomarket-sdk 1.0.1 → 3.1.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,324 @@
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 1_000. 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
+ # Requires no API key Access Rights
44
+ #
45
+ # https://api.exchange.cryptomkt.com/#subscribe-to-candles
46
+ #
47
+ # ==== Params
48
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of candles indexed by symbol, and the type of notification (either 'snapshot' or 'update')
49
+ # +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).
50
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
51
+ # +Integer+ +limit+:: Number of historical entries returned in the first feed. Min is 0. Max is 1_000. Default is 0
52
+ # +Proc+ +result_callback+:: Optional. A +Proc+ called with a list of subscribed symbols
53
+
54
+ def subscribe_to_candles(callback:, period:, symbols:, limit: nil, result_callback: nil)
55
+ params = { 'symbols' => symbols, 'limit' => limit }
56
+ send_channel_subscription("candles/#{period}", callback,
57
+ intercept_result_callback(result_callback), params)
58
+ end
59
+
60
+ # subscribes to a feed of candles regarding the last price converted to the target currency for all symbols or for the specified symbols
61
+ #
62
+ # Candles are used for the representation of a specific symbol as an OHLC chart
63
+ #
64
+ # Conversion from the symbol quote currency to the target currency is the mean of "best" bid price and "best" ask price in the order book. If there is no "best" bid or ask price, the last price is returned.
65
+ #
66
+ # Requires no API key Access Rights
67
+ #
68
+ # https://api.exchange.cryptomkt.com/#subscribe-to-converted-candles
69
+ #
70
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of candles indexed by symbol, and the type of notification (either 'snapshot' or 'update')
71
+ # +String+ +target_currency+:: Target currency for conversion
72
+ # +Array[String]+ +symbols+:: A list of symbols
73
+ # +String+ +period+:: A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month).
74
+ # +String+ +from+:: Optional. Initial value of the queried interval. As DateTime
75
+ # +String+ +till+:: Optional. Last value of the queried interval. As DateTime
76
+ # +Integer+ +limit+:: Optional. Prices per currency pair. Defaul is 100. Min is 1. Max is 1_000
77
+ # +Proc+ +result_callback+:: Optional. A +Proc+ called with a list of subscribed symbols
78
+
79
+ def subscribe_to_converted_candles(callback:, target_currency:, symbols:, period:, limit: nil, result_callback: nil) # rubocop:disable Metrics/ParameterLists
80
+ params = { 'target_currency' => target_currency, 'symbols' => symbols, 'limit' => limit }
81
+ send_channel_subscription("converted/candles/#{period}", 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
+ # normal subscriptions have one update message per symbol
90
+ #
91
+ # Requires no API key Access Rights
92
+ #
93
+ # https://api.exchange.cryptomkt.com/#subscribe-to-mini-ticker
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(callback:, speed:, symbols: ['*'], result_callback: nil)
102
+ params = { 'symbols' => symbols }
103
+ send_channel_subscription("ticker/price/#{speed}", callback,
104
+ intercept_result_callback(result_callback), params)
105
+ end
106
+
107
+ # subscribe to a feed of mini tickers
108
+ #
109
+ # subscription is for all symbols or for the specified symbols
110
+ #
111
+ # batch subscriptions have a joined update for all symbols
112
+ #
113
+ # Requires no API key Access Rights
114
+ #
115
+ # https://api.exchange.cryptomkt.com/#subscribe-to-mini-ticker-in-batches
116
+ #
117
+ # ==== Params
118
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of minitickers 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_mini_ticker_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
124
+ params = { 'symbols' => symbols }
125
+ send_channel_subscription("ticker/price/#{speed}/batch", callback,
126
+ intercept_result_callback(result_callback), params)
127
+ end
128
+
129
+ # subscribe to a feed of tickers
130
+ #
131
+ # subscription is for all symbols or for the specified symbols
132
+ #
133
+ # normal subscriptions have one update message per symbol
134
+ #
135
+ # Requires no API key Access Rights
136
+ #
137
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker
138
+ #
139
+ # ==== Params
140
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of tickers indexed by symbol, and the type of notification (only 'data')
141
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
142
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
143
+ # +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
144
+
145
+ def subscribe_to_ticker(callback:, speed:, symbols: ['*'], result_callback: nil)
146
+ params = { 'symbols' => symbols }
147
+ send_channel_subscription("ticker/#{speed}", callback, intercept_result_callback(result_callback), params)
148
+ end
149
+
150
+ # subscribe to a feed of tickers
151
+ #
152
+ # subscription is for all symbols or for the specified symbols
153
+ #
154
+ # batch subscriptions have a joined update for all symbols
155
+ #
156
+ # Requires no API key Access Rights
157
+ #
158
+ # https://api.exchange.cryptomkt.com/#subscribe-to-ticker-in-batches
159
+ #
160
+ # ==== Params
161
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of tickers indexed by symbol, and the type of notification (only 'data')
162
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
163
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
164
+ # +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
165
+
166
+ def subscribe_to_ticker_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
167
+ params = { 'symbols' => symbols }
168
+ send_channel_subscription("ticker/#{speed}/batch", callback, intercept_result_callback(result_callback), params)
169
+ end
170
+
171
+ # subscribe to a feed of a full orderbook
172
+ #
173
+ # subscription is for the specified symbols
174
+ #
175
+ # normal subscriptions have one update message per symbol
176
+ #
177
+ # the first notification is a snapshot of the full orderbook, and next
178
+ # notifications are updates to this snapshot
179
+ #
180
+ # Requires no API key Access Rights
181
+ #
182
+ # https://api.exchange.cryptomkt.com/#subscribe-to-full-order-book
183
+ #
184
+ # ==== Params
185
+ # +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')
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_full_order_book(callback:, symbols:, result_callback: nil)
190
+ params = { 'symbols' => symbols }
191
+ send_channel_subscription('orderbook/full', callback, intercept_result_callback(result_callback), params)
192
+ end
193
+
194
+ # subscribe to a feed of a partial orderbook
195
+ #
196
+ # subscription is for all symbols or for the specified symbols
197
+ #
198
+ # normal subscriptions have one update message per symbol
199
+ #
200
+ # Requires no API key Access Rights
201
+ #
202
+ # https://api.exchange.cryptomkt.com/#subscribe-to-partial-order-book
203
+ #
204
+ # ==== Params
205
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of partial orderbooks indexed by symbol, and the type of notification (only 'data')
206
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
207
+ # +String+ +depth+:: The depth of the partial orderbook
208
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
209
+ # +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
210
+
211
+ def subscribe_to_partial_order_book(callback:, depth:, speed:, symbols: ['*'], result_callback: nil)
212
+ params = { 'symbols' => symbols }
213
+ send_channel_subscription("orderbook/#{depth}/#{speed}", callback,
214
+ intercept_result_callback(result_callback), params)
215
+ end
216
+
217
+ # subscribe to a feed of a partial orderbook in batches
218
+ #
219
+ # subscription is for all symbols or for the specified symbols
220
+ #
221
+ # batch subscriptions have a joined update for all symbols
222
+ #
223
+ # https://api.exchange.cryptomkt.com/#subscribe-to-partial-order-book-in-batches
224
+ #
225
+ # ==== Params
226
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of partial orderbooks indexed by symbol, and the type of notification (only 'data')
227
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
228
+ # +String+ +depth+:: The depth of the partial orderbook
229
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
230
+ # +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
231
+
232
+ def subscribe_to_partial_order_book_in_batches(callback:, depth:, speed:, symbols: ['*'],
233
+ result_callback: nil)
234
+ params = { 'symbols' => symbols }
235
+ send_channel_subscription("orderbook/#{depth}/#{speed}/batch", callback,
236
+ intercept_result_callback(result_callback), params)
237
+ end
238
+
239
+ # subscribe to a feed of the top of the orderbook
240
+ #
241
+ # subscription is for all symbols or for the specified symbols
242
+ #
243
+ # normal subscriptions have one update message per symbol
244
+ #
245
+ # https://api.exchange.cryptomkt.com/#subscribe-to-top-of-book
246
+ #
247
+ # ==== Params
248
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
249
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
250
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
251
+ # +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
252
+
253
+ def subscribe_to_top_of_book(callback:, speed:, symbols: ['*'], result_callback: nil)
254
+ params = { 'symbols' => symbols }
255
+ send_channel_subscription("orderbook/top/#{speed}", callback,
256
+ intercept_result_callback(result_callback), params)
257
+ end
258
+
259
+ # subscribe to a feed of the top of the orderbook
260
+ #
261
+ # subscription is for all symbols or for the specified symbols
262
+ #
263
+ # batch subscriptions have a joined update for all symbols
264
+ #
265
+ # https://api.exchange.cryptomkt.com/#subscribe-to-top-of-book-in-batches
266
+ #
267
+ # ==== Params
268
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
269
+ # +String+ +speed+:: The speed of the feed. '100ms', '500ms' or '1000ms'
270
+ # +Array[String]+ +symbols+:: Optional. A list of symbol ids
271
+ # +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
272
+
273
+ def subscribe_to_top_of_book_in_batches(callback:, speed:, symbols: ['*'], result_callback: nil)
274
+ params = { 'symbols' => symbols }
275
+ send_channel_subscription("orderbook/top/#{speed}/batch", callback,
276
+ intercept_result_callback(result_callback), params)
277
+ end
278
+
279
+ # subscribe to a feed of the top of the orderbook
280
+ #
281
+ # subscription is for all currencies or for the specified currencies
282
+ #
283
+ # https://api.exchange.cryptomkt.com/#subscribe-to-price-rates
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(callback:, speed:, target_currency:, currencies: ['*'], result_callback: nil)
293
+ params = {
294
+ speed: speed, target_currency: target_currency, currencies: currencies
295
+ }
296
+ send_channel_subscription("price/rate/#{speed}", callback, intercept_result_callback(result_callback), params)
297
+ end
298
+
299
+ # subscribe to a feed of the top of the orderbook
300
+ #
301
+ # subscription is for all currencies or for the specified currencies
302
+ #
303
+ # batch subscriptions have a joined update for all currencies
304
+ #
305
+ # https://api.exchange.cryptomkt.com/#subscribe-to-price-rates-in-batches
306
+ #
307
+ # ==== Params
308
+ # +Proc+ +callback+:: A +Proc+ that recieves notifications as a hash of top of orderbooks indexed by symbol, and the type of notification (only 'data')
309
+ # +String+ +speed+:: The speed of the feed. '1s' or '3s'
310
+ # +String+ +target_currency+:: Quote currency of the rate
311
+ # +Array[String]+ +currencies+:: Optional. A list of currencies ids
312
+ # +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
313
+
314
+ def subscribe_to_price_rates_in_batches(callback:, speed:, target_currency:, currencies: ['*'],
315
+ result_callback: nil)
316
+ params = {
317
+ speed: speed, target_currency: target_currency, currencies: currencies
318
+ }
319
+ send_channel_subscription("price/rate/#{speed}/batch", callback,
320
+ intercept_result_callback(result_callback), params)
321
+ end
322
+ end
323
+ end
324
+ 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