trade-o-matic 0.2.1 → 0.3.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: 74776e7f65da3df4d74c5ab9dd6e644bd3921f55
4
- data.tar.gz: 8800ca9874d710757acb209fa72f891b5dd93435
3
+ metadata.gz: 69c3f0ffd768200acac1e0ccd836c5daaac08e59
4
+ data.tar.gz: 7e41570aa4c2a894861134cb50a670787384fe40
5
5
  SHA512:
6
- metadata.gz: 756a98df8523873f62a16a4d777e82d8588123ab912415c3dc88a908e3b879927936032eee1df52721c5f5fac486668f91811fea8c32a98e36755aae39c1b7e9
7
- data.tar.gz: 1078355996be86bc4a7432afd9b02d820058cca913a41bf0b768a32131d91d5453c4460e026365f7558fddaa168e0df258bc96b01f12d904d4ae8647bd5564b1
6
+ metadata.gz: 3dc8f24f61ba90595a9e5a39dfdd66f753762f3b32fb749e873f299f57ff6156bab77780180811446d5ae576ee1a45fc8e1f2efec4e9d9660c3b96ec5f0687e4
7
+ data.tar.gz: 470ce3b882cd7f45fee5330ccbd258c382e494be8836bf5392c70aaf0736f965de6f0741877ae820748002d55bb80ca5ab580944df440aa9f742d38a11e75d0d
@@ -21,8 +21,8 @@ module Trader
21
21
  class BitstampOrder < RawAccountOrder
22
22
  attr_mapped(:id, 'raw') # use original order information as id
23
23
  attr_mapped(:pair) { |r| MAIN_MARKET }
24
- attr_mapped(:price) { |r| r['raw']['price'].to_f }
25
- attr_mapped(:volume) { |r| r['raw']['amount'].to_f }
24
+ attr_mapped(:price) { |r| r['raw']['price'] }
25
+ attr_mapped(:volume) { |r| r['raw']['amount'] }
26
26
  attr_mapped(:executed_volume)
27
27
  attr_mapped(:instruction) { |r| r['raw']['type'] == 0 ? Order::BID : Order::ASK }
28
28
 
@@ -31,7 +31,7 @@ module Trader
31
31
  when 'Open'
32
32
  AccountOrder::OPEN
33
33
  when 'Finished'
34
- r['executed_volume'] < r['raw']['amount'].to_f ? AccountOrder::CANCELED : AccountOrder::CLOSED
34
+ r['executed_volume'] < big(r['raw']['amount']) ? AccountOrder::CANCELED : AccountOrder::CLOSED
35
35
  else
36
36
  AccountOrder::PENDING
37
37
  end
@@ -56,12 +56,12 @@ module Trader
56
56
  _book.prepare Time.now
57
57
 
58
58
  ob = execute_request(nil, 'order_book')
59
- ob['bids'].each { |o| _book.add_bid(o[0].to_f, o[1].to_f) }
60
- ob['asks'].each { |o| _book.add_ask(o[0].to_f, o[1].to_f) }
59
+ ob['bids'].each { |o| _book.add_bid(o[0], o[1]) }
60
+ ob['asks'].each { |o| _book.add_ask(o[0], o[1]) }
61
61
 
62
62
  tx = execute_request(nil, 'transactions')
63
63
  tx.each do |t|
64
- _book.add_transaction t['price'].to_f, t['amount'].to_f, Time.at(t['date'].to_i)
64
+ _book.add_transaction t['price'], t['amount'], Time.at(t['date'].to_i)
65
65
  end
66
66
  end
67
67
 
@@ -75,9 +75,9 @@ module Trader
75
75
  raw = execute_request(_session || session, 'balance')
76
76
 
77
77
  if _currency == BASE_CUR
78
- return BackendBalance.new raw['btc_balance'].to_f, raw['btc_available'].to_f
78
+ return BackendBalance.new raw['btc_balance'], raw['btc_available']
79
79
  else
80
- return BackendBalance.new raw['usd_balance'].to_f, raw['usd_available'].to_f
80
+ return BackendBalance.new raw['usd_balance'], raw['usd_available']
81
81
  end
