deribit-api 0.0.3 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05d5477493865ee6cbb3377f3e3b00b7cf46b4e6b68d521e55330e391a3aa5cd
4
- data.tar.gz: bbd48b6395cca467b1f5cb86ab3d7aeea3d888d69a8bddbd98178cbf841af849
3
+ metadata.gz: e11b1e56992f333f743eb40b24a6c336b06faa7ed3fa981383477e4b7ae87e90
4
+ data.tar.gz: aae71272675f88e4e793afbcb239662592beeae2f2f6e6fe8d5ce8eff5550f61
5
5
  SHA512:
6
- metadata.gz: b0af359c229cc8e7651fe2cbf2c0609ffefce77d09bca0a750cb884d33fb2d17b2de56fd19c1aa7414375ca99149ac581b016c7893732afaaaf86c248398aff6
7
- data.tar.gz: 876927c4c4acc286246a5315b66efa642053a925777953fce590ffc6af2627ba0a38ff95e7e49508517646512d8437fde4e3e8b9a15e7891892d23eaec950e51
6
+ metadata.gz: 423ba0584bd643834fb4ee11c7b57253565f37c544b207262604105b17bf3e406391db088745a84bead68ead8afa556f9f6d9a23eae15b7e2f97fcca94331767
7
+ data.tar.gz: a726ef0e7cc7dddafe08a8d48d608ef0b6506aca6c773643556912232ff98c2b7582928e345559c5a3cfd6c5a3709d8d27b99042feb87df76ea082ccc3c60eba
@@ -5,6 +5,13 @@
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.0] - 2019-04-02
9
+ ### Added
10
+ - public Websocket API
11
+ ### Fixed
12
+ - feature matrix in README.md
13
+ - unknown keyword error
14
+
8
15
  ## [0.0.3] - 2019-03-06
9
16
  ### Added
10
17
  - private HTTP API endpoints
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deribit-api (0.0.3)
4
+ deribit-api (0.1.0)
5
5
  faraday
6
6
  faraday_middleware
7
+ faye-websocket
7
8
  hashie
8
9
 
9
10
  GEM
@@ -25,10 +26,14 @@ GEM
25
26
  docile (1.3.1)
26
27
  dotenv (2.7.1)
27
28
  equalizer (0.0.11)
29
+ eventmachine (1.2.7)
28
30
  faraday (0.15.4)
29
31
  multipart-post (>= 1.2, < 3)
30
32
  faraday_middleware (0.13.1)
31
33
  faraday (>= 0.7.4, < 1.0)
34
+ faye-websocket (0.10.7)
35
+ eventmachine (>= 0.12.0)
36
+ websocket-driver (>= 0.5.1)
32
37
  hashie (3.6.0)
33
38
  ice_nine (0.11.2)
34
39
  json (2.2.0)
@@ -64,6 +69,9 @@ GEM
64
69
  coercible (~> 1.0)
65
70
  descendants_tracker (~> 0.0, >= 0.0.3)
66
71
  equalizer (~> 0.0, >= 0.0.9)
72
+ websocket-driver (0.7.0)
73
+ websocket-extensions (>= 0.1.0)
74
+ websocket-extensions (0.1.3)
67
75
  yard (0.9.18)
68
76
 
69
77
  PLATFORMS
data/README.md CHANGED
@@ -69,6 +69,14 @@ Orderbook for BTCUSD perpetual instrument:
69
69
  ```ruby
70
70
  orderbook = client.orderbook 'BTC-PERPETUAL', depth: 3
71
71
  puts orderbook.asks.first
72
+ ```
73
+
74
+ Orderbook streaming via websocket:
75
+
76
+ ```ruby
77
+ @client.orderbook 'ETH-PERPETUAL' do |orderbook|
78
+ puts orderbook
79
+ end
72
80
  ```
73
81
 
74
82
  Place a BTCUSD limit buy order 100 contracts @ 2500:
@@ -78,13 +86,21 @@ response = client.buy 'BTC-PERPETUAL', 100, price: 2500
78
86
  puts response.order.state
79
87
  ```
80
88
 
81
- Get last 10 option trades:
89
+ Get last 10 option trades via HTTP:
82
90
 
83
91
  ```ruby
84
92
  trades = client.trades 'options', count: 10
85
93
  puts trades.first
86
94
  ```
87
95
 
96
+ Stream ongoing trades via websocket:
97
+
98
+ ```ruby
99
+ @client.trades do |trade|
100
+ puts trade
101
+ end
102
+ ```
103
+
88
104
  Options trading summary:
89
105
 
90
106
  ```ruby
