gekko 0.3.1 → 0.5.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/lib/gekko/book.rb +51 -6
- data/lib/gekko/book_side.rb +12 -1
- data/lib/gekko/order.rb +30 -0
- data/lib/gekko/tape.rb +48 -42
- data/lib/gekko/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e807cf299a74840caedd3ab554af8b30c797d51
|
4
|
+
data.tar.gz: bce631e42323b43fd1864033a8e8bd6f4c97ffea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce1211699c74fc7232ddfbbc83db30d71fa45445a78c2b54c6ba547cd62b6d18d8d93b11486642b4ed6e6dfc496e9ab8acb32f55c916c0ac139edc6a64e0b9df
|
7
|
+
data.tar.gz: 31f755d6134b1650909bfb8860a28ab1a89e4732ee529fb87fb88161909acca8c6a51569bd7dbeb580997f76c11d33c8091a792b81c54f31eb6ab7eca74ce161
|
data/lib/gekko/book.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'oj'
|
2
|
+
Oj.default_options = { mode: :compat }
|
3
|
+
|
1
4
|
require 'gekko/book_side'
|
2
5
|
require 'gekko/tape'
|
3
6
|
require 'gekko/errors'
|
@@ -12,12 +15,12 @@ module Gekko
|
|
12
15
|
attr_accessor :pair, :bids, :asks, :tape, :received, :base_precision
|
13
16
|
|
14
17
|
def initialize(pair, opts = {})
|
15
|
-
self.pair = pair
|
16
|
-
self.bids = BookSide.new(:bid)
|
17
|
-
self.asks = BookSide.new(:ask)
|
18
|
-
self.tape = Tape.new(opts[:logger])
|
18
|
+
self.pair = opts[:pair] || pair
|
19
|
+
self.bids = opts[:bids] || BookSide.new(:bid)
|
20
|
+
self.asks = opts[:asks] || BookSide.new(:ask)
|
21
|
+
self.tape = opts[:tape] || Tape.new({ logger: opts[:logger] })
|
19
22
|
self.base_precision = opts[:base_precision] || 8
|
20
|
-
self.received = {}
|
23
|
+
self.received = opts[:received] || {}
|
21
24
|
end
|
22
25
|
|
23
26
|
#
|
@@ -75,7 +78,6 @@ module Gekko
|
|
75
78
|
quote_size: quote_size,
|
76
79
|
maker_order_id: next_match.id.to_s,
|
77
80
|
taker_order_id: order.id.to_s,
|
78
|
-
time: Time.now.to_f,
|
79
81
|
tick: order.bid? ? :up : :down
|
80
82
|
}
|
81
83
|
|
@@ -187,6 +189,49 @@ module Gekko
|
|
187
189
|
}
|
188
190
|
end
|
189
191
|
|
192
|
+
#
|
193
|
+
# Dumps the book to a JSON string
|
194
|
+
#
|
195
|
+
# @return [String] The serialized order book
|
196
|
+
#
|
197
|
+
def dump
|
198
|
+
Oj.dump({
|
199
|
+
time: Time.now.to_f,
|
200
|
+
bids: bids.to_hash,
|
201
|
+
asks: asks.to_hash,
|
202
|
+
pair: pair,
|
203
|
+
tape: tape.to_hash,
|
204
|
+
received: received,
|
205
|
+
base_precision: base_precision
|
206
|
+
})
|
207
|
+
end
|
208
|
+
|
209
|
+
#
|
210
|
+
# Loads the book from a JSON string
|
211
|
+
#
|
212
|
+
# @param serialized [String] A serialized book
|
213
|
+
# @return [Gekko::Book] The deserialized book instance
|
214
|
+
#
|
215
|
+
def self.load(serialized)
|
216
|
+
hsh = symbolize_keys(Oj.load(serialized))
|
217
|
+
|
218
|
+
hsh[:tape] = Tape.new(symbolize_keys(hsh[:tape]))
|
219
|
+
hsh[:bids] = BookSide.new(:bid, orders: hsh[:bids].map { |o| symbolize_keys(o) })
|
220
|
+
hsh[:asks] = BookSide.new(:ask, orders: hsh[:asks].map { |o| symbolize_keys(o) })
|
221
|
+
|
222
|
+
Book.new(hsh[:pair], hsh)
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
# Symbolizes keys of a non-nested +Hash+
|
227
|
+
#
|
228
|
+
# @param hsh [Hash] The +Hash+ for which we want to symbolize the keys
|
229
|
+
# @return [Hash] A copy of the parameter with all first-level keys symbolized
|
230
|
+
#
|
231
|
+
def self.symbolize_keys(hsh)
|
232
|
+
hsh.inject({}) { |mem, obj| mem[obj[0].to_sym] = obj[1]; mem }
|
233
|
+
end
|
234
|
+
|
190
235
|
end
|
191
236
|
end
|
192
237
|
|
data/lib/gekko/book_side.rb
CHANGED
@@ -9,9 +9,20 @@ module Gekko
|
|
9
9
|
|
10
10
|
attr_accessor :side
|
11
11
|
|
12
|
-
def initialize(side)
|
12
|
+
def initialize(side, opts = {})
|
13
13
|
raise "Incorrect side <#{side}>" unless [:bid, :ask].include?(side)
|
14
14
|
@side = side
|
15
|
+
|
16
|
+
opts[:orders] && opts[:orders].each_with_index { |obj, idx| self[idx] = Order.load(obj) }
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Returns a +Hash+ representation of this +BookSide+ instance
|
21
|
+
#
|
22
|
+
# @return [Hash] The serializable representation
|
23
|
+
#
|
24
|
+
def to_hash
|
25
|
+
map(&:to_hash)
|
15
26
|
end
|
16
27
|
|
17
28
|
#
|
data/lib/gekko/order.rb
CHANGED
@@ -24,6 +24,36 @@ module Gekko
|
|
24
24
|
raise 'The order creation timestamp can''t be nil' if !@created_at
|
25
25
|
end
|
26
26
|
|
27
|
+
|
28
|
+
#
|
29
|
+
# Loads an +Order+ from a +Hash+. Only limit orders are supported as market
|
30
|
+
# orders should never need to get serialized
|
31
|
+
#
|
32
|
+
# @return [LimitOrder] The unserialized order
|
33
|
+
#
|
34
|
+
def self.load(hsh)
|
35
|
+
order = LimitOrder.new(hsh[:side], UUID.parse(hsh[:id]), hsh[:size], hsh[:price], hsh[:expiration])
|
36
|
+
order.created_at = hsh[:created_at]
|
37
|
+
order
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns a +Hash+ representation of this +Order+ instance
|
42
|
+
#
|
43
|
+
# @return [Hash] The serializable representation
|
44
|
+
#
|
45
|
+
def to_hash
|
46
|
+
{
|
47
|
+
id: @id,
|
48
|
+
side: @side,
|
49
|
+
size: @size,
|
50
|
+
price: @price,
|
51
|
+
remaining: @remaining,
|
52
|
+
expiration: @expiration,
|
53
|
+
created_at: @created_at
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
27
57
|
#
|
28
58
|
# Returns +true+ if this order can execute against +limit_order+
|
29
59
|
#
|
data/lib/gekko/tape.rb
CHANGED
@@ -5,23 +5,57 @@ module Gekko
|
|
5
5
|
#
|
6
6
|
class Tape < Array
|
7
7
|
|
8
|
+
# The number of seconds in 24h
|
9
|
+
SECONDS_IN_24H = 60 * 60 * 24
|
10
|
+
|
8
11
|
attr_accessor :logger, :last_trade_price
|
12
|
+
attr_reader :volume_24h, :high_24h, :low_24h
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@logger = opts[:logger]
|
16
|
+
|
17
|
+
@cursor = opts[:cursor] || 0
|
18
|
+
@cursor_24h = opts[:cursor_24h] || 0
|
19
|
+
@volume_24h = opts[:volume_24h] || 0
|
20
|
+
@quote_volume_24h = opts[:quote_volume_24h] || 0
|
21
|
+
|
22
|
+
@low_24h = opts[:low_24h]
|
23
|
+
@high_24h = opts[:high_24h]
|
24
|
+
@last_trade_price = opts[:last_trade_price]
|
9
25
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
26
|
+
opts[:events] && opts[:events].each_with_index { |obj, idx| self[idx] = obj }
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Returns this +Tape+ object as a +Hash+ for the purpose of serialization
|
31
|
+
#
|
32
|
+
# @return [Hash] The JSON-friendly +Hash+ representation
|
33
|
+
#
|
34
|
+
def to_hash
|
35
|
+
{
|
36
|
+
cursor: @cursor,
|
37
|
+
cursor_24h: @cursor_24h,
|
38
|
+
volume_24h: @volume_24h,
|
39
|
+
high_24h: @high_24h,
|
40
|
+
low_24h: @low_24h,
|
41
|
+
quote_volume_24h: @quote_volume_24h,
|
42
|
+
last_trade_price: @last_trade_price,
|
43
|
+
events: self
|
44
|
+
}
|
16
45
|
end
|
17
46
|
|
47
|
+
|
18
48
|
#
|
19
49
|
# Prints a message on the tape
|
20
50
|
#
|
21
51
|
# @param message [Hash] The message to record
|
22
52
|
#
|
23
53
|
def <<(message)
|
24
|
-
message
|
54
|
+
message.merge!({
|
55
|
+
sequence: length,
|
56
|
+
time: Time.now.to_f
|
57
|
+
})
|
58
|
+
|
25
59
|
logger && logger.info(message)
|
26
60
|
|
27
61
|
super(message)
|
@@ -44,36 +78,6 @@ module Gekko
|
|
44
78
|
end
|
45
79
|
end
|
46
80
|
|
47
|
-
#
|
48
|
-
# Returns the traded volume for the last 24h
|
49
|
-
#
|
50
|
-
# @return [Fixnum] The last 24h volume
|
51
|
-
#
|
52
|
-
def volume_24h
|
53
|
-
move_24h_cursor!
|
54
|
-
@volume_24h
|
55
|
-
end
|
56
|
-
|
57
|
-
#
|
58
|
-
# Returns the highest trade price that occurred during the last 24h
|
59
|
-
#
|
60
|
-
# @return [Fixnum] The last 24h high
|
61
|
-
#
|
62
|
-
def high_24h
|
63
|
-
move_24h_cursor!
|
64
|
-
@high_24h
|
65
|
-
end
|
66
|
-
|
67
|
-
#
|
68
|
-
# Returns the lowest trade price that occurred during the last 24h
|
69
|
-
#
|
70
|
-
# @return [Fixnum] The last 24h low
|
71
|
-
#
|
72
|
-
def low_24h
|
73
|
-
move_24h_cursor!
|
74
|
-
@low_24h
|
75
|
-
end
|
76
|
-
|
77
81
|
#
|
78
82
|
# Recalculates the previous 24h high and low
|
79
83
|
#
|
@@ -87,8 +91,10 @@ module Gekko
|
|
87
91
|
evt = self[tmp_cursor]
|
88
92
|
|
89
93
|
while (evt && (evt[:time] >= time_24h_ago)) do
|
90
|
-
|
91
|
-
|
94
|
+
if evt[:type] == :execution
|
95
|
+
@high_24h = ((@high_24h.nil? || (evt[:price] > @high_24h)) && evt[:price]) || @high_24h
|
96
|
+
@low_24h = ((@low_24h.nil? || (evt[:price] < @low_24h)) && evt[:price]) || @low_24h
|
97
|
+
end
|
92
98
|
|
93
99
|
tmp_cursor -= 1
|
94
100
|
evt = (tmp_cursor >= 0) && self[tmp_cursor]
|
@@ -101,7 +107,7 @@ module Gekko
|
|
101
107
|
# @return [Fixnum] The last 24h quote currency volume
|
102
108
|
#
|
103
109
|
def quote_volume_24h
|
104
|
-
move_24h_cursor!
|
110
|
+
#move_24h_cursor!
|
105
111
|
@quote_volume_24h
|
106
112
|
end
|
107
113
|
|
@@ -136,7 +142,7 @@ module Gekko
|
|
136
142
|
# @return [Float] Yesterday's cut-off timestamp
|
137
143
|
#
|
138
144
|
def time_24h_ago
|
139
|
-
Time.now.to_f -
|
145
|
+
Time.now.to_f - SECONDS_IN_24H
|
140
146
|
end
|
141
147
|
|
142
148
|
#
|
@@ -145,7 +151,7 @@ module Gekko
|
|
145
151
|
# passed to Tape#fall_out_of_24h_window
|
146
152
|
#
|
147
153
|
def move_24h_cursor!
|
148
|
-
while(self[@cursor_24h] && (
|
154
|
+
while(self[@cursor_24h] && (self[@cursor_24h][:time] < time_24h_ago))
|
149
155
|
if self[@cursor_24h][:type] == :execution
|
150
156
|
fall_out_of_24h_window(self[@cursor_24h])
|
151
157
|
end
|
data/lib/gekko/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gekko
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David FRANCOIS
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uuidtools
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: pry
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|