82
82
  end
83
83
 
@@ -95,7 +95,7 @@ module Trader
95
95
  normalize_raw_order execute_request(
96
96
  _session || session,
97
97
  _type == Order::BID ? 'buy' : 'sell',
98
- { amount: _volume, price: _price }
98
+ { amount: _volume.to_f, price: _price.to_f }
99
99
  )
100
100
  end
101
101
 
@@ -146,14 +146,14 @@ module Trader
146
146
  def normalize_raw_order(_order)
147
147
  BitstampOrder.new({
148
148
  'raw' => _order,
149
- 'executed_volume' => 0.0,
149
+ 'executed_volume' => big(0),
150
150
  'status' => 'In Queue'
151
151
  })
152
152
  end
153
153
 
154
154
  def normalize_raw_order_status(_id, _status)
155
- executed_volume = _status['transactions'].inject(0.0) { |r, t| r + t['btc'].to_f }
156
- executed_price = _status['transactions'].inject(0.0) { |r, t| r + (t['price'].to_f * t['btc'].to_f) }
155
+ executed_volume = _status['transactions'].inject(big(0)) { |r, t| r + big(t['btc']) }
156
+ executed_price = _status['transactions'].inject(big(0)) { |r, t| r + (big(t['price']) * big(t['btc'])) }
157
157
 
158
158
  BitstampOrder.new({
159
159
  'raw' => _id,
@@ -162,5 +162,9 @@ module Trader
162
162
  'status' => _status['status']
163
163
  })
164
164
  end
165
+
166
+ def big(_string)
167
+ BigDecimal.new _string
168
+ end
165
169
  end
166
170
  end
@@ -10,12 +10,12 @@ module Trader
10
10
  _book.prepare Time.now
11
11
 
12
12
  ob = fetch_raw_order_book _book.pair
13
- ob['bids'].each { |o| _book.add_bid(o[0].to_f, o[1].to_f) }
14
- ob['asks'].each { |o| _book.add_ask(o[0].to_f, o[1].to_f) }
13
+ ob['bids'].each { |o| _book.add_bid(o[0], o[1]) }
14
+ ob['asks'].each { |o| _book.add_ask(o[0], o[1]) }
15
15
 
16
16
  tx = fetch_raw_transactions _book.pair
17
17
  tx['recentTrades'].each do |t|
18
- _book.add_transaction t['price'].to_f, t['amount'].to_f, Time.parse(t['timestamp'])
18
+ _book.add_transaction t['price'], t['amount'], Time.parse(t['timestamp'])
19
19
  end
20
20
  end
21
21
 
@@ -28,16 +28,16 @@ module Trader
28
28
  end
29
29
 
30
30
  class SurbtcBalanceBTC < RawBalance
31
- attr_mapped(:amount) { |r| r['amount'].to_f }
32
- attr_mapped(:available_amount) { |r| r['available_amount'].to_f }
31
+ attr_mapped(:amount) { |r| r['amount'] }
32
+ attr_mapped(:available_amount) { |r| r['available_amount'] }
33
33
  end
34
34
 
35
35
  class SurbtcOrder < RawAccountOrder
36
36
  attr_mapped(:id)
37
37
  attr_mapped(:pair) { |r| MAIN_MARKET }
38
38
  attr_mapped(:price) { |r| r['limit'] }
39
- attr_mapped(:volume) { |r| r['original_amount'].to_f }
40
- attr_mapped(:executed_volume) { |r| r['total_exchanged'].to_f }
39
+ attr_mapped(:volume) { |r| r['original_amount'] }
40
+ attr_mapped(:executed_volume) { |r| r['total_exchanged'] }
41
41
  attr_mapped(:instruction) { |r| TYPE_MAP[r['type'].downcase] }
42
42
  attr_mapped(:status) { |r| STATUS_MAP[r['state']] }
43
43
  attr_mapped(:limit?) { |r| r['price_type'] == 'limit' }
@@ -132,14 +132,14 @@ module Trader
132
132
  def build_order_json(_price, _volume, _instruction)
