orderbook 1.0.0 → 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/.gitignore +0 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +49 -0
- data/lib/orderbook/book_analysis.rb +25 -15
- data/lib/orderbook/book_methods.rb +34 -38
- data/lib/orderbook/version.rb +1 -1
- data/lib/orderbook.rb +16 -4
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0aa666b1b552ce4631f31e03394c802fde18ce5
|
4
|
+
data.tar.gz: 6431182407c7cdffa5b47f8db7dac9b995edd73c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c47317807dd3d9580218af90bd43b4f7d04ebc7d44ab543064f0ef0a2743ac89896ccce1a8f595635b66bd9d6d952e951e5db343798e79153ffb36ec0a0c8d73
|
7
|
+
data.tar.gz: b5417fbaa6ae780b2d8c6b917b29c3fab88c04d11f96b0e917b189d6b2a2fb785d623c44c694d688d805e825fa8ac699f7392a817af40d97b6a84826aeebc55a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/mikerodrigues/coinbase-exchange-ruby.git
|
3
|
+
revision: 051b256d2d0e414d7aec5bdb9a69ad33bfcf7e20
|
4
|
+
branch: orderbook
|
5
|
+
specs:
|
6
|
+
coinbase-exchange (0.1.2)
|
7
|
+
bigdecimal
|
8
|
+
em-http-request
|
9
|
+
faye-websocket
|
10
|
+
|
11
|
+
PATH
|
12
|
+
remote: .
|
13
|
+
specs:
|
14
|
+
orderbook (2.0.0)
|
15
|
+
|
16
|
+
GEM
|
17
|
+
remote: https://rubygems.org/
|
18
|
+
specs:
|
19
|
+
addressable (2.3.8)
|
20
|
+
bigdecimal (1.2.7)
|
21
|
+
cookiejar (0.3.2)
|
22
|
+
em-http-request (1.1.2)
|
23
|
+
addressable (>= 2.3.4)
|
24
|
+
cookiejar
|
25
|
+
em-socksify (>= 0.3)
|
26
|
+
eventmachine (>= 1.0.3)
|
27
|
+
http_parser.rb (>= 0.6.0)
|
28
|
+
em-socksify (0.3.0)
|
29
|
+
eventmachine (>= 1.0.0.beta.4)
|
30
|
+
eventmachine (1.0.7)
|
31
|
+
faye-websocket (0.10.0)
|
32
|
+
eventmachine (>= 0.12.0)
|
33
|
+
websocket-driver (>= 0.5.1)
|
34
|
+
http_parser.rb (0.6.0)
|
35
|
+
json (1.8.3)
|
36
|
+
rake (10.4.2)
|
37
|
+
websocket-driver (0.6.2)
|
38
|
+
websocket-extensions (>= 0.1.0)
|
39
|
+
websocket-extensions (0.1.2)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
bundler (~> 1.7)
|
46
|
+
coinbase-exchange!
|
47
|
+
json
|
48
|
+
orderbook!
|
49
|
+
rake (~> 10.0)
|
@@ -8,40 +8,50 @@ class Orderbook
|
|
8
8
|
@asks.count
|
9
9
|
end
|
10
10
|
|
11
|
+
def count
|
12
|
+
{ bid: bid_count, ask: ask_count }
|
13
|
+
end
|
14
|
+
|
11
15
|
def bid_volume
|
12
|
-
@bids.map {|x|
|
16
|
+
@bids.map {|x| x.fetch(:size)}.inject(:+)
|
13
17
|
end
|
14
18
|
|
15
19
|
def ask_volume
|
16
|
-
@asks.map {|x|
|
20
|
+
@asks.map {|x| x.fetch(:size)}.inject(:+)
|
21
|
+
end
|
22
|
+
|
23
|
+
def volume
|
24
|
+
{ bid: bid_volume, ask: ask_volume }
|
17
25
|
end
|
18
26
|
|
19
27
|
def average_bid
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
avg_bid = array.inject(:+) / array.count
|
24
|
-
avg_bid
|
28
|
+
bids = @bids.map {|x| x.fetch(:price)}
|
29
|
+
bids.inject(:+) / bids.count
|
25
30
|
end
|
26
31
|
|
27
32
|
def average_ask
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
asks = @asks.map {|x| x.fetch(:price)}
|
34
|
+
asks.inject(:+) / asks.count
|
35
|
+
end
|
36
|
+
|
37
|
+
def average
|
38
|
+
{ bid: average_bid, ask: average_ask }
|
33
39
|
end
|
34
40
|
|
35
41
|
def best_bid
|
36
|
-
|
42
|
+
@bids.sort_by {|x| x.fetch(:price)}.last
|
37
43
|
end
|
38
44
|
|
39
45
|
def best_ask
|
40
|
-
|
46
|
+
@asks.sort_by {|x| x.fetch(:price)}.first
|
47
|
+
end
|
48
|
+
|
49
|
+
def best
|
50
|
+
{ bid: best_bid, ask: best_ask }
|
41
51
|
end
|
42
52
|
|
43
53
|
def spread
|
44
|
-
best_ask - best_bid
|
54
|
+
best_ask.fetch(:price) - best_bid.fetch(:price)
|
45
55
|
end
|
46
56
|
|
47
57
|
def summarize
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require 'bigdecimal'
|
2
|
-
|
1
|
+
require 'bigdecimal'
|
3
2
|
class Orderbook
|
4
3
|
# This class provides methods to apply updates to the state of the orderbook
|
5
4
|
# as they come in as individual messages.
|
6
5
|
#
|
7
6
|
module BookMethods
|
7
|
+
BIGDECIMAL_KEYS = ['size', 'old_size', 'new_size', 'remaining_size', 'price', 'funds', 'old_funds', 'new_funds']
|
8
8
|
|
9
9
|
# Applies a message to an Orderbook object by making relevant changes to
|
10
10
|
# @bids, @asks, and @last_sequence.
|
@@ -12,6 +12,11 @@ class Orderbook
|
|
12
12
|
def apply(msg)
|
13
13
|
unless msg.fetch('sequence') <= @first_sequence
|
14
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
|
15
20
|
__send__(msg.fetch('type'), msg)
|
16
21
|
end
|
17
22
|
end
|
@@ -19,72 +24,63 @@ class Orderbook
|
|
19
24
|
private
|
20
25
|
|
21
26
|
def open(msg)
|
22
|
-
order =
|
23
|
-
case msg.fetch(
|
24
|
-
when
|
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'
|
25
30
|
@bids << order
|
26
|
-
when
|
31
|
+
when 'sell'
|
27
32
|
@asks << order
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
36
|
def match(msg)
|
32
|
-
|
33
|
-
|
34
|
-
when "sell"
|
37
|
+
case msg.fetch('side')
|
38
|
+
when 'sell'
|
35
39
|
@asks.map do |ask|
|
36
|
-
if ask.
|
37
|
-
|
38
|
-
new_size = old_size - match_size
|
39
|
-
ask[1] = new_size.to_s('F')
|
40
|
+
if ask.fetch(:order_id) == msg.fetch('maker_order_id')
|
41
|
+
ask[:size] = ask[:size] - msg.fetch('size')
|
40
42
|
end
|
41
43
|
end
|
42
44
|
@bids.map do |bid|
|
43
|
-
if bid.
|
44
|
-
|
45
|
-
new_size = old_size - match_size
|
46
|
-
bid[1] = new_size.to_s('F')
|
45
|
+
if bid.fetch(:order_id) == msg.fetch('taker_order_id')
|
46
|
+
bid[:size] = bid[:size] - msg.fetch('size')
|
47
47
|
end
|
48
48
|
end
|
49
|
-
when
|
49
|
+
when 'buy'
|
50
50
|
@bids.map do |bid|
|
51
|
-
if bid.
|
52
|
-
|
53
|
-
new_size = old_size - match_size
|
54
|
-
bid[1] = new_size.to_s('F')
|
51
|
+
if bid.fetch(:order_id) == msg.fetch('maker_order_id')
|
52
|
+
bid[:size] = bid[:size] - msg.fetch('size')
|
55
53
|
end
|
56
54
|
end
|
57
55
|
@asks.map do |ask|
|
58
|
-
if ask.
|
59
|
-
|
60
|
-
new_size = old_size - match_size
|
61
|
-
ask[1] = new_size.to_s('F')
|
56
|
+
if ask.fetch(:order_id) == msg.fetch('taker_order_id')
|
57
|
+
ask[:size] = ask[:size] - msg.fetch('size')
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
65
61
|
end
|
66
62
|
|
67
63
|
def done(msg)
|
68
|
-
case msg.fetch(
|
69
|
-
when
|
70
|
-
@asks.reject! {|a| a.
|
71
|
-
when
|
72
|
-
@bids.reject! {|
|
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']}
|
73
69
|
end
|
74
70
|
end
|
75
71
|
|
76
72
|
def change(msg)
|
77
|
-
case msg.fetch(
|
78
|
-
when
|
73
|
+
case msg.fetch('side')
|
74
|
+
when 'sell'
|
79
75
|
@asks.map do |a|
|
80
|
-
if a.
|
81
|
-
a[
|
76
|
+
if a.fetch(:order_id) == msg.fetch('order_id')
|
77
|
+
a[:size] = msg.fetch('new_size')
|
82
78
|
end
|
83
79
|
end
|
84
|
-
when
|
80
|
+
when 'buy'
|
85
81
|
@bids.map do |b|
|
86
|
-
if b.
|
87
|
-
b[
|
82
|
+
if b.fetch(:order_id) == msg.fetch('order_id')
|
83
|
+
b[:size] = msg.fetch('new_size')
|
88
84
|
end
|
89
85
|
end
|
90
86
|
end
|
data/lib/orderbook/version.rb
CHANGED
data/lib/orderbook.rb
CHANGED
@@ -55,8 +55,8 @@ class Orderbook
|
|
55
55
|
# If a +block+ is given it is passed each message as it is received.
|
56
56
|
#
|
57
57
|
def initialize(live = true, &block)
|
58
|
-
@bids = [
|
59
|
-
@asks = [
|
58
|
+
@bids = [{price: nil, size: nil, order_id: nil}]
|
59
|
+
@asks = [{price: nil, size: nil, order_id: nil}]
|
60
60
|
@first_sequence = 0
|
61
61
|
@last_sequence = 0
|
62
62
|
@websocket = Coinbase::Exchange::Websocket.new(keepalive: true)
|
@@ -84,8 +84,20 @@ class Orderbook
|
|
84
84
|
|
85
85
|
def fetch_current_orderbook
|
86
86
|
@client.orderbook(level: 3) do |resp|
|
87
|
-
@bids = resp['bids']
|
88
|
-
|
87
|
+
@bids = resp['bids'].map do |price, size, order_id|
|
88
|
+
{
|
89
|
+
price: BigDecimal.new(price),
|
90
|
+
size: BigDecimal.new(size),
|
91
|
+
order_id: order_id
|
92
|
+
}
|
93
|
+
end
|
94
|
+
@asks = resp['asks'].map do |price, size, order_id|
|
95
|
+
{
|
96
|
+
price: BigDecimal.new(price),
|
97
|
+
size: BigDecimal.new(size),
|
98
|
+
order_id: order_id
|
99
|
+
}
|
100
|
+
end
|
89
101
|
@first_sequence = resp['sequence']
|
90
102
|
end
|
91
103
|
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:
|
4
|
+
version: 2.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-
|
11
|
+
date: 2015-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -50,6 +50,7 @@ extra_rdoc_files: []
|
|
50
50
|
files:
|
51
51
|
- ".gitignore"
|
52
52
|
- Gemfile
|
53
|
+
- Gemfile.lock
|
53
54
|
- LICENSE.txt
|
54
55
|
- README.md
|
55
56
|
- Rakefile
|
@@ -79,9 +80,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
80
|
version: '0'
|
80
81
|
requirements: []
|
81
82
|
rubyforge_project:
|
82
|
-
rubygems_version: 2.
|
83
|
+
rubygems_version: 2.4.6
|
83
84
|
signing_key:
|
84
85
|
specification_version: 4
|
85
86
|
summary: Maintains an real-time copy of the Coinbase Exchange order book.
|
86
87
|
test_files: []
|
87
|
-
has_rdoc:
|