orderbook 2.0.1 → 2.0.2

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
  SHA1:
3
- metadata.gz: 0d5cc78ce1824c5c00fce053a371b7f43e6ab9e9
4
- data.tar.gz: 780c397a8788c3bdbce8bc2e6c1ce4f2383562b0
3
+ metadata.gz: 82bf3042bbd14421f52d056b6bd7c07ded3a4745
4
+ data.tar.gz: 04b949de80478883f3400d7d90ba99ca61160e15
5
5
  SHA512:
6
- metadata.gz: 3c1cf4ae709490839a03b509980b3478b86ef1c0a4019da68e9bff37eee53d2dcc540ea26bb4c360bf1e21f15bfc1ba7e3a36871d0f92c38c7d52223d0ea0336
7
- data.tar.gz: ac832ab9024886040366b1343961d777c4b428e085118935d4ed0a9ac956a6e0139025c651c333aa008382957631d276fb2fa1c661208945197b8d0078acdf8d
6
+ metadata.gz: 701b49e1646e44a5e08c7e3f09ea480f90bd7c47d629aa1be1c1c31f11de0137c893619c177e9491e2105b0e7c1668507090d2f836dc268b62825501a02fa784
7
+ data.tar.gz: df12ea165dffa99585bc74eb50d600c76065f4b58a7fcfb617fd873b6923aab0340000a85d7eed79e0757b53afc00991852e7002ec8dfe29a47ad0da1f492ad5
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in orderbook.gemspec
4
4
  gemspec
5
- gem 'coinbase-exchange', :git => 'https://github.com/mikerodrigues/coinbase-exchange-ruby.git', :branch => 'orderbook'
5
+ gem 'coinbase-exchange', git: 'https://github.com/mikerodrigues/coinbase-exchange-ruby.git', branch: 'orderbook'
6
6
  gem 'json'
data/Rakefile CHANGED
@@ -27,7 +27,7 @@ task :console do
27
27
  PRY.start
28
28
  end
29
29
 
30
- task :default => ['build', 'install']
30
+ task default: %w(build install)
31
31
 
32
32
  Rake::TestTask.new do |t|
33
33
  t.libs << 'test'
@@ -56,8 +56,8 @@ class Orderbook
56
56
  # If a +block+ is given it is passed each message as it is received.
57
57
  #
58
58
  def initialize(live = true, &block)
59
- @bids = [{price: nil, size: nil, order_id: nil}]
60
- @asks = [{price: nil, size: nil, order_id: nil}]
59
+ @bids = [{ price: nil, size: nil, order_id: nil }]
60
+ @asks = [{ price: nil, size: nil, order_id: nil }]
61
61
  @first_sequence = 0
62
62
  @last_sequence = 0
63
63
  @websocket = Coinbase::Exchange::Websocket.new(keepalive: true)
@@ -84,21 +84,15 @@ class Orderbook
84
84
  end
85
85
 
86
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
87
93
  @client.orderbook(level: 3) do |resp|
88
- @bids = resp['bids'].map do |price, size, order_id|
89
- {
90
- price: BigDecimal.new(price),
91
- size: BigDecimal.new(size),
92
- order_id: order_id
93
- }
94
- end
95
- @asks = resp['asks'].map do |price, size, order_id|
96
- {
97
- price: BigDecimal.new(price),
98
- size: BigDecimal.new(size),
99
- order_id: order_id
100
- }
101
- end
94
+ @bids = resp['bids'].map(&order_to_hash)
95
+ @asks = resp['asks'].map(&order_to_hash)
102
96
  @first_sequence = resp['sequence']
103
97
  end
104
98
  end
@@ -1,4 +1,7 @@
1
1
  class Orderbook
2
+ # Simple collection of commands to get info about the orderbook. Add our own
3
+ # methods for calculating whatever it is you feel like calculating.
4
+ #
2
5
  module BookAnalysis
3
6
  def bid_count
4
7
  @bids.count
@@ -13,11 +16,11 @@ class Orderbook
13
16
  end
14
17
 
15
18
  def bid_volume
16
- @bids.map {|x| x.fetch(:size)}.inject(:+)
19
+ @bids.map { |x| x.fetch(:size) }.inject(:+)
17
20
  end
18
21
 
19
22
  def ask_volume
20
- @asks.map {|x| x.fetch(:size)}.inject(:+)
23
+ @asks.map { |x| x.fetch(:size) }.inject(:+)
21
24
  end
22
25
 
23
26
  def volume