133
133
  if _price.nil?
134
134
  {
135
- amount: _volume,
135
+ amount: _volume.to_i,
136
136
  type: _instruction == Order::BID ? 'bid' : 'ask',
137
137
  price_type: 'market'
138
138
  }
139
139
  else
140
140
  {
141
- limit: _price,
142
- amount: _volume,
141
+ limit: _price.to_i,
142
+ amount: _volume.to_i,
143
143
  type: _instruction == Order::BID ? 'bid' : 'ask',
144
144
  price_type: 'limit'
145
145
  }
@@ -6,8 +6,12 @@ module Trader
6
6
  @converters = _converters
7
7
  end
8
8
 
9
- def rate
10
- converters.inject(1.0) { |r, c| c.rate * r }
9
+ def apply(_value, _invert=false)
10
+ unless _invert
11
+ converters.inject(_value) { |r, c| c.apply(r, false) }
12
+ else
13
+ converters.reverse.inject(_value) { |r, c| c.apply(r, true) }
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -1,9 +1,22 @@
1
1
  module Trader
2
2
  class FixedConverter < Converter
3
- attr_accessor :rate
3
+ attr_reader :rate
4
4
 
5
5
  def initialize(_rate)
6
6
  @rate = _rate
7
+ # TODO: maybe require rate to be a Standard.amount
8
+ end
9
+
10
+ def current_rate
11
+ rate
12
+ end
13
+
14
+ def apply(_value, _invert=false)
15
+ if _invert
16
+ _value / rate
17
+ else
18
+ _value * rate
19
+ end
7
20
  end
8
21
  end
9
22
  end
@@ -1,13 +1,18 @@
1
1
  module Trader
2
2
  class InverseConverter < Converter
3
- attr_reader :inverse
3
+ attr_reader :other
4
4
 
5
- def initialize(_inverse)
6
- @inverse = _inverse
5
+ def initialize(_other)
6
+ @other = _other
7
7
  end
8
8
 
9
- def rate
10
- 1.0 / inverse.rate
9
+ def current_rate
10
+ return nil if other.current_rate.nil?
11
+ 1.0 / other.current_rate
12
+ end
13
+
14
+ def apply(_value, _invert=false)
15
+ @other.apply(_value, !_invert)
11
16
  end
12
17
  end
13
18
  end
@@ -13,7 +13,7 @@ module Trader
13
13
  json_string = RestClient.get _url
14
14
  json = JSON.parse json_string
15
15
  value = _path.inject(json) { |r, k| r[k] }
16
- value.to_f
16
+ Standard.amount value
17
17
  end
18
18
  end
19
19
  end
@@ -1,8 +1,9 @@
1
1
  module Trader
2
- class SyncConverter < Converter
2
+ class SyncConverter < FixedConverter
3
3
  attr_reader :ttl
4
4
 
5
5
  def initialize(_ttl, &_block)
6
+ super nil
6
7
  @ttl = _ttl
7
8
  @block = _block
8
9
  end
@@ -16,7 +17,6 @@ module Trader
16
17
  @rate = @block.call
17
18
  @last_sync = Time.now
18
19
  end
19
-
20
20
  @rate
21
21
  end
22
22
  end
@@ -0,0 +1,13 @@
1
+ require 'bigdecimal'
2
+
3
+ module Trader
4
+ module Standard
5
+ extend self
6
+
7
+ def amount(_number)
8
+ return _number if _number.is_a? BigDecimal
9
+ return BigDecimal.new _number.to_s if _number.is_a? Float
10
+ BigDecimal.new _number
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,12 @@
1
1
  module Trader
2
2
  class Converter
3
- def rate
4
- raise NotImplementedError, 'rate method not implemented'
3
+
4
+ def current_rate
5
+ nil # current rate not available
6
+ end
7
+
8
+ def apply(_value, _invert=false)
9
+ raise NotImplementedError, 'apply method not implemented'
5
10
  end
6
11
  end
7
12
  end
@@ -1,12 +1,15 @@
1
1
  module Trader
2
2
  class Currency
3
- def self.register_conversion(_from, _to, _converter=nil, &_block)
3
+ def self.register_conversion(_from, _to, _converter=nil, _options={}, &_block)
4
4
  if !_block.nil?
5
- _converter = SyncConverter.new(60, &_block)
6
- elsif _converter.is_a? Integer or _converter.is_a? Float
5
+ _options = _converter || {}
6
+ _converter = SyncConverter.new(_options.fetch(:interval, 60.0), &_block)
7
+ elsif _converter.is_a? Numeric
7
8
  _converter = FixedConverter.new(_converter)
8
9
  end
9
10
 
11
+ _converter = inverse(_converter) if _options[:inverse]
12
+
10
13
  converters[_from.to_sym][_to.to_sym] = _converter
11
14
  reset_comp_cache
12
15
  end
@@ -78,7 +81,8 @@ module Trader
78
81
  end
79
82
 
80
83
  def convert(_value, _to)
81
- klass.converter_for!(code, _to.to_sym).rate * _value
84
+ converter = klass.converter_for!(code, _to.to_sym)
85
+ converter.apply _value
82
86
  end
83
87
 
84
88
  def pack(_value)
@@ -100,11 +104,11 @@ module Trader
100
104
  _value.amount
101
105
  end
102
106
  elsif _value.nil?
103
- _options[:default]
107
+ Standard.amount _options[:default]
104
108
  elsif _options.fetch(:strict, true)
105
109
  raise ArgumentError, "Must provide a currency bound price"
106
110
  else
107
- _value
111
+ Standard.amount _value
108
112
  end
109
113
  end
110
114
 
@@ -161,6 +165,14 @@ module Trader
161
165
  end)
162
166
  end
163
167
 
168
+ def self.inverse(_converter)
169
+ if _converter.is_a? InverseConverter
170
+ _converter.other
171
+ else
172
+ InverseConverter.new _converter
173
+ end
174
+ end
175
+
164
176
  def klass
165
177
  self.class
166
178
  end
@@ -4,7 +4,7 @@ module Trader
4
4
 
5
5
  def initialize(_currency, _amount)
6
6
  @currency = Currency.for_code _currency
7
- @amount = _amount
7
+ @amount = Standard.amount _amount
8
8
  end
9
9
 
10
10
  def pack(_amount)
@@ -37,6 +37,5 @@ module Trader
37
37
  Price.new currency, amount.public_send(op, _other)
38
38
  end
39
39
  end
40
-
41
40
  end
42
41
  end
@@ -7,8 +7,8 @@ module Trader
7
7
  type = conv['type'] || detect_type(conv)
8
8
  converter = send "configure_yaml_#{type}", conv
9
9
 
10
- Currency.register_conversion conv['from'], conv['to'], converter
11
- Currency.register_conversion conv['to'], conv['from'], invert(converter) if conv['symetric']
10
+ Currency.register_conversion conv['from'], conv['to'], converter, inverse: !!conv['inverse']
11
+ Currency.register_conversion conv['to'], conv['from'], converter, inverse: !conv['inverse'] if conv['symetric']
12
12
  end
13
13
  end
14
14
 
@@ -1,3 +1,3 @@
1
1
  module Trader
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/trade-o-matic.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "trade-o-matic/version"
2
+ require 'trade-o-matic/standard'
2
3
 
3
4
  require 'trade-o-matic/structs/currency'
4
5
  require 'trade-o-matic/structs/currency_pair'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trade-o-matic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ignacio Baixas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-11 00:00:00.000000000 Z
11
+ date: 2016-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -257,6 +257,7 @@ files:
257
257
  - lib/trade-o-matic/core/market.rb
258
258
  - lib/trade-o-matic/core/market_loader.rb
259
259
  - lib/trade-o-matic/services/backend_factory.rb
260
+ - lib/trade-o-matic/standard.rb
260
261
  - lib/trade-o-matic/structs/ask_slope.rb
261
262
  - lib/trade-o-matic/structs/bid_slope.rb
262
263
  - lib/trade-o-matic/structs/book.rb