trade-o-matic 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/trader +4 -0
- data/lib/trade-o-matic/adapters/bitstamp_account.rb +63 -0
- data/lib/trade-o-matic/cli.rb +49 -0
- data/lib/trade-o-matic/converters/fixed_converter.rb +16 -0
- data/lib/trade-o-matic/converters/sync_converter.rb +33 -0
- data/lib/trade-o-matic/flows/ask_replicator_flow.rb +50 -0
- data/lib/trade-o-matic/generators/linear_generator.rb +37 -0
- data/lib/trade-o-matic/structs/ask_slope.rb +10 -0
- data/lib/trade-o-matic/structs/bid_slope.rb +10 -0
- data/lib/trade-o-matic/structs/converter.rb +8 -0
- data/lib/trade-o-matic/structs/currency.rb +63 -0
- data/lib/trade-o-matic/structs/currency_pair.rb +14 -0
- data/lib/trade-o-matic/structs/market.rb +28 -0
- data/lib/trade-o-matic/structs/order.rb +3 -0
- data/lib/trade-o-matic/structs/price.rb +41 -0
- data/lib/trade-o-matic/structs/slope.rb +147 -0
- data/lib/trade-o-matic/structs/transaction.rb +3 -0
- data/lib/trade-o-matic/version.rb +3 -0
- data/lib/trade-o-matic.rb +19 -0
- metadata +281 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9300715275fb3f78ca15a6d534d493f61c75ea7e
|
4
|
+
data.tar.gz: b3f66fd9b2f31736c86260f45c817ea8dc85dc01
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5208ae28f7c8d4da98d1a65bfdef0f1f9b2b1a09e4744ee79b87c32f104a6c9e71ceca7ea4045af8cba160c7b4ffca7f2b338b694cb514310957791e3fd24897
|
7
|
+
data.tar.gz: 4efe51fef441d0a483e38a766743268f87bf4fb9a968496763c85befd879aa6e05902b5732e24e6e525199e83c4e2435019ca16130341f5ed25f9e18cd7e0b5a
|
data/bin/trader
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Trader
|
5
|
+
|
6
|
+
# TODO: separate market information from account
|
7
|
+
|
8
|
+
class BitstampAccount
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
end
|
12
|
+
|
13
|
+
def market_snapshot
|
14
|
+
market = Market.new :BTC, :Bitstamp_USD
|
15
|
+
unpack_order_book market, fetch_raw_order_book
|
16
|
+
unpack_transactions market, fetch_raw_transactions
|
17
|
+
market
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_balance # XBT in an XBT/USD pair
|
24
|
+
Price.new :BTC, 0.0
|
25
|
+
end
|
26
|
+
|
27
|
+
def quote_balance # USD in an XBT/USD pair
|
28
|
+
Price.new :Bitstamp_USD, 20000.0
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_order
|
32
|
+
end
|
33
|
+
|
34
|
+
def cancel_order
|
35
|
+
end
|
36
|
+
|
37
|
+
def orders
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def fetch_raw_order_book
|
43
|
+
JSON.parse(RestClient.get "https://www.bitstamp.net/api/order_book/")
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_raw_transactions
|
47
|
+
JSON.parse(RestClient.get "https://www.bitstamp.net/api/transactions/")
|
48
|
+
end
|
49
|
+
|
50
|
+
def unpack_order_book(_market, _ob)
|
51
|
+
_ob['bids'].each { |o| _market.add_bid(o[0].to_f, o[1].to_f) }
|
52
|
+
_ob['asks'].each { |o| _market.add_ask(o[0].to_f, o[1].to_f) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def unpack_transactions(_market, _tx)
|
56
|
+
_tx.each do |t|
|
57
|
+
time = Time.at(t['date'].to_i)
|
58
|
+
market.add_buy(t['price'].to_f, t['amount'].to_f, time) if ['type'] == 0
|
59
|
+
market.add_sell(t['price'].to_f, t['amount'].to_f, time) if ['type'] == 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'gli'
|
2
|
+
|
3
|
+
module Trader
|
4
|
+
class CLI
|
5
|
+
extend GLI::App
|
6
|
+
|
7
|
+
program_desc 'Trader command line interface'
|
8
|
+
|
9
|
+
desc "Executes trade-o-matic using provided settings"
|
10
|
+
command [:run, :r] do |c|
|
11
|
+
|
12
|
+
c.desc "Specifies the configuration file"
|
13
|
+
c.flag [:c, :config]
|
14
|
+
|
15
|
+
c.desc "Start the server in verbose mode"
|
16
|
+
c.switch :dry, :default_value => false
|
17
|
+
|
18
|
+
c.action do |global_options,options,args|
|
19
|
+
|
20
|
+
require 'trade-o-matic/adapters/bitstamp_account'
|
21
|
+
require 'trade-o-matic/generators/linear_generator'
|
22
|
+
require 'trade-o-matic/flows/ask_replicator_flow'
|
23
|
+
|
24
|
+
Currency.register_conversion(:CLP, :Bitstamp_USD, 1.0/710.0)
|
25
|
+
|
26
|
+
source = Trader::BitstampAccount.new
|
27
|
+
target = nil
|
28
|
+
generator = LinearGenerator.new(spread: Price.new(:CLP, 10000.0), step: Price.new(:CLP, 1000.0))
|
29
|
+
|
30
|
+
flow = Trader::AskReplicatorFlow.new source, target, generator
|
31
|
+
|
32
|
+
puts 'Running ask replicator'
|
33
|
+
orders = flow.run options[:dry]
|
34
|
+
|
35
|
+
puts 'Generated the following orders :'
|
36
|
+
orders.each { |o| puts "#{o.price} [#{o.volume}]" }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
on_error do |exc|
|
41
|
+
puts exc.to_s
|
42
|
+
puts exc.backtrace
|
43
|
+
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
exit run(ARGV)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Trader
|
2
|
+
|
3
|
+
class SyncConverter < Converter
|
4
|
+
|
5
|
+
attr_reader :ttl
|
6
|
+
|
7
|
+
def initialize(_ttl, &_block)
|
8
|
+
@ttl = _ttl
|
9
|
+
@block = _block
|
10
|
+
end
|
11
|
+
|
12
|
+
def expired?
|
13
|
+
@last_sync < Time.new - @ttl
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert(_value, _from, _to)
|
17
|
+
rate = sync_rate
|
18
|
+
_value * rate
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def sync_rate
|
24
|
+
if @last_sync.nil? or expired?
|
25
|
+
@rate = @block.call
|
26
|
+
@last_sync = Time.now
|
27
|
+
end
|
28
|
+
|
29
|
+
@rate
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Trader
|
2
|
+
|
3
|
+
class AskReplicatorFlow
|
4
|
+
|
5
|
+
def initialize(_source, _target, _generator)
|
6
|
+
@source = _source
|
7
|
+
@target = _target
|
8
|
+
@generator = _generator
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(_dry)
|
12
|
+
|
13
|
+
# TODO: assert that both source and target base currencies are the same.
|
14
|
+
|
15
|
+
market = source.market_snapshot
|
16
|
+
|
17
|
+
skip_volume = market.ask_slope.volume 60
|
18
|
+
|
19
|
+
start_price = market.ask_slope.price skip_volume
|
20
|
+
|
21
|
+
available_volume = market.ask_slope.assess source.quote_balance, skip_volume # TODO: check
|
22
|
+
|
23
|
+
# available_volume = target.base_balance if target.base_balance < available_volume
|
24
|
+
|
25
|
+
orders = generator.ask start_price, available_volume
|
26
|
+
|
27
|
+
orders = adjust_orders_to_slope orders, market.ask_slope
|
28
|
+
|
29
|
+
# orders.each { |o| o.price.convert(target.quote_currency) }
|
30
|
+
|
31
|
+
# executed = target_position.sync orders
|
32
|
+
# executed.each do |order|
|
33
|
+
|
34
|
+
# end
|
35
|
+
|
36
|
+
# TODO: transform orders price to target currency
|
37
|
+
|
38
|
+
# TODO: sync orders
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :source, :target, :generator
|
45
|
+
|
46
|
+
def adjust_orders_to_slope(_orders, _slope)
|
47
|
+
_orders
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Trader
|
2
|
+
class LinearGenerator
|
3
|
+
|
4
|
+
def initialize(_options)
|
5
|
+
@price_spread = _options[:spread]
|
6
|
+
@price_step = _options[:step]
|
7
|
+
end
|
8
|
+
|
9
|
+
def bid(_start_price, _volume)
|
10
|
+
generate _start_price, _volume, -1
|
11
|
+
end
|
12
|
+
|
13
|
+
def ask(_start_price, _volume)
|
14
|
+
generate _start_price, _volume, 1
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def generate(_start_price, _volume, _mult)
|
20
|
+
buckets = (@price_spread.amount / @price_step.amount).floor
|
21
|
+
|
22
|
+
# make sure price step is using the same currency as generated prices
|
23
|
+
conv_price_step = @price_step.convert(_start_price.currency).amount
|
24
|
+
|
25
|
+
buckets.floor.times.map do |i|
|
26
|
+
price = _start_price.amount + _mult * conv_price_step * i
|
27
|
+
volume = _volume.amount / buckets
|
28
|
+
|
29
|
+
Order.new(
|
30
|
+
Price.new(_start_price.currency, price),
|
31
|
+
Price.new(_volume.currency, volume)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Trader
|
2
|
+
class Currency
|
3
|
+
|
4
|
+
def self.register_conversion(_to, _from, _converter=nil, &_block)
|
5
|
+
_to = _to.code if _to.is_a? Currency
|
6
|
+
_from = _from.code if _from.is_a? Currency
|
7
|
+
|
8
|
+
if !_block.nil?
|
9
|
+
_converter = SyncConverter.new(300, &_block)
|
10
|
+
elsif _converter.is_a? Integer or _converter.is_a? Float
|
11
|
+
_converter = FixedConverter.new(_converter)
|
12
|
+
end
|
13
|
+
|
14
|
+
converters["#{_to}-#{_from}"] = _converter
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.for_code(_code)
|
18
|
+
registry[_code]
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :code
|
22
|
+
|
23
|
+
def initialize(_code)
|
24
|
+
@code = _code
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert(_value, _currency)
|
28
|
+
_currency = _currency.code if _currency.is_a? Currency
|
29
|
+
converter_for(code, _currency).convert(_value, code, _currency)
|
30
|
+
end
|
31
|
+
|
32
|
+
def unpack(_value, _options={})
|
33
|
+
_options = { default: _options } unless _options.is_a? Hash
|
34
|
+
|
35
|
+
if _value.is_a? Price
|
36
|
+
raise StandardError, "Expected value currency to be #{code} (was #{_value.currency.code})" if _value.currency != self
|
37
|
+
_value.amount
|
38
|
+
elsif _value.nil?
|
39
|
+
_options[:default]
|
40
|
+
elsif _options.fetch(:strict, true)
|
41
|
+
raise StandardError, "Must provide a currency bound price"
|
42
|
+
else
|
43
|
+
_value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def self.registry
|
50
|
+
@@registry ||= Hash.new { |h,k| h[k] = self.new(k.to_sym) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.converters
|
54
|
+
@@converters ||= Hash.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def converter_for(_from, _to)
|
58
|
+
cv = self.class.converters["#{_from}-#{_to}"]
|
59
|
+
raise StandardError, "No converter registered for #{_from}/#{_to}" if cv.nil?
|
60
|
+
cv
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Trader
|
2
|
+
class CurrencyPair
|
3
|
+
|
4
|
+
attr_reader :base, :quote
|
5
|
+
|
6
|
+
def initialize(_base, _quote)
|
7
|
+
_base = Currency.for_code _base unless _base.is_a? Currency
|
8
|
+
_quote = Currency.for_code _quote unless _quote.is_a? Currency
|
9
|
+
|
10
|
+
@base = _base
|
11
|
+
@quote = _quote
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Trader
|
2
|
+
class Market
|
3
|
+
|
4
|
+
attr_reader :pair, :ask_slope, :bid_slope
|
5
|
+
|
6
|
+
def initialize(_base, _quote)
|
7
|
+
@pair = CurrencyPair.new _base, _quote
|
8
|
+
@ask_slope = AskSlope.new @pair
|
9
|
+
@bid_slope = BidSlope.new @pair
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_bid(_price, _volume)
|
13
|
+
@bid_slope.add_order(_price, _volume)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_ask(_price, _volume)
|
17
|
+
@ask_slope.add_order(_price, _volume)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_sell(_price, _volume, _time)
|
21
|
+
@bid_slope.add_transaction(_price, _volume, _time)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_buy(_price, _volume, _time)
|
25
|
+
@bid_slope.add_transaction(_price, _volume, _time)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Trader
|
2
|
+
class Price
|
3
|
+
|
4
|
+
attr_reader :currency, :amount
|
5
|
+
|
6
|
+
def initialize(_currency, _amount)
|
7
|
+
_currency = Currency.for_code(_currency) unless _currency.is_a? Currency
|
8
|
+
|
9
|
+
@currency = _currency
|
10
|
+
@amount = _amount
|
11
|
+
end
|
12
|
+
|
13
|
+
def convert(_other_currency)
|
14
|
+
_other_currency = Currency.for _other_currency unless _other_currency.is_a? Currency
|
15
|
+
|
16
|
+
return self if _other_currency == currency
|
17
|
+
|
18
|
+
new_amount = @currency.convert amount, _other_currency
|
19
|
+
Price.new _other_currency, new_amount
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"#{amount} #{currency.code}"
|
24
|
+
end
|
25
|
+
|
26
|
+
[:<, :<=, :>=, :>, :==, '<=>'].each do |op|
|
27
|
+
define_method(op) do |_other|
|
28
|
+
_other = currency.unpack(_other)
|
29
|
+
amount.public_send(op, _other)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
[:+, :-, :*, :/].each do |op|
|
34
|
+
define_method(op) do |_other|
|
35
|
+
_other = currency.unpack(_other)
|
36
|
+
Price.new currency, amount.public_send(op, _other)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Trader
|
2
|
+
class Slope
|
3
|
+
|
4
|
+
attr_reader :pair
|
5
|
+
|
6
|
+
def initialize(_pair, _ref_time=nil)
|
7
|
+
@pair = _pair
|
8
|
+
@orders = []
|
9
|
+
@transactions = []
|
10
|
+
@orders_sorted = false
|
11
|
+
@ref_time = _ref_time || Time.now
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_order(_price, _volume)
|
15
|
+
@orders_sorted = false
|
16
|
+
@orders << Order.new(
|
17
|
+
Price.new(pair.quote, _price),
|
18
|
+
Price.new(pair.base, _volume),
|
19
|
+
)
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_transaction(_price, _volume, _time)
|
24
|
+
@transactions << Transaction.new(
|
25
|
+
Price.new(pair.quote, _price),
|
26
|
+
Price.new(pair.base, _volume),
|
27
|
+
_time
|
28
|
+
)
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def volume(_period_seconds)
|
33
|
+
ref_time = @ref_time - _period_seconds
|
34
|
+
amount = @transactions.inject(0.0) do |r, trx|
|
35
|
+
if trx.time >= ref_time
|
36
|
+
r + trx.volume.amount
|
37
|
+
else
|
38
|
+
r
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Price.new pair.base, amount
|
43
|
+
end
|
44
|
+
|
45
|
+
def price(_skip_volume=nil)
|
46
|
+
_skip_volume = pair.base.unpack _skip_volume, 0.0
|
47
|
+
|
48
|
+
slice(_skip_volume).first[0].price
|
49
|
+
end
|
50
|
+
|
51
|
+
def volume_for_price(_price, _skip_volume=nil)
|
52
|
+
_price = pair.quote.unpack _price
|
53
|
+
_skip_volume = pair.base.unpack _skip_volume, 0.0
|
54
|
+
|
55
|
+
wt_price = 0.0
|
56
|
+
r_volume = 0.0
|
57
|
+
|
58
|
+
slice(_skip_volume).each do |order, volume|
|
59
|
+
if compare(order.price.amount, _price) == -1
|
60
|
+
x = (_price - wt_price) * r_volume / (order.price.amount - _price)
|
61
|
+
if x < volume
|
62
|
+
volume = x
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
wt_price = (wt_price * r_volume + order.price.amount * volume) / (r_volume + volume)
|
67
|
+
r_volume += volume
|
68
|
+
end
|
69
|
+
|
70
|
+
Price.new pair.base, r_volume
|
71
|
+
end
|
72
|
+
|
73
|
+
def quote(_volume, _skip_volume=nil)
|
74
|
+
_volume = pair.base.unpack _volume, 0.0
|
75
|
+
_skip_volume = pair.base.unpack _skip_volume, 0.0
|
76
|
+
|
77
|
+
total_price = 0.0
|
78
|
+
slice(_skip_volume, _volume).each do |order, order_volume|
|
79
|
+
total_price += order_volume * order.price.amount
|
80
|
+
end
|
81
|
+
|
82
|
+
Price.new pair.quote, total_price
|
83
|
+
end
|
84
|
+
|
85
|
+
def assess(_amount, _skip_volume=nil)
|
86
|
+
_amount = pair.quote.unpack _amount
|
87
|
+
_skip_volume = pair.base.unpack _skip_volume, 0.0
|
88
|
+
|
89
|
+
total_volume = 0.0
|
90
|
+
slice(_skip_volume).each do |order, volume|
|
91
|
+
order_quote = order.price.amount * volume
|
92
|
+
if order_quote > _amount
|
93
|
+
total_volume += _amount / order.price.amount
|
94
|
+
break
|
95
|
+
else
|
96
|
+
total_volume += volume
|
97
|
+
_amount -= order_quote
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
Price.new pair.base, total_volume
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
attr_reader :transactions
|
107
|
+
|
108
|
+
def orders
|
109
|
+
unless @orders_sorted
|
110
|
+
sort_by_relevance @orders
|
111
|
+
@orders_sorted = true
|
112
|
+
end
|
113
|
+
|
114
|
+
@orders
|
115
|
+
end
|
116
|
+
|
117
|
+
def slice(_skip_volume, _volume=nil)
|
118
|
+
return to_enum(:slice, _skip_volume, _volume) unless block_given?
|
119
|
+
|
120
|
+
orders.each do |order|
|
121
|
+
if order.volume.amount >= _skip_volume
|
122
|
+
volume = order.volume.amount - _skip_volume
|
123
|
+
|
124
|
+
unless _volume.nil?
|
125
|
+
volume = _volume if _volume < volume
|
126
|
+
_volume -= volume
|
127
|
+
end
|
128
|
+
|
129
|
+
yield order, volume
|
130
|
+
break if _volume == 0.0
|
131
|
+
_skip_volume = 0.0
|
132
|
+
else
|
133
|
+
_skip_volume -= order.volume.amount
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def sort_by_relevance(_orders)
|
139
|
+
_orders.sort! { |a, b| compare a.price.amount, b.price.amount }
|
140
|
+
end
|
141
|
+
|
142
|
+
def compare(_price_a, _price_b)
|
143
|
+
# abstract
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "trade-o-matic/version"
|
2
|
+
|
3
|
+
require 'trade-o-matic/structs/currency'
|
4
|
+
require 'trade-o-matic/structs/currency_pair'
|
5
|
+
require 'trade-o-matic/structs/converter'
|
6
|
+
require 'trade-o-matic/structs/price'
|
7
|
+
require 'trade-o-matic/structs/order'
|
8
|
+
require 'trade-o-matic/structs/transaction'
|
9
|
+
require 'trade-o-matic/structs/market'
|
10
|
+
require 'trade-o-matic/structs/slope'
|
11
|
+
require 'trade-o-matic/structs/ask_slope'
|
12
|
+
require 'trade-o-matic/structs/bid_slope'
|
13
|
+
|
14
|
+
require 'trade-o-matic/converters/fixed_converter'
|
15
|
+
require 'trade-o-matic/converters/sync_converter'
|
16
|
+
|
17
|
+
module Trader
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trade-o-matic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ignacio Baixas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gli
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.12'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.12'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: inquirer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rainbow
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry-byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rest-client
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.6'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '10.4'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '10.4'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.1'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.1'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec-nc
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.2'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.2'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: guard
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.11'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.11'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: guard-rspec
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ~>
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '4.5'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ~>
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '4.5'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: terminal-notifier-guard
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.6'
|
174
|
+
- - '>='
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 1.6.1
|
177
|
+
type: :development
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ~>
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '1.6'
|
184
|
+
- - '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: 1.6.1
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: pry
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ~>
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0.10'
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ~>
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0.10'
|
201
|
+
- !ruby/object:Gem::Dependency
|
202
|
+
name: pry-remote
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - ~>
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '0.1'
|
208
|
+
type: :development
|
209
|
+
prerelease: false
|
210
|
+
version_requirements: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ~>
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0.1'
|
215
|
+
- !ruby/object:Gem::Dependency
|
216
|
+
name: pry-nav
|
217
|
+
requirement: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ~>
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0.2'
|
222
|
+
type: :development
|
223
|
+
prerelease: false
|
224
|
+
version_requirements: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - ~>
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: '0.2'
|
229
|
+
description: Yep
|
230
|
+
email:
|
231
|
+
- ignacio@platan.us
|
232
|
+
executables:
|
233
|
+
- trader
|
234
|
+
extensions: []
|
235
|
+
extra_rdoc_files: []
|
236
|
+
files:
|
237
|
+
- bin/trader
|
238
|
+
- lib/trade-o-matic.rb
|
239
|
+
- lib/trade-o-matic/adapters/bitstamp_account.rb
|
240
|
+
- lib/trade-o-matic/cli.rb
|
241
|
+
- lib/trade-o-matic/converters/fixed_converter.rb
|
242
|
+
- lib/trade-o-matic/converters/sync_converter.rb
|
243
|
+
- lib/trade-o-matic/flows/ask_replicator_flow.rb
|
244
|
+
- lib/trade-o-matic/generators/linear_generator.rb
|
245
|
+
- lib/trade-o-matic/structs/ask_slope.rb
|
246
|
+
- lib/trade-o-matic/structs/bid_slope.rb
|
247
|
+
- lib/trade-o-matic/structs/converter.rb
|
248
|
+
- lib/trade-o-matic/structs/currency.rb
|
249
|
+
- lib/trade-o-matic/structs/currency_pair.rb
|
250
|
+
- lib/trade-o-matic/structs/market.rb
|
251
|
+
- lib/trade-o-matic/structs/order.rb
|
252
|
+
- lib/trade-o-matic/structs/price.rb
|
253
|
+
- lib/trade-o-matic/structs/slope.rb
|
254
|
+
- lib/trade-o-matic/structs/transaction.rb
|
255
|
+
- lib/trade-o-matic/version.rb
|
256
|
+
homepage: https://github.com/surbtc/trade-o-matic
|
257
|
+
licenses:
|
258
|
+
- MIT
|
259
|
+
metadata: {}
|
260
|
+
post_install_message:
|
261
|
+
rdoc_options: []
|
262
|
+
require_paths:
|
263
|
+
- lib
|
264
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
265
|
+
requirements:
|
266
|
+
- - '>='
|
267
|
+
- !ruby/object:Gem::Version
|
268
|
+
version: '0'
|
269
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
270
|
+
requirements:
|
271
|
+
- - '>='
|
272
|
+
- !ruby/object:Gem::Version
|
273
|
+
version: '0'
|
274
|
+
requirements: []
|
275
|
+
rubyforge_project:
|
276
|
+
rubygems_version: 2.4.8
|
277
|
+
signing_key:
|
278
|
+
specification_version: 4
|
279
|
+
summary: Trade-O-Matic is a trade automation framework
|
280
|
+
test_files: []
|
281
|
+
has_rdoc:
|