gekko 0.3.1 → 0.5.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: 724b1a6b9a228d238ffdcb74a84e2460a09df83e
4
- data.tar.gz: 3c9ce015f90c21e9b43780dddae3b7581d865299
3
+ metadata.gz: 6e807cf299a74840caedd3ab554af8b30c797d51
4
+ data.tar.gz: bce631e42323b43fd1864033a8e8bd6f4c97ffea
5
5
  SHA512:
6
- metadata.gz: 1956c91a15816852444d39cb70aa3f62c43ded976493d7dd54c474e3c4e64716c65985479ba1b9d63e9a5beeece308d7d3904f7c8ecbe2dbc5596c5bc5b777d4
7
- data.tar.gz: 3d54b6d4daae77ac190ca2fc4a95f5fe2f9238e9275ca91a0d72d33f77b28578cc149e2cb95bec053cc679bf5c41bdae995adef22f957ad3349f02cbdf84cc00
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
 
@@ -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
- def initialize(logger = nil)
11
- @logger = logger
12
- @cursor = 0
13
- @cursor_24h = 0
14
- @volume_24h = 0
15
- @quote_volume_24h = 0
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[:sequence] = length
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
- @high_24h = ((@high_24h.nil? || (evt[:price] > @high_24h)) && evt[:price]) || @high_24h
91
- @low_24h = ((@low_24h.nil? || (evt[:price] < @low_24h)) && evt[:price]) || @low_24h
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 - 24*3600
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] && ((self[@cursor_24h][:type] != :execution) || (self[@cursor_24h][:time] < time_24h_ago)))
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
@@ -1,6 +1,6 @@
1
1
  module Gekko
2
2
 
3
3
  # The Gekko version string
4
- VERSION = '0.3.1'
4
+ VERSION = '0.5.0'
5
5
 
6
6
  end
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.3.1
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-12 00:00:00.000000000 Z
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