orderbook 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 82bf3042bbd14421f52d056b6bd7c07ded3a4745
4
- data.tar.gz: 04b949de80478883f3400d7d90ba99ca61160e15
3
+ metadata.gz: 20a70a3b134b39779181f6f4137a5200f003593e
4
+ data.tar.gz: 269d90ef37d27f7925e10f241326cf65c41ad3e1
5
5
  SHA512:
6
- metadata.gz: 701b49e1646e44a5e08c7e3f09ea480f90bd7c47d629aa1be1c1c31f11de0137c893619c177e9491e2105b0e7c1668507090d2f836dc268b62825501a02fa784
7
- data.tar.gz: df12ea165dffa99585bc74eb50d600c76065f4b58a7fcfb617fd873b6923aab0340000a85d7eed79e0757b53afc00991852e7002ec8dfe29a47ad0da1f492ad5
6
+ metadata.gz: 255c3b44bb6cb4bee6bd90975bac52f51401d79d0e4374250545e438f2348223ca01e78a348f23bffa1e444d1d0aa479b024872fcdd40b3ec3ff17e415d5e426
7
+ data.tar.gz: a1581ff672f3e345c5745171754a399f6b552203fa73828976468445d36883a79f72a05d2eaddbe67176c1fc57dd33ff21dea919ec16ab71f649c9944c2f1444
data/Gemfile CHANGED
@@ -4,3 +4,4 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
  gem 'coinbase-exchange', git: 'https://github.com/mikerodrigues/coinbase-exchange-ruby.git', branch: 'orderbook'
6
6
  gem 'json'
7
+ gem 'eventmachine'
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: https://github.com/mikerodrigues/coinbase-exchange-ruby.git
3
- revision: 051b256d2d0e414d7aec5bdb9a69ad33bfcf7e20
3
+ revision: 527d6b4e9d5e6bd2d2deab7ac5f16f58674194bc
4
4
  branch: orderbook
5
5
  specs:
6
6
  coinbase-exchange (0.1.2)
@@ -11,7 +11,7 @@ GIT
11
11
  PATH
12
12
  remote: .
13
13
  specs:
14
- orderbook (2.0.1)
14
+ orderbook (3.0.0)
15
15
 
16
16
  GEM
17
17
  remote: https://rubygems.org/
@@ -27,7 +27,7 @@ GEM
27
27
  http_parser.rb (>= 0.6.0)
28
28
  em-socksify (0.3.0)
29
29
  eventmachine (>= 1.0.0.beta.4)
30
- eventmachine (1.0.7)
30
+ eventmachine (1.0.8)
31
31
  faye-websocket (0.10.0)
32
32
  eventmachine (>= 0.12.0)
33
33
  websocket-driver (>= 0.5.1)
@@ -44,6 +44,7 @@ PLATFORMS
44
44
  DEPENDENCIES
45
45
  bundler (~> 1.7)
46
46
  coinbase-exchange!
47
+ eventmachine
47
48
  json
48
49
  orderbook!
49
50
  rake (~> 10.0)
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
- # Orderbook
1
+ # Orderbook 3.0.0
2
+ <a href="https://codeclimate.com/github/mikerodrigues/orderbook"><img src="https://codeclimate.com/github/mikerodrigues/orderbook/badges/gpa.svg" /></a>
3
+
4
+ Version 3.0.0 has a slightly different interface and properly queues messages
5
+ for an accurate Orderbook.
2
6
 
3
7
  A gem for creating a realtime order book for the Coinbase Exchange.
4
8
 
@@ -43,7 +47,7 @@ ob = Orderbook.new(false)
43
47
 
44
48
  # When you want it to go live:
45
49
 
46
- ob.live!
50
+ ob.start!
47
51
  ```
48
52
 
49
53
  * Create a live Orderbook with a callback to fire on each message:
@@ -53,18 +57,13 @@ ob = Orderbook.new do |message|
53
57
  end
54
58
  ```
55
59
 
56
- * Create or reset the callback:
60
+ * Create or reset the message callback:
57
61
  ```ruby
58
- ob.callback = lambda do |message|
59
- puts message.fetch 'callback'
62
+ ob.on_message do |message|
63
+ puts message.fetch 'sequence'
60
64
  end
61
65
  ```
62
66
 