@@ -96,19 +112,21 @@ puts summaries.first
96
112
 
97
113
  All endpoints marked with [X] are fully implemented and ready to use, see the features table below:
98
114
 
99
- API endpoints | Private? | HTTP API | Websocket API | FIX API
100
- ---| :---: | :---: | :---: |
101
- Time || [X] ||
102
- Test || [X] ||
103
- Ping || [X] ||
104
- Instruments || [X] ||
105
- Currencies || [X] ||
106
- Index || [X] ||
107
- Orderbook || [X] ||
108
- Trades || [X] ||
109
- Summary || [X] ||
110
- Announcements || [X] ||
111
- Settlements || [X] ||
115
+ API endpoints | Private? | HTTP API | Websocket API | FIX API |
116
+ --------------|----------|----------|---------------|---------|
117
+ Time || [X] | [X] ||
118
+ Setheartbeat || N/A | [X] ||
119
+ Cancelheartbeat || N/A | [X] ||
120
+ Test || [X] | [X] ||
121
+ Ping || [X] | [X] ||
122
+ Instruments || [X] | [X] ||
123
+ Currencies || [X] | [X] ||
124
+ Index || [X] | [X] ||
125
+ Orderbook || [X] | [X] ||
126
+ Trades || [X] | [X] ||
127
+ Summary || [X] | [X] ||
128
+ Announcements || [X] | [X] ||
129
+ Settlements || [X] | [X] ||
112
130
  Account | YES | [X] ||
113
131
  Buy | YES | [X] ||
114
132
  Sell | YES | [X] ||
data/TODOs.org CHANGED
@@ -8,7 +8,20 @@
8
8
  ** FIX API
9
9
  ** DONE use minitest
10
10
  CLOSED: [2019-02-26 Tue] SCHEDULED: <2019-02-26 Tue>
11
- ** extract RPC client
12
- ** Websocket API
11
+ ** extract HTTP client
12
+ ** DONE public Websocket API
13
+ CLOSED: [2019-04-02 Tue 13:12] SCHEDULED: <2019-03-29 Fri>
14
+ :LOGBOOK:
15
+ CLOCK: [2019-04-02 Tue 10:10]--[2019-04-02 Tue 13:12] => 3:02
16
+ :END:
17
+ ** private Websocket API
13
18
  ** response middleware
14
19
  ** check key/secret present for private endpoints
20
+ ** fix trade history
21
+ ** research async websocket implementation
22
+ ** TODO Deribit implementation
23
+ SCHEDULED: <2019-04-09 Tue +1w>
24
+ :PROPERTIES:
25
+ :LAST_REPEAT: [2019-04-02 Tue 13:02]
26
+ :END:
27
+ - State "DONE" from "TODO" [2019-04-02 Tue 13:02]
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency 'faraday'
39
39
  spec.add_dependency 'faraday_middleware'
40
40
  spec.add_dependency 'hashie'
41
+ spec.add_dependency 'faye-websocket'
41
42
 
42
43
  spec.add_development_dependency 'bundler'
43
44
  spec.add_development_dependency 'dotenv'
@@ -1,10 +1,12 @@
1
1
  require 'faraday'
2
2
  require 'faraday_middleware'
3
3
  require 'hashie'
4
+ require 'faye/websocket'
4
5
 
5
6
  require 'deribit/version'
6
7
  require 'deribit/client'
7
8
  require 'deribit/authentication'
9
+ require 'deribit/websocket'
8
10
 
9
11
  # Root module
10
12
  module Deribit
@@ -2,9 +2,9 @@ module Deribit
2
2
  # @author Iulian Costan
3
3
  class Client
4
4
  # URL for testnet
5
- TESTNET_URL = 'https://test.deribit.com'
5
+ TESTNET_URL = 'test.deribit.com'
6
6
  # URL for mainnet
7
- MAINNET_URL = 'https://www.deribit.com'
7
+ MAINNET_URL = 'www.deribit.com'
8
8
 
9
9
  # Create new instance
10
10
  # @param key [String] Deribit Access Key
@@ -13,7 +13,7 @@ module Deribit
13
13
  # @param debug [Boolean] set to true for debug output
14
14
  # @return [Deribit::Client] the instance of client
15
15
  def initialize(key: nil, secret: nil, testnet: false, debug: false)
16
- url = testnet ? TESTNET_URL : MAINNET_URL
16
+ url = 'https://' + (testnet ? TESTNET_URL : MAINNET_URL)
17
17
  @connection = Faraday::Connection.new(url: url) do |f|
18
18
  f.request :json
19
19
  f.response :mashify
@@ -26,57 +26,116 @@ module Deribit
26
26
 