@@ -25,12 +28,12 @@ class Orderbook
25
28
  end
26
29
 
27
30
  def average_bid
28
- bids = @bids.map {|x| x.fetch(:price)}
31
+ bids = @bids.map { |x| x.fetch(:price) }
29
32
  bids.inject(:+) / bids.count
30
33
  end
31
34
 
32
35
  def average_ask
33
- asks = @asks.map {|x| x.fetch(:price)}
36
+ asks = @asks.map { |x| x.fetch(:price) }
34
37
  asks.inject(:+) / asks.count
35
38
  end
36
39
 
@@ -39,11 +42,11 @@ class Orderbook
39
42
  end
40
43
 
41
44
  def best_bid
42
- @bids.sort_by {|x| x.fetch(:price)}.last
45
+ @bids.sort_by { |x| x.fetch(:price) }.last
43
46
  end
44
47
 
45
48
  def best_ask
46
- @asks.sort_by {|x| x.fetch(:price)}.first
49
+ @asks.sort_by { |x| x.fetch(:price) }.first
47
50
  end
48
51
 
49
52
  def best
@@ -57,11 +60,6 @@ class Orderbook
57
60
  def summarize
58
61
  print "# of asks: #{ask_count}\n# of bids: #{bid_count}\nAsk volume: #{ask_volume.to_s('F')}\nBid volume: #{bid_volume.to_s('F')}\n"
59
62
  $stdout.flush
60
- # puts "Avg. ask: #{average_ask}"
61
- # puts "Avg. bid: #{average_bid}"
62
- # puts "Best ask: #{best_bid}"
63
- # puts "Best bid: #{best_ask}"
64
- # puts "Spread: #{spread}"
65
63
  end
66
64
  end
67
65
  end
@@ -1,94 +1,68 @@
1
- require 'bigdecimal'
1
+ require 'bigdecimal'
2
2
  class Orderbook
3
3
  # This class provides methods to apply updates to the state of the orderbook
4
- # as they come in as individual messages.
4
+ # as they are received by the websocket.
5
5
  #
6
6
  module BookMethods
7
- BIGDECIMAL_KEYS = ['size', 'old_size', 'new_size', 'remaining_size', 'price', 'funds', 'old_funds', 'new_funds']
7
+ BIGDECIMAL_KEYS = %w(size old_size new_size remaining_size price)
8
8
 
9
9
  # Applies a message to an Orderbook object by making relevant changes to
10
10
  # @bids, @asks, and @last_sequence.
11
11
  #
12
12
  def apply(msg)
13
- unless msg.fetch('sequence') <= @first_sequence
14
- @last_sequence = msg.fetch('sequence')
15
- BIGDECIMAL_KEYS.each do |key|
16
- if msg.fetch(key, false)
17
- msg[key] = BigDecimal.new(msg.fetch(key))
18
- end
19
- end
20
- __send__(msg.fetch('type'), msg)
13
+ return if msg.fetch('sequence') <= @first_sequence
14
+ @last_sequence = msg.fetch('sequence')
15
+ BIGDECIMAL_KEYS.each do |key|
16
+ msg[key] = BigDecimal.new(msg.fetch(key)) if msg.fetch(key, false)
21
17
  end
18
+
19
+ __send__(msg.fetch('type'), msg)
22
20
  end
23
21
 
24
22
  private
25
23
 
26
24
  def open(msg)
27
- order = { price: msg.fetch('price'), size: msg.fetch('remaining_size'), order_id: msg.fetch('order_id') }
28
- case msg.fetch('side')
29
- when 'buy'
30
- @bids << order
31
- when 'sell'
32
- @asks << order
33
- end
25
+ order = {
26
+ price: msg.fetch('price'),
27
+ size: msg.fetch('remaining_size'),
28
+ order_id: msg.fetch('order_id')
29
+ }
30
+
31
+ @bids << order if msg.fetch('side') == 'buy'
32
+ @asks << order if msg.fetch('side') == 'sell'
34
33
  end
35
34
 
36
35
  def match(msg)
37
- case msg.fetch('side')
38
- when 'sell'
39
- @asks.map do |ask|
40
- if ask.fetch(:order_id) == msg.fetch('maker_order_id')
41
- ask[:size] = ask[:size] - msg.fetch('size')
42
- end
43
- end
44
- @bids.map do |bid|
45
- if bid.fetch(:order_id) == msg.fetch('taker_order_id')
46
- bid[:size] = bid[:size] - msg.fetch('size')
47
- end
48
- end
49
- when 'buy'
50
- @bids.map do |bid|
51
- if bid.fetch(:order_id) == msg.fetch('maker_order_id')
52
- bid[:size] = bid[:size] - msg.fetch('size')
53
- end
54
- end
55
- @asks.map do |ask|
56
- if ask.fetch(:order_id) == msg.fetch('taker_order_id')
57
- ask[:size] = ask[:size] - msg.fetch('size')
58
- end
36
+ decrement_match = lambda do |o|
37
+ if o.fetch(:order_id) == msg.fetch('maker_order_id')
38
+ o[:size] = o.fetch(:size) - msg.fetch('size')
59
39
  end
60
40
  end
41
+
42
+ @asks.map(&decrement_match) if msg.fetch('side') == 'sell'
43
+ @bids.map(&decrement_match) if msg.fetch('side') == 'buy'
61
44
  end
62
45
 
63
46
  def done(msg)
64
- case msg.fetch('side')
65
- when 'sell'
66
- @asks.reject! {|a| a.fetch(:order_id) == msg['order_id']}
67
- when 'buy'
68
- @bids.reject! {|b| b.fetch(:order_id) == msg['order_id']}
69
- end
47
+ matching_order = ->(o) { o.fetch(:order_id) == msg.fetch('order_id') }
48
+
49
+ @asks.reject!(&matching_order) if msg.fetch('side') == 'sell'
50
+ @bids.reject!(&matching_order) if msg.fetch('side') == 'buy'
70
51
  end
71
52
 
72
53
  def change(msg)
73
- case msg.fetch('side')
74
- when 'sell'
75
- @asks.map do |a|
76
- if a.fetch(:order_id) == msg.fetch('order_id')
77
- a[:size] = msg.fetch('new_size')
78
- end
79
- end
80
- when 'buy'
81
- @bids.map do |b|
82
- if b.fetch(:order_id) == msg.fetch('order_id')
83
- b[:size] = msg.fetch('new_size')
84
- end
54
+ change_order = lambda do |o|
55
+ if o.fetch(:order_id) == msg.fetch('order_id')
56
+ o[:size] = msg.fetch('new_size')
85
57
  end
86
58
  end
59
+
60
+ @asks.map(&change_order) if msg.fetch('side') == 'sell'
61
+ @bids.map(&change_order) if msg.fetch('side') == 'buy'
87
62
  end
88
63
 
89
- def received(msg)
64
+ def received(_)
90
65
  # The book doesn't change for this message type.
91
66
  end
92
-
93
67
  end
94
68
  end
@@ -1,7 +1,4 @@
1
1
  class Orderbook
2
- class RealTimeBook < Orderbook
3
- # For backwards compatability
4
-
5
- end
2
+ # For backwards compatability
3
+ class RealTimeBook < Orderbook; end
6
4
  end
7
-
@@ -1,3 +1,5 @@
1
+ # Orderbook version number. I try to keep it semantic.
2
+ #
1
3
  class Orderbook
2
- VERSION = "2.0.1"
4
+ VERSION = '2.0.2'
3
5
  end
@@ -4,22 +4,22 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'orderbook/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "orderbook"
7
+ spec.name = 'orderbook'
8
8
  spec.version = Orderbook::VERSION
9
- spec.authors = ["Michael Rodrigues"]
10
- spec.email = ["mikebrodrigues@gmail.com"]
11
- spec.summary = %q{Maintains an real-time copy of the Coinbase Exchange order book.}
12
- spec.description = %q{Orderbook uses the Coinbase Exchange Websocket stream
9
+ spec.authors = ['Michael Rodrigues']
10
+ spec.email = ['mikebrodrigues@gmail.com']
11
+ spec.summary = %q(Maintains an real-time copy of the Coinbase Exchange order book.)
12
+ spec.description = %q(Orderbook uses the Coinbase Exchange Websocket stream
13
13
  to maintain a real-time copy of the order book. Use it
14
- in your BTC trading bot.}
15
- spec.homepage = "https://github.com/mikerodrigues/orderbook"
16
- spec.license = "MIT"
14
+ in your BTC trading bot.)
15
+ spec.homepage = 'https://github.com/mikerodrigues/orderbook'
16
+ spec.license = 'MIT'
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
- spec.require_paths = ["lib"]
21
+ spec.require_paths = ['lib']
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.7"
24
- spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency 'bundler', '~> 1.7'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
25
  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.1
4
+ version: 2.0.2
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-03 00:00:00.000000000 Z
11
+ date: 2015-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler