deribit-api 0.1.5 → 2.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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +71 -48
- data/README.md +63 -76
- data/TODOs.org +8 -2
- data/bin/auth.sh +18 -0
- data/bin/trades.py +24 -0
- data/bin/trades.rb +43 -0
- data/bin/whales-watching.rb +25 -0
- data/deribit.gemspec +8 -5
- data/lib/deribit.rb +21 -8
- data/lib/deribit/authentication.rb +9 -14
- data/lib/deribit/client.rb +203 -350
- data/lib/deribit/http.rb +20 -13
- data/lib/deribit/naming.rb +82 -0
- data/lib/deribit/version.rb +1 -1
- data/lib/deribit/websocket.rb +73 -54
- metadata +55 -8
data/lib/deribit/http.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
module Deribit
|
2
2
|
# HTTP API
|
3
|
+
# @author Iulian Costan (deribit-api@iuliancostan.com)
|
3
4
|
# @see https://docs.deribit.com/api-http.html
|
4
5
|
class Http
|
5
6
|
def initialize(host, key: nil, secret: nil, debug: false)
|
6
|
-
|
7
|
-
@connection = Faraday::Connection.new(url: url) do |f|
|
7
|
+
@connection = Faraday::Connection.new(url: http_url(host)) do |f|
|
8
8
|
f.request :json
|
9
|
+
f.use Deribit::Authentication, key, secret
|
9
10
|
f.response :mashify
|
10
11
|
f.response :json
|
11
|
-
f.use
|
12
|
+
f.use Faraday::Response::RaiseError
|
12
13
|
f.response :detailed_logger if debug
|
13
14
|
f.adapter Faraday.default_adapter
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
def get(
|
18
|
-
response = @connection.get path(
|
18
|
+
def get(uri, params = {})
|
19
|
+
response = @connection.get path(uri), params
|
19
20
|
|
20
21
|
# TODO: move to middleware
|
21
|
-
raise response.
|
22
|
-
raise response.body.message unless response.body.success
|
22
|
+
# raise response.error unless response.error
|
23
|
+
# raise response.body.message unless response.body.success
|
23
24
|
|
24
25
|
body = response.body
|
25
|
-
|
26
|
+
body.result
|
26
27
|
end
|
27
28
|
|
28
|
-
def post(
|
29
|
-
response = @connection.post path(
|
29
|
+
def post(uri, params)
|
30
|
+
response = @connection.post path(uri), params
|
30
31
|
|
31
32
|
# TODO: move to middleware
|
32
33
|
raise response.message unless response.success?
|
@@ -37,9 +38,15 @@ module Deribit
|
|
37
38
|
|
38
39
|
private
|
39
40
|
|
40
|
-
def path(
|
41
|
-
|
42
|
-
|
41
|
+
def path(uri)
|
42
|
+
path = '/api/v2'
|
43
|
+
path += '/' unless uri.start_with? '/'
|
44
|
+
path += uri
|
45
|
+
path
|
46
|
+
end
|
47
|
+
|
48
|
+
def http_url(host)
|
49
|
+
'https://' + host
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Naming
|
4
|
+
def self.trades_channel(options)
|
5
|
+
private = options.delete :private
|
6
|
+
trades = private ? 'user.trades' : 'trades'
|
7
|
+
channel trades, options
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.trades_uri(options)
|
11
|
+
private = options.delete :private
|
12
|
+
uri = private ? 'private/get_user_trades' : 'public/get_last_trades'
|
13
|
+
uri += options[:instrument_name] ? '_by_instrument' : '_by_currency'
|
14
|
+
uri += options[:end_timestamp] ? '_and_time' : ''
|
15
|
+
uri
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.book_channel(options)
|
19
|
+
'book' + for_instrument(options) + with_group_and_depth(options) + with_interval(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.channel(prefix, options)
|
23
|
+
prefix + channel_suffix(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.channel_for_instrument(prefix, options)
|
27
|
+
prefix + for_instrument(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.instrument_with_interval(prefix, options)
|
31
|
+
prefix + for_instrument(options) + with_interval(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.cancel_uri(options)
|
35
|
+
"/private/cancel_all" + by_instrument(options) + by_currency(options)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.by_instrument(options)
|
41
|
+
options[:instrument_name] ? '_by_instrument' : ''
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.by_currency(options)
|
45
|
+
options[:currency] ? '_by_currency' : ''
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.for_instrument(options)
|
49
|
+
raise 'instrument_name param is required' unless options[:instrument_name]
|
50
|
+
|
51
|
+
".#{options[:instrument_name]}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.with_interval(options)
|
55
|
+
interval = options[:interval] || '100ms'
|
56
|
+
".#{interval}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.with_group_and_depth(options)
|
60
|
+
if options[:group] || options[:depth]
|
61
|
+
group = options[:group] || '5'
|
62
|
+
depth = options[:depth] || '10'
|
63
|
+
".#{group}.#{depth}"
|
64
|
+
else
|
65
|
+
''
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.channel_suffix(options)
|
70
|
+
currency = options[:currency]
|
71
|
+
instrument_name = options[:instrument_name]
|
72
|
+
kind = options[:kind] || 'any'
|
73
|
+
interval = options[:interval] || 'raw'
|
74
|
+
if instrument_name
|
75
|
+
".#{instrument_name}.#{interval}"
|
76
|
+
elsif currency
|
77
|
+
".#{kind}.#{currency}.#{interval}"
|
78
|
+
else
|
79
|
+
raise 'invalid args'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/deribit/version.rb
CHANGED
data/lib/deribit/websocket.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Deribit
|
2
4
|
# Websocket API
|
3
|
-
# @
|
5
|
+
# @author Iulian Costan (deribit-api@iuliancostan.com)
|
6
|
+
# @see https://docs.deribit.com/#subscriptions
|
4
7
|
class Websocket
|
5
|
-
attr_reader :host, :key, :secret
|
8
|
+
attr_reader :host, :key, :secret, :access_token, :callbacks
|
6
9
|
|
7
10
|
# Create new websocket instance
|
8
11
|
# @param host [String] the underlying host to connect to
|
@@ -14,6 +17,7 @@ module Deribit
|
|
14
17
|
@key = key
|
15
18
|
@secret = secret
|
16
19
|
@callbacks = {}
|
20
|
+
@ws = nil
|
17
21
|
end
|
18
22
|
|
19
23
|
# Subscribe to a specific topic and optionally filter by symbol
|
@@ -21,85 +25,100 @@ module Deribit
|
|
21
25
|
# @param params [Hash] the arguments for subscription
|
22
26
|
# @yield [Array] data payload
|
23
27
|
def subscribe(topic, params: {}, &callback)
|
24
|
-
raise '
|
25
|
-
|
26
|
-
EM.run do
|
27
|
-
connect
|
28
|
+
raise 'block is required' unless block_given?
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
# connect on demand
|
31
|
+
@ws = connect unless connected?
|
32
|
+
raise 'websocket is closed' unless @ws.open?
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
uri = auth ? 'private' : 'public'
|
36
|
-
action = "/api/v1/#{uri}/#{topic}"
|
34
|
+
# save callback handler
|
35
|
+
@callbacks[topic.to_s] = callback
|
37
36
|
|
38
|
-
|
39
|
-
|
37
|
+
# authorize if needed
|
38
|
+
authorize if authorization_required?(topic)
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
# subscription request
|
41
|
+
payload = {
|
42
|
+
jsonrpc: '2.0',
|
43
|
+
method: 'public/subscribe',
|
44
|
+
id: rand(9999),
|
45
|
+
params: { channels: [topic] }
|
46
|
+
}
|
47
|
+
@ws.send payload.to_json.to_s
|
43
48
|
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
EM.stop_event_loop
|
50
|
+
def authorized?
|
51
|
+
!access_token.nil?
|
48
52
|
end
|
49
53
|
|
50
54
|
private
|
51
55
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
_ackey: @key,
|
56
|
-
_acsec: @secret,
|
57
|
-
_action: action
|
58
|
-
}
|
59
|
-
payload.merge! params
|
60
|
-
# query = env['url'].query
|
56
|
+
def connected?
|
57
|
+
!@ws.nil?
|
58
|
+
end
|
61
59
|
|
62
|
-
|
60
|
+
def authorization_required?(topic)
|
61
|
+
topic.include? 'user'
|
63
62
|
end
|
64
63
|
|
65
|
-
def
|
66
|
-
|
64
|
+
def authorize
|
65
|
+
timestamp = Time.now.utc.to_i * 1000
|
66
|
+
nonce = rand(999_999).to_s
|
67
|
+
signature = Deribit.signature timestamp, nonce, '', @secret
|
68
|
+
payload = {
|
69
|
+
jsonrpc: '2.0',
|
70
|
+
method: 'public/auth',
|
71
|
+
id: 'auth',
|
72
|
+
params: {
|
73
|
+
grant_type: :client_signature,
|
74
|
+
client_id: @key,
|
75
|
+
timestamp: timestamp,
|
76
|
+
nonce: nonce,
|
77
|
+
data: '',
|
78
|
+
signature: signature
|
79
|
+
}
|
80
|
+
}
|
81
|
+
@callbacks['auth'] = lambda do |result|
|
82
|
+
@access_token = result['access_token']
|
83
|
+
end
|
84
|
+
@ws.send payload.to_json.to_s
|
67
85
|
end
|
68
86
|
|
69
|
-
def
|
70
|
-
{}
|
87
|
+
def websocket_url
|
88
|
+
"wss://#{host}/ws/api/v2"
|
71
89
|
end
|
72
90
|
|
73
91
|
def connect
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
# puts [:open, event
|
92
|
+
websocket = self
|
93
|
+
ws = WebSocket::Client::Simple.connect websocket_url
|
94
|
+
ws.on :open do |event|
|
95
|
+
# puts [:open, event]
|
78
96
|
end
|
79
|
-
|
80
|
-
|
97
|
+
ws.on :error do |event|
|
98
|
+
# puts [:error, event.inspect]
|
81
99
|
end
|
82
|
-
|
100
|
+
ws.on :close do |event|
|
83
101
|
# puts [:close, event.reason]
|
84
|
-
|
102
|
+
ws = nil
|
85
103
|
end
|
86
|
-
|
104
|
+
ws.on :message do |event|
|
87
105
|
json = JSON.parse event.data
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
data.each do |payload|
|
96
|
-
payload = Hashie::Mash.new payload if payload.is_a? Hash
|
97
|
-
@result = callback.yield payload, @result
|
106
|
+
if json['method'] == 'subscription'
|
107
|
+
id = json['params']['channel']
|
108
|
+
data = json['params']['data']
|
109
|
+
callback = websocket.callbacks[id]
|
110
|
+
data = [data] if data.is_a? Hash
|
111
|
+
data.each do |datum|
|
112
|
+
@result = callback.yield Hashie::Mash.new(datum)
|
98
113
|
end
|
99
114
|
else
|
100
|
-
|
115
|
+
id = json['id']
|
116
|
+
callback = websocket.callbacks[id]
|
117
|
+
callback&.yield json['result']
|
101
118
|
end
|
102
119
|
end
|
120
|
+
until ws.open? do sleep 1 end # wait for opening
|
121
|
+
ws
|
103
122
|
end
|
104
123
|
end
|
105
124
|
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.
|
4
|
+
version: 2.0.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: 2020-
|
11
|
+
date: 2020-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: faraday-detailed_logger
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: websocket-client-simple
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: hashie
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -206,9 +206,51 @@ dependencies:
|
|
206
206
|
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: '0'
|
209
|
-
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rubocop
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: solargraph
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: irb
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - ">="
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '0'
|
244
|
+
type: :development
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - ">="
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
251
|
+
description: Idiomatic Ruby library for Deribit API 2.0
|
210
252
|
email:
|
211
|
-
-
|
253
|
+
- deribit-api@iuliancostan.com
|
212
254
|
executables: []
|
213
255
|
extensions: []
|
214
256
|
extra_rdoc_files: []
|
@@ -223,14 +265,19 @@ files:
|
|
223
265
|
- README.md
|
224
266
|
- Rakefile
|
225
267
|
- TODOs.org
|
268
|
+
- bin/auth.sh
|
226
269
|
- bin/console
|
227
270
|
- bin/setup
|
271
|
+
- bin/trades.py
|
272
|
+
- bin/trades.rb
|
273
|
+
- bin/whales-watching.rb
|
228
274
|
- deribit.gemspec
|
229
275
|
- lib/deribit-api.rb
|
230
276
|
- lib/deribit.rb
|
231
277
|
- lib/deribit/authentication.rb
|
232
278
|
- lib/deribit/client.rb
|
233
279
|
- lib/deribit/http.rb
|
280
|
+
- lib/deribit/naming.rb
|
234
281
|
- lib/deribit/version.rb
|
235
282
|
- lib/deribit/websocket.rb
|
236
283
|
homepage: https://github.com/icostan/deribit-api-ruby
|
@@ -258,5 +305,5 @@ requirements: []
|
|
258
305
|
rubygems_version: 3.1.2
|
259
306
|
signing_key:
|
260
307
|
specification_version: 4
|
261
|
-
summary: Ruby library for Deribit API
|
308
|
+
summary: Idiomatic Ruby library for Deribit API 2.0
|
262
309
|
test_files: []
|