27
27
  # Retrieves the current time (in ms).
28
28
  # @return [Integer] current time in milliseconds
29
+ # @yield [Integer] current time in milliseconds
29
30
  # @see https://docs.deribit.com/rpc-endpoints.html#time
30
- def time
31
- get :time
31
+ def time(&blk)
32
+ if block_given?
33
+ websocket.subscribe :time, &blk
34
+ else
35
+ get :time
36
+ end
37
+ end
38
+
39
+ # Signals the Websocket connection to send and request heartbeats.
40
+ # @param interval [Integer] The heartbeat interval
41
+ # @yield [String] 'ok' on success, error message otherwise
42
+ # @see https://docs.deribit.com/rpc-endpoints.html#setheartbeat
43
+ def enable_heartbeat(interval = 60, &blk)
44
+ raise 'This API endpoint cannot be used over HTTP.' unless block_given?
45
+
46
+ websocket.subscribe :setheartbeat, params: { interval: interval }, &blk
47
+ end
48
+
49
+ # Signals the Websocket connection to not send or request heartbeats.
50
+ # @yield [String] 'ok' on success, error message otherwise
51
+ # @see https://docs.deribit.com/rpc-endpoints.html#cancelheartbeat
52
+ def cancel_heartbeat(&blk)
53
+ raise 'This API endpoint cannot be used over HTTP.' unless block_given?
54
+
55
+ websocket.subscribe :cancelheartbeat, &blk
32
56
  end
33
57
 
34
58
  # Tests the connection to the API server, and returns its version.
35
59
  # @param exception [any] Provide this parameter force an error message.
36
60
  # @return [Hashie::Mash] test data
61
+ # @yield [Hashie::Mash] test data
37
62
  # @see https://docs.deribit.com/rpc-endpoints.html#test
38
- def test(exception: false)
39
- get :test, params: { exception: exception }, raw_body: true
63
+ def test(exception: false, &blk)
64
+ params = { exception: exception }
65
+ if block_given?
66
+ websocket.subscribe :test, params: params, &blk
67
+ else
68
+ get :test, params: params, raw_body: true
69
+ end
40
70
  end
41
71
 
42
72
  # This API endpoint always responds with "pong".
43
- # @return [Hashie::Mash] ping
73
+ # @return [String] pong
74
+ # @yield [String] pong
44
75
  # @see https://docs.deribit.com/rpc-endpoints.html#ping
45
- def ping
46
- get :ping
76
+ def ping(&blk)
77
+ if block_given?
78
+ websocket.subscribe :ping, &blk
79
+ else
80
+ get :ping
81
+ end
47
82
  end
48
83
 
49
84
  # Retrieves available trading instruments.
50
85
  # @param expired [Boolean] Set to true to show expired instruments instead of active ones.
51
86
  # @return [Array] the list of instruments
87
+ # @yield [Hashie::Mash] the instrument
52
88
  # @see https://docs.deribit.com/rpc-endpoints.html#getinstruments
53
- def instruments(expired: false)
54
- get :getinstruments, params: { expired: expired }
89
+ def instruments(expired: false, &blk)
90
+ params = { expired: expired }
91
+ if block_given?
92
+ websocket.subscribe :getinstruments, params: params, &blk
93
+ else
94
+ get :getinstruments, params: params
95
+ end
55
96
  end
56
97
 
57
98
  # Retrieves all cryptocurrencies supported by the API.
58
99
  # @return [Array] the list of cryptocurrencies
100
+ # @yield [Hashie:Hash] the currency
59
101
  # @see https://docs.deribit.com/rpc-endpoints.html#getcurrencies
60
- def currencies
61
- get :getcurrencies
102
+ def currencies(&blk)
103
+ if block_given?
104
+ websocket.subscribe :getcurrencies, &blk
105
+ else
106
+ get :getcurrencies
107
+ end
62
108
  end
63
109
 
64
110
  # Retrieves the current index price for the BTC-USD instruments.
111
+ # @param currency [String] the currency to get index for
65
112
  # @return [Hashie::Mash] index price for BTC-USD instrument
113
+ # @yield [Hashie::Mash] index price for BTC-USD instrument
66
114
  # @see https://docs.deribit.com/rpc-endpoints.html#index
67
- def index
68
- get :index
115
+ def index(currency = 'BTC', &blk)
116
+ params = { currency: currency }
117
+ if block_given?
118
+ websocket.subscribe :index, params: params, &blk
119
+ else
120
+ get :index, params: params
121
+ end
69
122
  end
70
123
 
71
124
  # Retrieves the order book, along with other market values for a given instrument.
72
125
  # @param instrument [String] The instrument name for which to retrieve the order book, (see #instruments) to obtain instrument names.
73
126
  # @param depth [Integer] the depth of the order book
74
127
  # @return [Hashie::Mash] the order book
128
+ # @yield [Hashie::Mash] the order book
75
129
  # @see https://docs.deribit.com/rpc-endpoints.html#getorderbook
76
- def orderbook(instrument, depth: 10)
130
+ def orderbook(instrument, depth: 10, &blk)
77
131
  raise ArgumentError, 'instrument param is required' unless instrument
78
132
 
79
- get :getorderbook, params: { instrument: instrument, depth: depth }
133
+ params = { instrument: instrument, depth: depth }
134
+ if block_given?
135
+ websocket.subscribe :getorderbook, params: params, &blk
136
+ else
137
+ get :getorderbook, params: params
138
+ end
80
139
  end
81
140
 
82
141
  # Retrieve the latest trades that have occurred for a specific instrument.
@@ -92,35 +151,57 @@ module Deribit
92
151
  # @option filters [Integer] :endTimestamp The timestamp (in ms) of the last trade to be returned
93
152
  # @option filters [Boolean] :includeOld (false) to get archived trades for expired instruments when true (added from performance considerations)
94
153
  # @return [Array] the list of trades
154
+ # @yield [Hashie::Mash] new trade
95
155
  # @see https://docs.deribit.com/rpc-endpoints.html#getlasttrades
96
- def trades(instrument = :all, filters = {})
156
+ def trades(instrument = :all, filters = {}, &blk)
97
157
  raise ArgumentError, 'instrument param is required' unless instrument
98
158
 
99
- get :getlasttrades, params: filters.merge(instrument: instrument)
159
+ params = filters.merge(instrument: instrument)
160
+ if block_given?
161
+ websocket.subscribe :getlasttrades, params: params, &blk
162
+ else
163
+ get :getlasttrades, params: params
164
+ end
100
165
  end
101
166
 
102
167
  # Retrieves the summary information such as open interest, 24h volume, etc. for a specific instrument.
103
168
  # @param instrument [String] Either the name of the instrument, or 'all' for all active instruments, 'futures' for all active futures, or 'options' for all active options.
104
- # @return [Array, Hashie::Hash] the summary as array or hash based on instrument param
169
+ # @return [Array, Hashie::Mash] the summary as array or hash based on instrument param
170
+ # @yield [Hashie::Mash] the summary
105
171
  # @see https://docs.deribit.com/rpc-endpoints.html#getsummary
106
- def summary(instrument)
172
+ def summary(instrument = :all, &blk)
107
173
  raise ArgumentError, 'instrument argument is required' unless instrument
108
174
 
109
- get :getsummary, params: { instrument: instrument }
175
+ params = { instrument: instrument }
176
+ if block_given?
177
+ websocket.subscribe :getsummary, params: params, &blk
178
+ else
179
+ get :getsummary, params: params
180
+ end
110
181
  end
111
182
 
112
183
  # Retrieves aggregated 24h trade volumes for different instrument types.
113
184
  # @return [Hashie::Mash] the statistics
185
+ # @yield [Hashie::Mash] the statistics
114
186
  # @see https://docs.deribit.com/rpc-endpoints.html#stats
115
- def stats
116
- get :stats
187
+ def stats(&blk)
188
+ if block_given?
189
+ websocket.subscribe :stats, &blk
190
+ else
191
+ get :stats
192
+ end
117
193
  end
118
194
 
119
195
  # Retrieves announcements from last 30 days.
120
196
  # @return [Array] the list of announcements
197
+ # @yield [Hashie::Mash] the announcement
121
198
  # @see https://docs.deribit.com/rpc-endpoints.html#getannouncements
122
- def announcements
123
- get :getannouncements
199
+ def announcements(&blk)
200
+ if block_given?
201
+ websocket.subscribe :getannouncements, &blk
202
+ else
203
+ get :getannouncements
204
+ end
124
205
  end
125
206
 
126
207
  # Retrieves settlement, delivery and bankruptcy events that have occurred.
@@ -130,10 +211,15 @@ module Deribit
130
211
  # @option filters [String] :type The type of settlements to return. Possible values "settlement", "delivery", "bankruptcy"
131
212
  # @option filters [Integer] :startTstamp The latest timestamp to return result for
132
213
  # @option filters [String] :continuation Continuation token for pagination. Each response contains a token to be used for continuation
133
- # @return [Hashie::Hash] the settlements
214
+ # @return [Hashie::Mash] the settlements
215
+ # @yield [Hashie::Mash] the settlements
134
216
  # @see https://docs.deribit.com/rpc-endpoints.html#getlastsettlements
135
- def settlements(filters = {})
136
- get :getlastsettlements, params: filters
217
+ def settlements(filters = {}, &blk)
218
+ if block_given?
219
+ websocket.subscribe :getlastsettlements, params: filters, &blk
220
+ else
221
+ get :getlastsettlements, params: filters
222
+ end
137
223
  end
138
224
 
139
225
  # Retrieves user account summary.
@@ -289,12 +375,16 @@ module Deribit
289
375
  # @option filters [String] :type The type of settlements to return. Possible values "settlement", "delivery", "bankruptcy"
290
376
  # @option filters [Integer] :startTstamp The latest timestamp to return result for
291
377
  # @option filters [String] :continuation Continuation token for pagination. Each response contains a token to be used for continuation
292
- # @return [Hashie::Hash] the settlements
378
+ # @return [Hashie::Mash] the settlements
293
379
  # @see https://docs.deribit.com/rpc-endpoints.html#settlementhistory
294
380
  def settlements_history(filters = {})
295
381
  get :settlementhistory, auth: true, params: filters
296
382
  end
297
383
 
384
+ def websocket
385
+ Deribit::Websocket.new TESTNET_URL
386
+ end
387
+
298
388
  private
299
389
 
300
390
  def get(action, params: {}, raw_body: false, auth: false)
@@ -1,3 +1,3 @@
1
1
  module Deribit
2
- VERSION = '0.0.3'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -0,0 +1,82 @@
1
+ module Deribit
2
+ class Websocket
3
+ attr_reader :host, :api_key, :api_secret
4
+
5
+ # Create new websocket instance
6
+ # @param host [String] the underlying host to connect to
7
+ # @param api_key [String] the api key
8
+ # @param api_secret [String] the api secret
9
+ # @return [Deribit::Websocket] new websocket instance
10
+ def initialize(host, api_key: nil, api_secret: nil)
11
+ @host = host
12
+ @api_key = api_key
13
+ @api_secret = api_secret
14
+ @callbacks = {}
15
+ end
16
+
17
+ # Subscribe to a specific topic and optionally filter by symbol
18
+ # @param topic [String] topic to subscribe to e.g. 'trade'
19
+ # @param params [Hash] the arguments for subscription
20
+ # @yield [Array] data payload
21
+ def subscribe(topic, params: {}, &callback)
22
+ raise 'callback block is required' unless block_given?
23
+
24
+ EM.run do
25
+ connect
26
+
27
+ id = rand(9999)
28
+ @callbacks[id] = callback
29
+
30
+ payload = { id: id, action: "/api/v1/public/#{topic}", arguments: params }
31
+ @faye.send payload.to_json.to_s
32
+ end
33
+ end
34
+
35
+ # Stop websocket listener
36
+ def stop
37
+ EM.stop_event_loop
38
+ end
39
+
40
+ private
41
+
42
+ def websocket_url
43
+ "wss://#{host}/ws/api/v1/"
44
+ end
45
+
46
+ def headers
47
+ {}
48
+ end
49
+
50
+ def connect
51
+ @result = nil
52
+ @faye = Faye::WebSocket::Client.new websocket_url, [], headers: headers
53
+ @faye.on :open do |_event|
54
+ # puts [:open, event.data]
55
+ end
56
+ @faye.on :error do |event|
57
+ raise event.message
58
+ end
59
+ @faye.on :close do |_event|
60
+ # puts [:close, event.reason]
61
+ @faye = nil
62
+ end
63
+ @faye.on :message do |event|
64
+ json = JSON.parse event.data
65
+ id = json['id']
66
+ data = json['result'] || json['message']
67
+
68
+ callback = @callbacks[id]
69
+ # TODO: rewrite this part
70
+ if callback && data
71
+ data = [data] unless data.is_a? Array
72
+ data.each do |payload|
73
+ payload = Hashie::Mash.new payload if payload.is_a? Hash
74
+ @result = callback.yield payload, @result
75
+ end
76
+ else
77
+ puts "==> #{event.data}"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deribit-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iulian Costan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-06 00:00:00.000000000 Z
11
+ date: 2019-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faye-websocket
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +218,7 @@ files:
204
218
  - lib/deribit/authentication.rb
205
219
  - lib/deribit/client.rb
206
220
  - lib/deribit/version.rb
221
+ - lib/deribit/websocket.rb
207
222
  homepage: https://github.com/icostan/deribit-api-ruby
208
223
  licenses: []
209
224
  metadata: