moneymarket 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 431f681b6306e4f8f9bac8017b05eb444b8fdf2e
4
+ data.tar.gz: f27dfd43db2c3aa4eadb7e4f9e82f44760b35c1a
5
+ SHA512:
6
+ metadata.gz: c889833e9447fb731530f530aa588668e2d0d399d5730c8febaa935e7f5d8374dc88c3af6b40fa537238ef34b51527833c61235d982b768957d39bd95b98cac1
7
+ data.tar.gz: 9b9ecb7169ef94c1bb361e3a3c86f0bb85c5e633029c2bb716176594ac1646066bab861326227dacd89b26b02d3c823ddbac4cde512737ff47c8ccb52417934d
data/bin/moneymarket ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # TOOD: json-RPC mode
4
+ # require 'moneymarket'
5
+ # require 'moneymarket/cli'
@@ -0,0 +1,20 @@
1
+ require 'moneymarket/version'
2
+
3
+ require 'money'
4
+ require 'moneymarket/utils/calculator'
5
+ require 'moneymarket/utils/command'
6
+
7
+ require 'moneymarket/core/order'
8
+ require 'moneymarket/core/bid'
9
+ require 'moneymarket/core/ask'
10
+ require 'moneymarket/core/market'
11
+ require 'moneymarket/core/match'
12
+ require 'moneymarket/core/account'
13
+ require 'moneymarket/core/account_provider'
14
+ require 'moneymarket/core/slope'
15
+ require 'moneymarket/core/book'
16
+
17
+ module Moneymarket
18
+ def self.book()
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ class CheckOrderSolvent < Command.new(:market, :order)
2
+ def perform
3
+ return true if order.market_order?
4
+ source_available_amount >= order.required_amount
5
+ end
6
+
7
+ private
8
+
9
+ def source_available_amount
10
+ market.source_account_for(order).available
11
+ end
12
+ end
@@ -0,0 +1,109 @@
1
+ class ApplyMatch < Command.new(:market, :match)
2
+ def perform
3
+ cache_balances :before
4
+ execute_exchange
5
+ execute_fees unless same_user?
6
+ cache_balances :after
7
+ event
8
+ end
9
+
10
+ private
11
+
12
+ def execute_exchange
13
+ bid_quote_account.unfreeze quote unless bid.new?
14
+ ask_base_account.unfreeze volume unless ask.new?
15
+
16
+ bid.consume volume
17
+ ask.consume volume
18
+
19
+ transfer quote, from: bid_quote_account, to: ask_quote_account
20
+ transfer volume, from: ask_base_account, to: bid_base_account
21
+
22
+ event.quote = quote
23
+ end
24
+
25
+ def execute_fees
26
+ transfer bid_fee, from: bid_base_account, to: exchange_base_account
27
+ transfer ask_fee, from: ask_quote_account, to: exchange_quote_account
28
+
29
+ event.bid_fee = bid_fee
30
+ event.ask_fee = ask_fee
31
+ end
32
+
33
+ def cache_balances(_which)
34
+ event.public_send("bid_base_account_#{_which}=", bid_base_account.clone)
35
+ event.public_send("bid_quote_account_#{_which}=", bid_quote_account.clone)
36
+ event.public_send("ask_base_account_#{_which}=", ask_base_account.clone)
37
+ event.public_send("ask_quote_account_#{_which}=", ask_quote_account.clone)
38
+ event.public_send("ex_base_account_#{_which}=", exchange_base_account.clone)
39
+ event.public_send("ex_quote_account_#{_which}=", exchange_quote_account.clone)
40
+ end
41
+
42
+ def event
43
+ @event ||= Events::TransactionExecuted.new.tap do |ev|
44
+ ev.bid = bid.ref
45
+ ev.ask = ask.ref
46
+ ev.volume = volume
47
+ ev.quote = quote
48
+ end
49
+ end
50
+
51
+ def bid
52
+ match.bid
53
+ end
54
+
55
+ def ask
56
+ match.ask
57
+ end
58
+
59
+ def volume
60
+ match.volume
61
+ end
62
+
63
+ def quote
64
+ @quote ||= begin
65
+ CalculateQuote.new(volume: volume, unit_price: match.price_paid).perform
66
+ end
67
+ end
68
+
69
+ def transfer(_amount, from: nil, to: nil)
70
+ from.withdraw _amount
71
+ to.deposit _amount
72
+ end
73
+
74
+ def bid_base_account
75
+ market.base_account_for match.bid
76
+ end
77
+
78
+ def ask_base_account
79
+ market.base_account_for match.ask
80
+ end
81
+
82
+ def bid_quote_account
83
+ market.quote_account_for match.bid
84
+ end
85
+
86
+ def ask_quote_account
87
+ market.quote_account_for match.ask
88
+ end
89
+
90
+ def same_user?
91
+ bid.user == ask.user
92
+ end
93
+
94
+ def bid_fee
95
+ @bid_fee ||= CalculateFee.new(order: bid, collected_amount: volume).perform
96
+ end
97
+
98
+ def ask_fee
99
+ @ask_fee ||= CalculateFee.new(order: ask, collected_amount: quote).perform
100
+ end
101
+
102
+ def exchange_base_account
103
+ market.exchange_base_account
104
+ end
105
+
106
+ def exchange_quote_account
107
+ market.exchange_quote_account
108
+ end
109
+ end
@@ -0,0 +1,28 @@
1
+ class LimitMatches < Command.new(:matches, :destination_limit)
2
+ def perform
3
+ matches.select do |match|
4
+ next false if destination_limit <= 0
5
+
6
+ quote = calc_quote(match)
7
+ if quote > destination_limit
8
+ # IDEA: instead of lowering the match amount maybe this should be considered insolvency
9
+ match.volume = calc_volume(match, destination_limit)
10
+ destination_limit = 0
11
+ else
12
+ destination_limit -= quote
13
+ end
14
+
15
+ match.volume > 0
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def calc_quote(_match)
22
+ _match.match.destination_collected_amount for_volume: _match.volume
23
+ end
24
+
25
+ def calc_volume(_match, _new_quote)
26
+ _match.match.volume_required_to_collect _new_quote
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ class MatchOrderToSlope < Command.new(:slope, :order)
2
+ def perform
3
+ Enumerator.new do |y|
4
+ remaining = order.volume
5
+ each_order do |match|
6
+ next if match.timestamp > _order.timestamp # << this should trigger an alert, should never happen
7
+
8
+ if match.volume >= remaining
9
+ y << build_match(match, remaining)
10
+ break
11
+ else
12
+ y << build_match(match, match.volume)
13
+ remaining -= match.volume
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def each_order
22
+ if order.market_order?
23
+ slope.each
24
+ else
25
+ slope.each_until_limit(order.limit)
26
+ end
27
+ end
28
+
29
+ def build_match(_match, _volume)
30
+ Match.new(trigger: order, match: _match, volume: _volume)
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ module Moneymarket
2
+ class Account
3
+ attr_reader :user, :currency, :total, :frozen, :ref
4
+
5
+ def initialize(_user, _currency, _total, _frozen, _ref = nil)
6
+ @user = _user
7
+ @currency = _currency
8
+ @total = _total
9
+ @frozen = _frozen
10
+ @ref = _ref
11
+ end
12
+
13
+ def available
14
+ total - frozen
15
+ end
16
+
17
+ def freeze(_amount)
18
+ # TODO: check currency?
19
+ raise ArgumentError, 'amount to freeze must be positive' if _amount < 0
20
+ raise ArgumentError, 'trying to freeze more than is available' if _amount > available
21
+ @frozen += _amount
22
+ end
23
+
24
+ def unfreeze(_amount)
25
+ raise ArgumentError, 'amount to unfreeze must be positive' if _amount < 0
26
+ raise ArgumentError, 'trying to unfreeze more than is frozen' if _amount > frozen
27
+ @frozen -= _amount
28
+ end
29
+
30
+ def deposit(_amount)
31
+ raise ArgumentError, 'amount to deposit must be positive' if _amount < 0
32
+ @total += _amount
33
+ end
34
+
35
+ def withdraw(_amount)
36
+ raise ArgumentError, 'amount to withdraw must be positive' if _amount < 0
37
+ raise ArgumentError, 'not enough funds to withdraw' if _amount > available
38
+ @total -= _amount
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ module Moneymarket
2
+ class AccountProvider
3
+ def initialize
4
+ @accounts = {}
5
+ end
6
+
7
+ def reset
8
+ @accounts = {}
9
+ end
10
+
11
+ def exchange_account_for(_currency)
12
+ assert_implemented :exchange_account_for
13
+ end
14
+
15
+ def account_for(_user_id, _currency)
16
+ assert_implemented :account_for
17
+ end
18
+
19
+ def preload_user_balances(_users, _currencies)
20
+ assert_implemented :preload_user_balances
21
+ end
22
+
23
+ def preload_balances(_order)
24
+ _order.base_balance = fetch_balance(_order.account_id, _order.base_currency)
25
+ _order.quote_balance = fetch_balance(_order.account_id, _order.quote_currency)
26
+ end
27
+
28
+ private
29
+
30
+ def assert_implemented(_name)
31
+ raise NotImplementedError, "#{_name} is not implemented"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ module Moneymarket
2
+ class Ask < Order
3
+ def bid?
4
+ false
5
+ end
6
+
7
+ def source_account
8
+ :base_account
9
+ end
10
+
11
+ def destination_account
12
+ :quote_account
13
+ end
14
+
15
+ def source_required_amount(for_volume: nil)
16
+ volume || amount
17
+ end
18
+
19
+ def destination_collected_amount(for_volume: nil)
20
+ Calculator.quote(volume: volume || amount, unit_price: limit)
21
+ end
22
+
23
+ def volume_required_to_collect(_source_amount)
24
+ _source_amount
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ module Moneymarket
2
+ class Bid < Order
3
+ def bid?
4
+ true
5
+ end
6
+
7
+ def source_account
8
+ :quote_account
9
+ end
10
+
11
+ def destination_account
12
+ :base_account
13
+ end
14
+
15
+ def source_required_amount(for_volume: nil)
16
+ Calculator.quote(volume: for_volume || volume, unit_price: limit)
17
+ end
18
+
19
+ def destination_collected_amount(for_volume: nil)
20
+ for_volume || volume
21
+ end
22
+
23
+ def volume_required_to_collect(_source_amount)
24
+ Calculator.volume(
25
+ quote: _source_amount,
26
+ unit_price: limit,
27
+ unit_currency: volume.currency
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,76 @@
1
+ module Moneymarket
2
+ def Book
3
+ attr_reader :asks, :bids
4
+
5
+ def initialize(_market)
6
+ @market = _market
7
+ @bids = Slope.new { |a, b| a.limit_cents <=> b.limit_cents }
8
+ @asks = Slope.new { |a, b| b.limit_cents <=> a.limit_cents }
9
+ end
10
+
11
+ def flush_events
12
+ flushed = @events
13
+ @events = []
14
+ flushed
15
+ end
16
+
17
+ def push(_order)
18
+ # TODO: check market(currency)
19
+
20
+ if _order.new?
21
+ raise ArgumentError, 'insolvent order' unless check_solvent _order
22
+
23
+ matches = match_to_slope _order
24
+ matches = adjust_market_order matches, _order if _order.market_order?
25
+ preload_balances matches
26
+ matches.each { |tx| execute_match tx }
27
+ _order.flag_as_open
28
+
29
+ freeze_source_balance _order
30
+ # TODO: execute_triggers (stop-loss, take-profit, etc)
31
+ end
32
+
33
+ slope_for(_order).add _order if _order.open?
34
+ end
35
+
36
+ def cancel(_order)
37
+ if _order.open?
38
+
39
+ slope_for(_order).remove _order
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def slope_for(_order)
46
+ if order.bid? then bids else asks end
47
+ end
48
+
49
+ def oposite_slope(_order)
50
+ if order.bid? then asks else bids end
51
+ end
52
+
53
+ def check_solvent(_order)
54
+ CheckOrderSolvent.for market: market, order: _order
55
+ end
56
+
57
+ def match_to_slope(_order)
58
+ slope = oposite_slope(_order)
59
+ MatchOrderToSlope.for slope: slope, order: _order
60
+ end
61
+
62
+ def adjust_market_order(_matches, _order)
63
+ limit = market.source_account(_order).available_amount
64
+ LimitMatches.for matches: _matches, limit: limit
65
+ end
66
+
67
+ def execute_match(_match)
68
+ @events << ExecuteMatch.for(market: market, match: _match)
69
+ end
70
+
71
+ def preload_balances(_matches)
72
+ users = _matches.map { |m| [m.bid.user, m.ask.user] }.flatten.uniq
73
+ market.preload_user_balances users
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,39 @@
1
+ module Moneymarket
2
+ class Market
3
+ attr_reader :account_provider
4
+
5
+ def initialize(_base_currency, _quote_currency, account_provider = nil)
6
+ @base_currency = _base_currency
7
+ @quote_currency = _quote_currency
8
+ @account_provider = account_provider
9
+ end
10
+
11
+ def preload_user_balances(_users)
12
+ account_provider.preload_balances(_users, [_base_currency, _quote_currency])
13
+ end
14
+
15
+ def exchange_base_account
16
+ account_provider.exchange_account_for base_currency
17
+ end
18
+
19
+ def exchange_quote_account
20
+ account_provider.exchange_account_for quote_currency
21
+ end
22
+
23
+ def base_account_for(_order)
24
+ account_provider.account_for(_order.user_id, base_currency)
25
+ end
26
+
27
+ def quote_account_for(_order)
28
+ account_provider.account_for(_order.user_id, quote_currency)
29
+ end
30
+
31
+ def source_account_for(_order)
32
+ public_send(_order.source_account, _order)
33
+ end
34
+
35
+ def destination_account_for(_order)
36
+ public_send(_order.destination_account, _order)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ module Moneymarket
2
+ class Match
3
+ attr_reader :market, :bid, :ask
4
+ attr_accessor :volume
5
+
6
+ def initialize(_trigger, _match, _volume)
7
+ @trigger = _trigger
8
+ @bid = _trigger.bid? ? _trigger : _match
9
+ @ask = _trigger.bid? ? _match : _trigger
10
+ @match = _match
11
+ @volume = _volume
12
+ end
13
+
14
+ def price_paid
15
+ match.limit
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ module Moneymarket
2
+ class Order
3
+ NEW = :new
4
+ OPEN = :open
5
+ TRADED = :traded
6
+ CANCELED = :canceled
7
+
8
+ attr_reader :user, :volume, :limit, :fee, :ref
9
+
10
+ def initialize(user: nil, status: NEW, volume: nil, limit: nil, fee: 0.0, ref: nil)
11
+ @user = user
12
+ @status = status
13
+ @volume = volume
14
+ @limit = limit
15
+ @fee = fee
16
+ @ref = ref
17
+ end
18
+
19
+ def market_order?
20
+ limit.nil?
21
+ end
22
+
23
+ def base_currency
24
+ volume.currency
25
+ end
26
+
27
+ def quote_currency
28
+ limit.currency
29
+ end
30
+
31
+ def consume(_volume)
32
+ raise ArgumentError, 'cannot consume, order closed' if closed?
33
+ raise ArgumentError, 'amount to consume must be positive' if _volume < 0
34
+ raise ArgumentError, 'trying to consume more than is available' if _volume > @volume
35
+ @volume -= _volume
36
+
37
+ @status = TRADED if @volume == 0
38
+ end
39
+
40
+ def flag_as_open
41
+ if market_order?
42
+ flag_as_canceled
43
+ else
44
+ @status = OPEN if new?
45
+ end
46
+ end
47
+
48
+ def flag_as_canceled
49
+ @status = CANCELED unless closed?
50
+ end
51
+
52
+ [NEW, OPEN, TRADED, CANCELED].each do |name|
53
+ define_method("#{name}?") { @status == name }
54
+ end
55
+
56
+ def closed?
57
+ traded? || canceled?
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,44 @@
1
+ module Moneymarket
2
+ class Slope
3
+ def initialize(&_comp_func)
4
+ @orders = []
5
+ @cmp = _comp_func
6
+ end
7
+
8
+ def add(_order)
9
+ idx = orders.index { |o| compare(o, _order) > 0 }
10
+ if idx.nil?
11
+ orders << _order
12
+ else
13
+ orders.insert idx, _order
14
+ end
15
+ end
16
+
17
+ def remove(_order)
18
+ orders.delete(_order)
19
+ end
20
+
21
+ def each
22
+ orders.each
23
+ end
24
+
25
+ def each_until_limit(_limit)
26
+ Enumerator.new do |y|
27
+ orders.each do |order|
28
+ break if cmp.call(order, _limit) > 0
29
+ y << order
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :orders, :cmp
37
+
38
+ def compare(a, b)
39
+ r = cmp.call a, b
40
+ r = a.created_at <=> b.created_at if r == 0
41
+ r
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ module Moneymarket
2
+ module Calculator
3
+ extend self
4
+
5
+ def quote(volume: nil, unit_price: nil)
6
+ base_currency = volume.currency
7
+ quote = ((unit_price.cents * volume.cents).to_d / base_currency.subunit_to_unit).ceil
8
+ Money.new quote, unit_price.currency
9
+ end
10
+
11
+ def volume(quote: nil, unit_price: nil, unit_currency: nil)
12
+ volume = ((quote.cents * unit_currency.subunit_to_unit).to_d / unit_price.cents).floor
13
+ Money.new volume, unit_currency
14
+ end
15
+
16
+ def fee(amount: nil, percent: nil)
17
+ result = (amount.cents * (percent.to_d / 100)).floor # fees always round to floor
18
+ Money.new result, amount.currency
19
+ end
20
+
21
+ def order_fee(order: nil, collected_amount: nil) # move this to command
22
+ collected_amount = order.collected_amount if collected_amount.nil?
23
+ fee_cents = (collected_amount.cents * (order.fee.to_d / 100)).floor
24
+ Money.new fee_cents, collected_amount.currency
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module Moneymarket
2
+ module Command
3
+ def self.new(*_attributes)
4
+ attr_names = []
5
+ attr_defaults = {}
6
+
7
+ _attributes.each do |att|
8
+ if att.is_a? Hash
9
+ attr_defaults.merge att
10
+ attr_names += att.keys
11
+ else
12
+ attr_names << att
13
+ end
14
+ end
15
+
16
+ Struct.new(*attr_names) do
17
+ define_method(:initialize) do |kwargs={}|
18
+ kwargs = attr_defaults.merge kwargs
19
+ attr_values = attr_names.map { |a| kwargs[a] }
20
+ super(*attr_values)
21
+ end
22
+
23
+ define_method(:perform) {}
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Trader
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,238 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moneymarket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ignacio Baixas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: money
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '6.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '6.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-nc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '2.11'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '2.11'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '4.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '4.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: terminal-notifier-guard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '1.6'
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: 1.6.1
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ~>
126
+ - !ruby/object:Gem::Version
127
+ version: '1.6'
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: 1.6.1
131
+ - !ruby/object:Gem::Dependency
132
+ name: pry
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ~>
136
+ - !ruby/object:Gem::Version
137
+ version: '0.10'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ~>
143
+ - !ruby/object:Gem::Version
144
+ version: '0.10'
145
+ - !ruby/object:Gem::Dependency
146
+ name: pry-remote
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ~>
150
+ - !ruby/object:Gem::Version
151
+ version: '0.1'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ~>
157
+ - !ruby/object:Gem::Version
158
+ version: '0.1'
159
+ - !ruby/object:Gem::Dependency
160
+ name: pry-byebug
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: '3.2'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ~>
171
+ - !ruby/object:Gem::Version
172
+ version: '3.2'
173
+ - !ruby/object:Gem::Dependency
174
+ name: pry-nav
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ~>
178
+ - !ruby/object:Gem::Version
179
+ version: '0.2'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ~>
185
+ - !ruby/object:Gem::Version
186
+ version: '0.2'
187
+ description: Yep
188
+ email:
189
+ - ignacio@platan.us
190
+ executables:
191
+ - moneymarket
192
+ extensions: []
193
+ extra_rdoc_files: []
194
+ files:
195
+ - bin/moneymarket
196
+ - lib/moneymarket.rb
197
+ - lib/moneymarket/commands/check_order_solvent.rb
198
+ - lib/moneymarket/commands/execute_match.rb
199
+ - lib/moneymarket/commands/limit_matches.rb
200
+ - lib/moneymarket/commands/match_order_to_slope.rb
201
+ - lib/moneymarket/core/account.rb
202
+ - lib/moneymarket/core/account_provider.rb
203
+ - lib/moneymarket/core/ask.rb
204
+ - lib/moneymarket/core/bid.rb
205
+ - lib/moneymarket/core/book.rb
206
+ - lib/moneymarket/core/market.rb
207
+ - lib/moneymarket/core/match.rb
208
+ - lib/moneymarket/core/order.rb
209
+ - lib/moneymarket/core/slope.rb
210
+ - lib/moneymarket/utils/calculator.rb
211
+ - lib/moneymarket/utils/command.rb
212
+ - lib/moneymarket/version.rb
213
+ homepage: https://github.com/surbtc/moneymarket
214
+ licenses:
215
+ - MIT
216
+ metadata: {}
217
+ post_install_message:
218
+ rdoc_options: []
219
+ require_paths:
220
+ - lib
221
+ required_ruby_version: !ruby/object:Gem::Requirement
222
+ requirements:
223
+ - - '>='
224
+ - !ruby/object:Gem::Version
225
+ version: '0'
226
+ required_rubygems_version: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - '>='
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ requirements: []
232
+ rubyforge_project:
233
+ rubygems_version: 2.6.1
234
+ signing_key:
235
+ specification_version: 4
236
+ summary: Moneymarket is a lightweight in-memory foreign exchange market engine
237
+ test_files: []
238
+ has_rdoc: