gekko 0.0.1 → 0.1.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.rb +2 -0
- data/lib/gekko/book.rb +81 -38
- data/lib/gekko/limit_order.rb +29 -0
- data/lib/gekko/market_order.rb +36 -0
- data/lib/gekko/order.rb +26 -23
- data/lib/gekko/tape.rb +70 -6
- data/lib/gekko/version.rb +1 -1
- metadata +81 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c22a43388f516eb29f65b1c7439018b7d0b62b2d
|
4
|
+
data.tar.gz: f5b5b3011d40a9dfa97b3573b166af0c772023cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c486804dc2109f896f2d98cb160b099e73dbe157c465f21bf61f7cfa56f36794ceac3886677ebd802102bc90d0c5e0059aeaa354c590047b152a39746dd6bac
|
7
|
+
data.tar.gz: 5c303f98396a43ba09640630f8bb8f649b064819f05a5b76c4fc1e75f7bdc0d2e58411bb8fc186d18b96006e5b1aa916750ce60d9915fb5e9fb64eae5baceed3
|
data/lib/gekko.rb
CHANGED
data/lib/gekko/book.rb
CHANGED
@@ -16,13 +16,15 @@ module Gekko
|
|
16
16
|
# The default minimum price increment accepted for placed orders
|
17
17
|
DEFAULT_TICK_SIZE = 1000
|
18
18
|
|
19
|
-
attr_accessor :pair, :bids, :asks, :tape, :tick_size
|
19
|
+
attr_accessor :pair, :bids, :asks, :tape, :tick_size, :received, :base_precision
|
20
20
|
|
21
21
|
def initialize(pair, opts = {})
|
22
|
-
self.pair
|
23
|
-
self.bids
|
24
|
-
self.asks
|
25
|
-
self.tape
|
22
|
+
self.pair = pair
|
23
|
+
self.bids = BookSide.new(:bid)
|
24
|
+
self.asks = BookSide.new(:ask)
|
25
|
+
self.tape = Tape.new(opts[:logger])
|
26
|
+
self.base_precision = 8
|
27
|
+
self.received = {}
|
26
28
|
|
27
29
|
self.tick_size = opts[:tick_size] || DEFAULT_TICK_SIZE
|
28
30
|
raise "Tick size must be a positive integer if provided" if tick_size && (!tick_size.is_a?(Fixnum) || tick_size <= 0)
|
@@ -35,44 +37,68 @@ module Gekko
|
|
35
37
|
#
|
36
38
|
def receive_order(order)
|
37
39
|
|
38
|
-
raise Gekko::
|
40
|
+
raise 'Order must be a Gekko::LimitOrder or a Gekko::MarketOrder' unless [LimitOrder, MarketOrder].include?(order.class)
|
39
41
|
|
40
|
-
|
41
|
-
opposite_side = order.bid? ? asks : bids
|
42
|
-
next_match = opposite_side.first
|
42
|
+
raise Gekko::TickSizeMismatch unless (order.is_a?(MarketOrder) || (order.price % tick_size).zero?)
|
43
43
|
|
44
|
-
|
44
|
+
if received.has_key?(order.id.to_s)
|
45
|
+
tape << order.message(:reject, reason: "Duplicate ID <#{order.id.to_s}>")
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
47
|
+
else
|
48
|
+
self.received[order.id.to_s] = order
|
49
|
+
tape << order.message(:received)
|
50
|
+
|
51
|
+
order_side = order.bid? ? bids : asks
|
52
|
+
opposite_side = order.bid? ? asks : bids
|
53
|
+
next_match = opposite_side.first
|
54
|
+
|
55
|
+
while !order.done? && order.crosses?(next_match)
|
56
|
+
trade_price = next_match.price
|
57
|
+
base_size = [next_match.remaining, order.remaining].min
|
58
|
+
|
59
|
+
if order.is_a?(LimitOrder)
|
60
|
+
quote_size = (base_size * trade_price) / (10 ** base_precision)
|
61
|
+
|
62
|
+
elsif order.is_a?(MarketOrder)
|
63
|
+
if order.ask? || (order.remaining_quote_margin > ((trade_price * base_size) / (10 ** base_precision)))
|
64
|
+
quote_size = ((trade_price * base_size) / (10 ** base_precision))
|
65
|
+
order.remaining_quote_margin -= quote_size if order.bid?
|
66
|
+
elsif order.bid?
|
67
|
+
quote_size = order.remaining_quote_margin
|
68
|
+
base_size = (order.remaining_quote_margin * (10 ** base_precision)) / trade_price
|
69
|
+
order.remaining_quote_margin -= quote_size
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
tape << {
|
75
|
+
type: :execution,
|
76
|
+
price: trade_price,
|
77
|
+
base_size: base_size,
|
78
|
+
quote_size: quote_size,
|
79
|
+
maker_order_id: next_match.id.to_s,
|
80
|
+
taker_order_id: order.id.to_s,
|
81
|
+
time: Time.now.to_f,
|
82
|
+
tick: order.bid? ? :up : :down
|
83
|
+
}
|
84
|
+
|
85
|
+
order.remaining -= base_size
|
86
|
+
next_match.remaining -= base_size
|
87
|
+
|
88
|
+
if next_match.filled?
|
89
|
+
tape << opposite_side.shift.message(:done, reason: :filled)
|
90
|
+
next_match = opposite_side.first
|
91
|
+
end
|
68
92
|
end
|
69
|
-
end
|
70
93
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
94
|
+
if order.filled?
|
95
|
+
tape << order.message(:done, reason: :filled)
|
96
|
+
elsif order.fill_or_kill?
|
97
|
+
tape << order.message(:done, reason: :killed)
|
98
|
+
else
|
99
|
+
order_side.insert_order(order)
|
100
|
+
tape << order.message(:open)
|
101
|
+
end
|
76
102
|
end
|
77
103
|
end
|
78
104
|
|
@@ -100,6 +126,23 @@ module Gekko
|
|
100
126
|
ask && bid && (ask - bid)
|
101
127
|
end
|
102
128
|
|
129
|
+
#
|
130
|
+
# Returns the current ticker
|
131
|
+
#
|
132
|
+
# @return [Hash] The current ticker
|
133
|
+
#
|
134
|
+
def ticker
|
135
|
+
v24h = tape.volume_24h
|
136
|
+
{
|
137
|
+
last: tape.last_trade_price,
|
138
|
+
bid: bid,
|
139
|
+
ask: ask,
|
140
|
+
spread: spread,
|
141
|
+
volume_24h: v24h,
|
142
|
+
vwap_24h: (v24h > 0) && (tape.quote_volume_24h * (10 ** base_precision)/ v24h)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
103
146
|
end
|
104
147
|
end
|
105
148
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Gekko
|
2
|
+
|
3
|
+
#
|
4
|
+
# Represents a limit order. These order must specify a price.
|
5
|
+
#
|
6
|
+
class LimitOrder < Order
|
7
|
+
|
8
|
+
attr_accessor :price
|
9
|
+
|
10
|
+
def initialize(side, id, size, price, expiration = nil)
|
11
|
+
super(side, id, size, expiration)
|
12
|
+
@price = price
|
13
|
+
raise 'Price must be a positive integer' if @price.nil? || (!@price.is_a?(Fixnum) || (@price <= 0))
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Returns +true+ if the order is filled
|
18
|
+
#
|
19
|
+
def filled?
|
20
|
+
remaining.zero?
|
21
|
+
end
|
22
|
+
|
23
|
+
def done?
|
24
|
+
filled?
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Gekko
|
2
|
+
|
3
|
+
#
|
4
|
+
# Represents a market order. If a bid, it must specify the maximum spendable quote
|
5
|
+
# currency as remaining quote margin
|
6
|
+
#
|
7
|
+
class MarketOrder < Order
|
8
|
+
|
9
|
+
attr_accessor :quote_margin, :remaining_quote_margin
|
10
|
+
|
11
|
+
def initialize(side, id, size, quote_margin, expiration = nil)
|
12
|
+
super(side, id, size, expiration)
|
13
|
+
@quote_margin = quote_margin
|
14
|
+
@remaining_quote_margin = @quote_margin
|
15
|
+
raise 'Quote currency margin must be provided for a market bid' if quote_margin.nil? && bid?
|
16
|
+
raise 'Quote currency margin can not be specified for a market ask' if quote_margin && ask?
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Returns +true+ if the order is filled
|
21
|
+
#
|
22
|
+
def filled?
|
23
|
+
remaining.zero?
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Returns +true+ if the order has been filled or can not keep
|
28
|
+
# executing further due to quote currency margin constraints
|
29
|
+
#
|
30
|
+
def done?
|
31
|
+
filled? || (bid? && remaining_quote_margin.zero?)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/lib/gekko/order.rb
CHANGED
@@ -2,7 +2,7 @@ module Gekko
|
|
2
2
|
|
3
3
|
#
|
4
4
|
# Represents a trade order. Trade orders can be either buy (bid) or sell (ask) orders.
|
5
|
-
# All orders are identified by an UUID, must specify a size,
|
5
|
+
# All orders are identified by an UUID, and must specify a size, and an optional
|
6
6
|
# expiration timestamp.
|
7
7
|
#
|
8
8
|
class Order
|
@@ -11,38 +11,33 @@ module Gekko
|
|
11
11
|
|
12
12
|
def initialize(side, id, size, price, expiration = nil)
|
13
13
|
@id = id
|
14
|
-
@side = side
|
15
|
-
@size
|
14
|
+
@side = side && side.to_sym
|
15
|
+
@size = size
|
16
16
|
@remaining = @size
|
17
|
-
@price = price
|
18
17
|
@expiration = expiration
|
19
18
|
@created_at = Time.now.to_f
|
20
19
|
|
21
|
-
raise 'Orders must have an UUID'
|
22
|
-
raise 'Side must be either :bid or :ask'
|
23
|
-
raise '
|
24
|
-
raise '
|
25
|
-
raise '
|
26
|
-
raise 'The order creation timestamp can''t be nil' if !@created_at
|
20
|
+
raise 'Orders must have an UUID' unless @id && @id.is_a?(UUID)
|
21
|
+
raise 'Side must be either :bid or :ask' unless [:bid, :ask].include?(@side)
|
22
|
+
raise 'Size must be a positive integer' if (@size && (!@size.is_a?(Fixnum) || @size <= 0))
|
23
|
+
raise 'Expiration must be omitted or be an integer' unless (@expiration.nil? || (@expiration.is_a?(Fixnum) && @expiration > 0))
|
24
|
+
raise 'The order creation timestamp can''t be nil' if !@created_at
|
27
25
|
end
|
28
26
|
|
29
27
|
#
|
30
|
-
# Returns +true+ if this order can execute against +
|
28
|
+
# Returns +true+ if this order can execute against +limit_order+
|
31
29
|
#
|
32
|
-
# @param
|
30
|
+
# @param limit_order [LimitOrder] The limit order against which we want
|
33
31
|
# to know if an execution is possible
|
34
32
|
#
|
35
|
-
def crosses?(
|
36
|
-
if
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
33
|
+
def crosses?(limit_order)
|
34
|
+
if limit_order
|
35
|
+
raise 'Can not test againt a market order' unless limit_order.is_a?(LimitOrder)
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
remaining.zero?
|
37
|
+
if bid? ^ limit_order.bid?
|
38
|
+
is_a?(MarketOrder) || (bid? && (price >= limit_order.price)) || (ask? && (price <= limit_order.price))
|
39
|
+
end
|
40
|
+
end
|
46
41
|
end
|
47
42
|
|
48
43
|
#
|
@@ -57,7 +52,7 @@ module Gekko
|
|
57
52
|
def message(type, extra_attrs = {})
|
58
53
|
{
|
59
54
|
type: type,
|
60
|
-
order_id: id,
|
55
|
+
order_id: id.to_s,
|
61
56
|
side: side,
|
62
57
|
size: size,
|
63
58
|
remaining: remaining,
|
@@ -79,5 +74,13 @@ module Gekko
|
|
79
74
|
!bid?
|
80
75
|
end
|
81
76
|
|
77
|
+
#
|
78
|
+
# Returns +true+ if this order isn't supposed to stick around in
|
79
|
+
# the order book
|
80
|
+
#
|
81
|
+
def fill_or_kill?
|
82
|
+
is_a?(Gekko::MarketOrder)
|
83
|
+
end
|
84
|
+
|
82
85
|
end
|
83
86
|
end
|
data/lib/gekko/tape.rb
CHANGED
@@ -3,13 +3,16 @@ module Gekko
|
|
3
3
|
#
|
4
4
|
# Records the trading engine messages sequentially
|
5
5
|
#
|
6
|
-
class Tape
|
6
|
+
class Tape < Array
|
7
7
|
|
8
|
-
attr_accessor :
|
8
|
+
attr_accessor :logger, :last_trade_price
|
9
9
|
|
10
10
|
def initialize(logger = nil)
|
11
|
-
@
|
12
|
-
@
|
11
|
+
@logger = logger
|
12
|
+
@cursor = 0
|
13
|
+
@cursor_24h = 0
|
14
|
+
@volume_24h = 0
|
15
|
+
@quote_volume_24h = 0
|
13
16
|
end
|
14
17
|
|
15
18
|
#
|
@@ -18,10 +21,71 @@ module Gekko
|
|
18
21
|
# @param message [Hash] The message to record
|
19
22
|
#
|
20
23
|
def <<(message)
|
21
|
-
message[:sequence] =
|
24
|
+
message[:sequence] = length
|
22
25
|
logger && logger.info(message)
|
23
|
-
|
26
|
+
|
27
|
+
if message[:type] == :execution
|
28
|
+
# Keep last price up to date
|
29
|
+
@last_trade_price = message[:price]
|
30
|
+
|
31
|
+
# Keep 24h volume up to date
|
32
|
+
@volume_24h += message[:base_size]
|
33
|
+
@quote_volume_24h += message[:quote_size]
|
34
|
+
move_24h_cursor!
|
35
|
+
end
|
36
|
+
|
37
|
+
super(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Returns the next unread element from the tape
|
42
|
+
#
|
43
|
+
# @return [Hash] The next unread element
|
44
|
+
#
|
45
|
+
def next
|
46
|
+
if @cursor < length
|
47
|
+
n = self[@cursor]
|
48
|
+
@cursor += 1
|
49
|
+
n
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Returns the traded volume for the last 24h
|
55
|
+
#
|
56
|
+
# @return [Fixnum] The last 24h volume
|
57
|
+
#
|
58
|
+
def volume_24h
|
59
|
+
move_24h_cursor!
|
60
|
+
@volume_24h
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Returns the traded amount of quote currency in the last 24h
|
65
|
+
#
|
66
|
+
# @return [Fixnum] The last 24h quote currency volume
|
67
|
+
#
|
68
|
+
def quote_volume_24h
|
69
|
+
move_24h_cursor!
|
70
|
+
@quote_volume_24h
|
24
71
|
end
|
25
72
|
|
73
|
+
#
|
74
|
+
# Moves the cursor pointing to the first trade that happened during
|
75
|
+
# the last 24h and updates the volume along the way
|
76
|
+
#
|
77
|
+
def move_24h_cursor!
|
78
|
+
time_24h_ago = Time.now.to_f - 24*3600
|
79
|
+
|
80
|
+
while(self[@cursor_24h] && ((self[@cursor_24h][:type] != :execution) || (self[@cursor_24h][:time] < time_24h_ago)))
|
81
|
+
if self[@cursor_24h] && self[@cursor_24h][:type] == :execution
|
82
|
+
@volume_24h -= self[@cursor_24h][:base_size]
|
83
|
+
@quote_volume_24h -= self[@cursor_24h][:quote_size]
|
84
|
+
end
|
85
|
+
|
86
|
+
@cursor_24h += 1
|
87
|
+
end
|
88
|
+
end
|
26
89
|
end
|
27
90
|
end
|
91
|
+
|
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.0
|
4
|
+
version: 0.1.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-
|
11
|
+
date: 2015-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uuidtools
|
@@ -24,48 +24,118 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.10'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rspec
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ~>
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
47
|
+
version: '3.1'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - ~>
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
54
|
+
version: '3.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.8'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: timecop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.7'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.7'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: redcarpet
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.1'
|
41
111
|
- !ruby/object:Gem::Dependency
|
42
112
|
name: simplecov
|
43
113
|
requirement: !ruby/object:Gem::Requirement
|
44
114
|
requirements:
|
45
115
|
- - ~>
|
46
116
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
117
|
+
version: '0.9'
|
48
118
|
type: :development
|
49
119
|
prerelease: false
|
50
120
|
version_requirements: !ruby/object:Gem::Requirement
|
51
121
|
requirements:
|
52
122
|
- - ~>
|
53
123
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
124
|
+
version: '0.9'
|
55
125
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
126
|
+
name: coveralls
|
57
127
|
requirement: !ruby/object:Gem::Requirement
|
58
128
|
requirements:
|
59
129
|
- - ~>
|
60
130
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
131
|
+
version: '0.7'
|
62
132
|
type: :development
|
63
133
|
prerelease: false
|
64
134
|
version_requirements: !ruby/object:Gem::Requirement
|
65
135
|
requirements:
|
66
136
|
- - ~>
|
67
137
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
138
|
+
version: '0.7'
|
69
139
|
description: Gekko is a bare-bones order matcher whose task is to accept orders and
|
70
140
|
maintain an order book.
|
71
141
|
email:
|
@@ -80,6 +150,8 @@ files:
|
|
80
150
|
- lib/gekko/book.rb
|
81
151
|
- lib/gekko/book_side.rb
|
82
152
|
- lib/gekko/errors.rb
|
153
|
+
- lib/gekko/limit_order.rb
|
154
|
+
- lib/gekko/market_order.rb
|
83
155
|
- lib/gekko/order.rb
|
84
156
|
- lib/gekko/tape.rb
|
85
157
|
- lib/gekko/version.rb
|