gemini-rb 0.0.1

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,231 @@
1
+ require 'eventmachine'
2
+ require 'faye/websocket'
3
+ require 'json'
4
+
5
+ module Gemini
6
+ module WebsocketConnection
7
+
8
+ def listen!
9
+ subscribe_to_channels
10
+ listen
11
+ ws_client.run!
12
+ end
13
+
14
+ def ws_send(msg)
15
+ ws_client.send msg
16
+ end
17
+
18
+ def ws_close_all
19
+ ws_client.stop!
20
+ @ws_open = false
21
+ ws_reset_channels
22
+ end
23
+
24
+ def ws_auth(&block)
25
+ unless @ws_auth
26
+ nonce = (Time.now.to_f * 10_000).to_i.to_s
27
+ sub_id = add_callback(&block)
28
+ save_channel_id(sub_id,0)
29
+ if config.api_version == 1
30
+ payload = 'AUTH' + nonce
31
+ signature = sign(payload)
32
+ ws_safe_send({
33
+ apiKey: config.api_key,
34
+ authSig: sign(payload),
35
+ authPayload: payload,
36
+ subId: sub_id.to_s,
37
+ event: 'auth'
38
+ })
39
+ else
40
+ payload = 'AUTH' + nonce + nonce
41
+ signature = sign(payload)
42
+ ws_safe_send({
43
+ apiKey: config.api_key,
44
+ authSig: sign(payload),
45
+ authPayload: payload,
46
+ authNonce: nonce,
47
+ subId: sub_id.to_s,
48
+ event: 'auth'
49
+ })
50
+ end
51
+ @ws_auth = true
52
+ end
53
+ end
54
+
55
+ def ws_unauth
56
+ ws_safe_send({event: 'unauth'})
57
+ end
58
+
59
+ private
60
+
61
+ def ws_reset_channels
62
+ @chan_ids = []
63
+ @ws_registration_messages = []
64
+ @callbacks = {}
65
+ end
66
+
67
+ def ws_client
68
+ options = {
69
+ url: config.websocket_api_endpoint,
70
+ reconnect: config.reconnect,
71
+ reconnect_after: config.reconnect_after
72
+ }
73
+ @ws_client ||= WSClient.new(options)
74
+ end
75
+
76
+ def chan_ids
77
+ @chan_ids ||= []
78
+ end
79
+
80
+ def ws_open
81
+ @ws_open ||= false
82
+ end
83
+
84
+ def ws_registration_messages
85
+ @ws_registration_messages ||= []
86
+ end
87
+
88
+ def callbacks
89
+ @callbacks ||= []
90
+ end
91
+
92
+ def add_callback(&block)
93
+ id = 0
94
+ @mutex.synchronize do
95
+ callbacks[@c_counter] = { block: block, chan_id: nil }
96
+ id = @c_counter
97
+ @c_counter += 1
98
+ end
99
+ id
100
+ end
101
+
102
+ def register_authenticated_channel(msg, &block)
103
+ sub_id = add_callback(&block)
104
+ msg.merge!(subId: sub_id.to_s)
105
+ ws_safe_send(msg.merge(event:'subscribe'))
106
+ end
107
+
108
+ def ws_safe_send(msg)
109
+ if ws_open
110
+ ws_client.send msg
111
+ else
112
+ ws_registration_messages.push msg
113
+ end
114
+ end
115
+
116
+ def register_channel(msg, &block)
117
+ sub_id = add_callback(&block)
118
+ msg.merge!(subId: sub_id.to_s)
119
+ if ws_open
120
+ ws_client.send msg.merge(event: 'subscribe')
121
+ else
122
+ ws_registration_messages.push msg.merge(event: 'subscribe')
123
+ end
124
+ end
125
+
126
+ def listen
127
+ ws_client.on(:message) do |rmsg|
128
+ msg = JSON.parse(rmsg)
129
+ if msg.kind_of?(Hash) && msg["event"] == "subscribed"
130
+ save_channel_id(msg["subId"],msg["chanId"])
131
+ elsif msg.kind_of?(Array)
132
+ exec_callback_for(msg)
133
+ end
134
+ end
135
+ end
136
+
137
+ def save_channel_id(sub_id,chan_id)
138
+ callbacks[sub_id.to_i][:chan_id] = chan_id
139
+ chan_ids[chan_id] = sub_id.to_i
140
+ end
141
+
142
+ def exec_callback_for(msg)
143
+ return if msg[1] == 'hb' #ignore heartbeat
144
+ id = msg[0]
145
+ callbacks[chan_ids[id.to_i]][:block].call(msg)
146
+ end
147
+
148
+ def subscribe_to_channels
149
+ ws_client.on(:open) do
150
+ @ws_open = true
151
+ ws_registration_messages.each do |msg|
152
+ ws_client.send(msg)
153
+ end
154
+ end
155
+ end
156
+
157
+ class WSClient
158
+ def initialize(options = {})
159
+ # set some defaults
160
+ @url = options[:url] || 'wss://api.gemini.com/ws'
161
+ @reconnect = options[:reconnect] || false
162
+ @reconnect_after = options[:reconnect_after] || 30
163
+ @stop = false
164
+ end
165
+
166
+ def on(msg, &blk)
167
+ ivar = "@#{msg}_cb"
168
+ instance_variable_set(ivar.to_sym, blk)
169
+ end
170
+
171
+ def run!
172
+ if EventMachine.reactor_running?
173
+ connect!
174
+ else
175
+ EM.run { connect! }
176
+ end
177
+ end
178
+
179
+ def stop!
180
+ @stop = true
181
+ @ws.close
182
+ end
183
+
184
+ def connect!
185
+ @stop = false
186
+ @ws = Faye::WebSocket::Client.new(@url)
187
+ @ws.onopen = method(:ws_opened)
188
+ @ws.onmessage = method(:ws_receive)
189
+ @ws.onclose = method(:ws_closed)
190
+ @ws.onerror = method(:ws_error)
191
+ end
192
+
193
+ def send(msg)
194
+ raise ConnectionClosed if stopped?
195
+ connect! unless alive?
196
+ msg = msg.is_a?(Hash) ? msg.to_json : msg
197
+ @ws.send(msg)
198
+ end
199
+
200
+ def alive?
201
+ @ws && @ws.ready_state == Faye::WebSocket::API::OPEN
202
+ end
203
+
204
+ def stopped?
205
+ @stop
206
+ end
207
+
208
+ private
209
+
210
+ def ws_opened(event)
211
+ @open_cb.call(event) if @open_cb
212
+ end
213
+
214
+ def ws_receive(event)
215
+ @message_cb.call(event.data) if @message_cb
216
+ end
217
+
218
+ def ws_closed(event)
219
+ if @stop
220
+ EM.stop
221
+ elsif @reconnect
222
+ EM.add_timer(@reconnect_after){ connect! }
223
+ end
224
+ end
225
+
226
+ def ws_error(event)
227
+ raise WebsocketError, event.message
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1 @@
1
+ require_relative "./gemini.rb"
data/lib/gemini.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'uri'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'faraday'
5
+ require 'json'
6
+ require 'faraday_middleware'
7
+ require 'gemini/configurable'
8
+ require 'gemini/errors'
9
+ require 'gemini/connection'
10
+ require 'gemini/websocket_connection'
11
+ require 'gemini/authenticated_rest'
12
+ require 'gemini/api_versions'
13
+ require 'gemini/client'
14
+
15
+ # API Version 1
16
+ require 'gemini/v1/ticker'
17
+ require 'gemini/v1/trades'
18
+ require 'gemini/v1/funding_book'
19
+ require 'gemini/v1/orderbook'
20
+ require 'gemini/v1/lends'
21
+ require 'gemini/v1/symbols'
22
+ require 'gemini/v1/stats'
23
+ require 'gemini/v1/account_info'
24
+ require 'gemini/v1/deposit'
25
+ require 'gemini/v1/orders'
26
+ require 'gemini/v1/wallet'
27
+ require 'gemini/v1/positions'
28
+ require 'gemini/v1/historical_data'
29
+ require 'gemini/v1/margin_funding'
30
+
31
+ # API Version 2
32
+ require 'gemini/v2/stats'
33
+ require 'gemini/v2/ticker'
34
+ require 'gemini/v2/utils'
35
+ require 'gemini/v2/personal'
36
+ require 'gemini/v2/trading'
37
+ require 'gemini/v2/margin'
38
+
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemini-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Maros Hluska
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: eventmachine
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.0.9.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.0.9.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: faraday-detailed_logger
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.0.0
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.0.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.0
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.0.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: faye-websocket
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 0.10.3
80
+ type: :runtime
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: 0.10.3
87
+ - !ruby/object:Gem::Dependency
88
+ name: json
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: 1.8.3
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.3
97
+ type: :runtime
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.8.3
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.8.3
107
+ - !ruby/object:Gem::Dependency
108
+ name: faraday_middleware
109
+ requirement: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '0.10'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 0.10.0
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.10'
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 0.10.0
127
+ description: Simple Gemini API ruby wrapper
128
+ email:
129
+ - mhluska@gmail.com
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - lib/gemini-api-rb.rb
135
+ - lib/gemini.rb
136
+ - lib/gemini/api_versions.rb
137
+ - lib/gemini/authenticated_rest.rb
138
+ - lib/gemini/client.rb
139
+ - lib/gemini/configurable.rb
140
+ - lib/gemini/connection.rb
141
+ - lib/gemini/errors.rb
142
+ - lib/gemini/v1/account_info.rb
143
+ - lib/gemini/v1/deposit.rb
144
+ - lib/gemini/v1/funding_book.rb
145
+ - lib/gemini/v1/historical_data.rb
146
+ - lib/gemini/v1/lends.rb
147
+ - lib/gemini/v1/margin_funding.rb
148
+ - lib/gemini/v1/orderbook.rb
149
+ - lib/gemini/v1/orders.rb
150
+ - lib/gemini/v1/positions.rb
151
+ - lib/gemini/v1/stats.rb
152
+ - lib/gemini/v1/symbols.rb
153
+ - lib/gemini/v1/ticker.rb
154
+ - lib/gemini/v1/trades.rb
155
+ - lib/gemini/v1/wallet.rb
156
+ - lib/gemini/v2/margin.rb
157
+ - lib/gemini/v2/personal.rb
158
+ - lib/gemini/v2/stats.rb
159
+ - lib/gemini/v2/ticker.rb
160
+ - lib/gemini/v2/trading.rb
161
+ - lib/gemini/v2/utils.rb
162
+ - lib/gemini/version.rb
163
+ - lib/gemini/websocket_connection.rb
164
+ homepage: http://mhluska.com/
165
+ licenses:
166
+ - MIT
167
+ metadata: {}
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 2.6.12
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Gemini API Wrapper
188
+ test_files: []