63
- * The old class name is still supported and is equivalent to an Orderbook:
64
- ```ruby
65
- rtb = Orderbook::RealTimeBook.new
66
- ```
67
-
68
67
  * List current bids:
69
68
  ```ruby
70
69
  ob.bids
@@ -77,7 +76,7 @@ ob.asks
77
76
 
78
77
  * Show sequence number for initial level 3 snapshot:
79
78
  ```ruby
80
- ob.first_sequence
79
+ ob.snapshot_sequence
81
80
  ```
82
81
 
83
82
  * Show sequence number for the last message received
@@ -11,7 +11,9 @@ class Orderbook
11
11
  include BookMethods
12
12
  include BookAnalysis
13
13
 
14
- PING_INTERVAL = 15 # seconds in between pinging the connection.
14
+ # seconds in between pinging the connection.
15
+ #
16
+ PING_INTERVAL = 15
15
17
 
16
18
  # Array of bids
17
19
  #
@@ -23,7 +25,7 @@ class Orderbook
23
25
 
24
26
  # Sequence number from the initial level 3 snapshot
25
27
  #
26
- attr_reader :first_sequence
28
+ attr_reader :snapshot_sequence
27
29
 
28
30
  # Sequence number of most recently received message
29
31
  #
@@ -33,71 +35,107 @@ class Orderbook
33
35
  #
34
36
  attr_reader :websocket
35
37
 
36
- # Coinbase::Exchange::AsyncClient object
38
+ # Coinbase::Exchange::Client object
37
39
  #
38
40
  attr_reader :client
39
41
 
40
- # Thread running the EM loop
42
+ # Thread running the EM loop for the websocket
43
+ #
44
+ attr_reader :em_thread
45
+
46
+ # Thread running the processing loop
41
47
  #
42
- attr_reader :thread
48
+ attr_reader :processing_thread
43
49
 
44
- # Last time a pong was received after a ping
50
+ # DateTime of last successful pong
45
51
  #
46
52
  attr_reader :last_pong
47
53
 
48
- # Callback to pass each received message to
54
+ # Message queue for incoming messages.
49
55
  #
50
- attr_accessor :callback
56
+ attr_reader :queue
51
57
 
52
58
  # Creates a new live copy of the orderbook.
53
59
  #
54
- # If +live+ is set to false, the orderbook will not start automatically.
60
+ # If +start+ is set to false, the orderbook will not start automatically.
55
61
  #
56
62
  # If a +block+ is given it is passed each message as it is received.
57
63
  #
58
- def initialize(live = true, &block)
59
- @bids = [{ price: nil, size: nil, order_id: nil }]
60
- @asks = [{ price: nil, size: nil, order_id: nil }]
61
- @first_sequence = 0
64
+ def initialize(start = true, &block)
65
+ @bids = []
66
+ @asks = []
67
+ @snapshot_sequence = 0
62
68
  @last_sequence = 0
69
+ @queue = Queue.new
63
70
  @websocket = Coinbase::Exchange::Websocket.new(keepalive: true)
64
- @client = Coinbase::Exchange::AsyncClient.new
65
- @callback = block if block_given?
66
- live && live!
71
+ @client = Coinbase::Exchange::Client.new
72
+ @on_message = block if block_given?
73
+ start && start!
67
74
  end
68
75
 
69
76
  # Used to start the thread that listens to updates on the websocket and
70
77
  # applies them to the current orderbook to create a live book.
71
78
  #
72
- def live!
73
- setup_websocket
74
- start_thread
79
+ def start!
80
+ start_em_thread
81
+
82
+ # Wait to make sure the snapshot sequence ID is higher than the sequence of
83
+ # the first message in the queue.
84
+ #
85
+ sleep 0.3
86
+ apply_orderbook_snapshot
87
+ start_processing_thread
88
+ end
89
+
90
+ # Stops the processing thread, EM thread, and the websocket.
91
+ #
92
+ def stop!
93
+ @processing_thread.kill
94
+ @em_thread.kill
95
+ @websocket.stop!
96
+ end
97
+
98
+ # Start and stop the Orderbook. Used to reset Orderbook state with a fresh
99
+ # snapshot.
100
+ #
101
+ def reset!
102
+ stop!
103
+ start!
104
+ end
105
+
106
+ def on_message(&block)
107
+ @on_message = block
75
108
  end
76
109
 
77
110
  private
78
111
 
79
- def setup_websocket
80
- @websocket.message do |message|
81
- apply(message)
82
- @callback && @callback.call(message)
83
- end
112
+ # Converts an order array from the API into a hash.
113
+ #
114
+ def order_to_hash(price, size, order_id)
115
+ { price: BigDecimal.new(price),
116
+ size: BigDecimal.new(size),
117
+ order_id: order_id
118
+ }
84
119
  end
85
120
 
86
- def fetch_current_orderbook
87
- order_to_hash = lambda do |price, size, order_id|
88
- { price: BigDecimal.new(price),
89
- size: BigDecimal.new(size),
90
- order_id: order_id
91
- }
92
- end
121
+ # Fetch orderbook snapshot from API and convert order arrays to hashes.
122
+ #
123
+ def apply_orderbook_snapshot
93
124
  @client.orderbook(level: 3) do |resp|
94
- @bids = resp['bids'].map(&order_to_hash)
95
- @asks = resp['asks'].map(&order_to_hash)
96
- @first_sequence = resp['sequence']
125
+ @bids = resp['bids'].map { |b| order_to_hash(*b) }
126
+ @asks = resp['asks'].map { |a| order_to_hash(*a) }
127
+ @snapshot_sequence = resp['sequence']
128
+ @last_sequence = resp['sequence']
129
+ end
130
+ end
131
+
132
+ def setup_websocket_callback
133
+ @websocket.message do |message|
134
+ @queue.push(message)
97
135
  end
98
136
  end
99
137
 
100
- def ping
138
+ def setup_ping_timer
101
139
  EM.add_periodic_timer(PING_INTERVAL) do
102
140
  @websocket.ping do
103
141
  @last_pong = Time.now
@@ -105,19 +143,29 @@ class Orderbook
105
143
  end
106
144
  end
107
145
 
108
- def handle_errors
146
+ def setup_error_handler
109
147
  EM.error_handler do |e|
110
148
  print "Websocket Error: #{e.message} - #{e.backtrace.join("\n")}"
111
149
  end
112
150
  end
113
151
 
114
- def start_thread
115
- @thread = Thread.new do
152
+ def start_em_thread
153
+ @em_thread = Thread.new do
154
+ setup_websocket_callback
116
155
  EM.run do
117
- fetch_current_orderbook
118
156
  @websocket.start!
119
- ping
120
- handle_errors
157
+ setup_ping_timer
158
+ setup_error_handler
159
+ end
160
+ end
161
+ end
162
+
163
+ def start_processing_thread
164
+ @processing_thread = Thread.new do
165
+ loop do
166
+ message = @queue.shift
167
+ apply(message)
168
+ @on_message.call(message) unless @on_message.nil?
121
169
  end
122
170
  end
123
171
  end
@@ -10,7 +10,11 @@ class Orderbook
10
10
  # @bids, @asks, and @last_sequence.
11
11
  #
12
12
  def apply(msg)
13
- return if msg.fetch('sequence') <= @first_sequence
13
+ return if msg.fetch('sequence') != @last_sequence + 1
14
+ #if msg.fetch('sequence') != @last_sequence + 1
15
+ # puts "Expected #{@last_sequence + 1}, got #{msg.fetch('sequence')}"
16
+ # @websocket.stop!
17
+ #end
14
18
  @last_sequence = msg.fetch('sequence')
15
19
  BIGDECIMAL_KEYS.each do |key|
16
20
  msg[key] = BigDecimal.new(msg.fetch(key)) if msg.fetch(key, false)
@@ -1,5 +1,5 @@
1
1
  # Orderbook version number. I try to keep it semantic.
2
2
  #
3
3
  class Orderbook
4
- VERSION = '2.0.2'
4
+ VERSION = '3.0.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orderbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Rodrigues
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-04 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -57,7 +57,6 @@ files:
57
57
  - lib/orderbook.rb
58
58
  - lib/orderbook/book_analysis.rb
59
59
  - lib/orderbook/book_methods.rb
60
- - lib/orderbook/real_time_book.rb
61
60
  - lib/orderbook/version.rb
62
61
  - orderbook.gemspec
63
62
  homepage: https://github.com/mikerodrigues/orderbook
@@ -1,4 +0,0 @@
1
- class Orderbook
2
- # For backwards compatability
3
- class RealTimeBook < Orderbook; end
4
- end