trade-o-matic 0.3.2 → 0.4.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: ffa9eaa9a1e1e4a7ae37faf694d4882fb95a356c
4
- data.tar.gz: c184b0499a3414f1155ef69ddd22717456093075
3
+ metadata.gz: 10edb6d47a3ca071570ab17ed6559306c6a3f1c3
4
+ data.tar.gz: 0fd5ae2dec38031376ec526f6dcd9050c012eb63
5
5
  SHA512:
6
- metadata.gz: 5f8ba8f453091a648e7f953f9f7375e55c1c223ea15508867122371786b414aa0c03c1c2b467aba83f5136a37dfdffa17c201b172b2d25012d12be8a67939ede
7
- data.tar.gz: c4caec6d3f480b81e0f81bc2e692cb63d4c8e0af80bc2883247ad826bbc8f5e35cb9ffe4fbcc294a9e1a1097e0ba8a40bf7ad2084dbb746d8815bd90bbf60371
6
+ metadata.gz: 7b6fdc892965766b66919c22e237fdb944fc1d81b6693c273e3d9e8b4644c556a1b317f46596e376b6b713dd2a4e581c97311ce64280a90001be91c506a44ad9
7
+ data.tar.gz: 27ebedede4d516d9c33b5e88a32854790adee9d66f7cf7a295518b73394646631760949ab5358917ae6ca8f3360a1532dce5fedd3cd7942cb7207d342582f7f6
@@ -1,6 +1,5 @@
1
1
  module Trader
2
2
  class RawResource
3
-
4
3
  def self.enforce_attr(*_attrs)
5
4
  _attrs.each do |att|
6
5
  define_method(att) do
@@ -26,6 +25,5 @@ module Trader
26
25
  def initialize(_raw)
27
26
  @raw = _raw
28
27
  end
29
-
30
28
  end
31
29
  end
@@ -0,0 +1,62 @@
1
+ require 'trade-o-matic/adapters/base/raw_account_order'
2
+ require 'trade-o-matic/adapters/base/raw_balance'
3
+
4
+ module Trader
5
+ class BaseBackend
6
+ attr_reader :name
7
+
8
+ def initialize(_name)
9
+ @name = _name
10
+ end
11
+
12
+ def get_available_markets
13
+ []
14
+ end
15
+
16
+ def fill_book(_book)
17
+ not_supported :book
18
+ end
19
+
20
+ def get_session(_credentials)
21
+ _credentials
22
+ end
23
+
24
+ def get_balance(_session, _currency)
25
+ not_supported :get_balance
26
+ end
27
+
28
+ def generate_endpoint(_session, _currency)
29
+ not_supported :deposit
30
+ end
31
+
32
+ def withdraw_to_endpoint(_session, _currency, _amount, _endpoint)
33
+ not_supported :withdraw
34
+ end
35
+
36
+ def get_orders(_session, _pair)
37
+ not_supported :list_orders
38
+ end
39
+
40
+ def create_order(_session, _pair, _volume, _price, _type)
41
+ not_supported :create_order
42
+ end
43
+
44
+ def fetch_order(_session, _id)
45
+ not_supported :fetch_order
46
+ end
47
+
48
+ def cancel_order(_session, _id)
49
+ not_supported :cancel_order
50
+ end
51
+
52
+ def not_supported(_feature)
53
+ raise NotSupportedError.new name, _feature
54
+ end
55
+
56
+ private
57
+
58
+ def error(_messsage)
59
+ raise BackendError.new name, _messsage
60
+ end
61
+ end
62
+ end
@@ -1,11 +1,9 @@
1
1
  require 'rest-client'
2
2
  require 'base64'
3
3
  require 'json'
4
- require 'trade-o-matic/adapters/base/raw_account_order'
5
- require 'trade-o-matic/adapters/base/raw_balance'
6
4
 
7
5
  module Trader
8
- class BitfinexBackend
6
+ class BitfinexBackend < BaseBackend
9
7
  BASE_CUR = Currency.for_code(:BTC)
10
8
  QUOTE_CUR = Currency.for_code(:BITFINEX_USD)
11
9
  MAIN_MARKET = CurrencyPair.new BASE_CUR, QUOTE_CUR
@@ -42,8 +40,8 @@ module Trader
42
40
  end
43
41
  end
44
42
 
45
- def initialize(_session=nil)
46
- @session = _session
43
+ def initialize
44
+ super :bitfinex
47
45
  end
48
46
 
49
47
  def get_available_markets
@@ -65,28 +63,29 @@ module Trader
65
63
  end
66
64
  end
67
65
 
68
- def get_session(_credentials)
69
- _credentials
66
+ def get_session(_cred)
67
+ raise AssertError, 'missing credentials' if !_cred.key?(:api_key) || !_cred.key?(:secret)
68
+ _cred
70
69
  end
71
70
 
72
71
  def get_balance(_session, _currency)
73
- raise "#{_currency} not supported" unless _currency == BASE_CUR || _currency == QUOTE_CUR
74
-
75
72
  raw = auth_post(_session, 'balances')
76
73
  wrap_balance raw, _currency
77
74
  end
78
75
 
79
- def get_orders(_session, _pair)
80
- raise 'market not supported' unless _pair == MAIN_MARKET
76
+ def withdraw_to_endpoint(_session, _currency, _amount, _endpoint)
77
+ not_supported "usd withdrawals" if _currency == QUOTE_CUR
78
+ execute_btc_withdraw(_session, _amount, _endpoint)
79
+ end
81
80
 
81
+ def get_orders(_session, _pair)
82
82
  raw = auth_post(_session, 'orders')
83
83
  raw = raw.select { |o| o['type'].include? 'limit' }
84
84
  raw.map { |o| wrap_order o }
85
85
  end
86
86
 
87
87
  def create_order(_session, _pair, _volume, _price, _type)
88
- raise 'market not supported' unless _pair == MAIN_MARKET
89
- raise 'market orders not supported' if _price.nil?
88
+ not_supported "market orders" if _price.nil?
90
89
 
91
90
  wrap_order auth_post(_session, 'order/new', {
92
91
  exchange: "bitfinex",
@@ -118,8 +117,6 @@ module Trader
118
117
  end
119
118
 
120
119
  def auth_post(_creds, _url, _data = {})
121
- raise ArgumentError if !_creds.key?(:api_key) or !_creds.key?(:secret)
122
-
123
120
  payload = build_payload("/v1/#{_url}", _data)
124
121
  headers = {
125
122
  'Content-Type' => 'application/json',
@@ -158,5 +155,23 @@ module Trader
158
155
  def wrap_order(_raw)
159
156
  OrderAdaptor.new _raw
160
157
  end
158
+
159
+ def execute_btc_withdraw(_session, _amount, _endpoint)
160
+ case _endpoint
161
+ when BitcoinAddress
162
+ auth_post(_session, 'withdraw', {
163
+ withdraw_type: 'bitcoin',
164
+ walletselected: 'exchange',
165
+ amount: _amount.to_s('F'),
166
+ address: _endpoint.address
167
+ })
168
+ else
169
+ not_supported "endpoint not supported"
170
+ end
171
+ end
172
+
173
+ def process_withdraw(_raw)
174
+ error _raw['message'] if _raw['status'] == 'error'
175
+ end
161
176
  end
162
177
  end
@@ -1,10 +1,8 @@
1
1
  require 'rest-client'
2
2
  require 'json'
3
- require 'trade-o-matic/adapters/base/raw_account_order'
4
- require 'trade-o-matic/adapters/base/raw_balance'
5
3
 
6
4
  module Trader
7
- class BitstampBackend
5
+ class BitstampBackend < BaseBackend
8
6
  BASE_CUR = Currency.for_code(:BTC)
9
7
  QUOTE_CUR = Currency.for_code(:BITSTAMP_USD)
10
8
  MAIN_MARKET = CurrencyPair.new BASE_CUR, QUOTE_CUR
@@ -42,8 +40,8 @@ module Trader
42
40
  end
43
41
  end
44
42
 
45
- def initialize(_session=nil)
46
- @session = _session
43
+ def initialize
44
+ super :bitstamp
47
45
  end
48
46
 
49
47
  def get_available_markets
@@ -65,13 +63,7 @@ module Trader
65
63
  end
66
64
  end
67
65
 
68
- def get_session(_credentials)
69
- _credentials
70
- end
71
-
72
66
  def get_balance(_session, _currency)
73
- raise "#{_currency} not supported" unless _currency == BASE_CUR || _currency == QUOTE_CUR
74
-
75
67
  raw = execute_request(_session || session, 'balance')
76
68
 
77
69
  if _currency == BASE_CUR
@@ -82,15 +74,12 @@ module Trader
82
74
  end
83
75
 
84
76
  def get_orders(_session, _pair)
85
- raise 'market not supported' unless _pair == MAIN_MARKET
86
-
87
77
  raw_orders = execute_request(_session || session, 'open_orders')
88
78
  raw_orders.map { |o| normalize_raw_order o }
89
79
  end
90
80
 
91
81
  def create_order(_session, _pair, _volume, _price, _type)
92
- raise 'market not supported' unless _pair == MAIN_MARKET
93
- raise 'market orders not supported' if _price.nil?
82
+ not_supported('market orders') if _price.nil?
94
83
 
95
84
  normalize_raw_order execute_request(
96
85
  _session || session,
@@ -107,10 +96,6 @@ module Trader
107
96
  )
108
97
  end
109
98
 
110
- def cancel_order(_session, _id)
111
- # TODO
112
- end
113
-
114
99
  private
115
100
 
116
101
  attr_reader :session
@@ -1,11 +1,10 @@
1
1
  require 'rest-client'
2
2
  require 'json'
3
- require 'trade-o-matic/adapters/base/raw_account_order'
4
3
  require 'rainbow'
5
4
  require 'rainbow/ext/string'
6
5
 
7
6
  module Trader
8
- class FakeBackend
7
+ class FakeBackend < BaseBackend
9
8
  class FakeBalance < Struct.new(:amount, :available_amount);
10
9
  end
11
10
 
@@ -46,6 +45,7 @@ module Trader
46
45
  end
47
46
 
48
47
  def initialize(_config=nil)
48
+ super :fake
49
49
  get_session(_config) unless _config.nil?
50
50
  end
51
51
 
@@ -1,8 +1,12 @@
1
1
  require 'json'
2
2
  require 'rainbow'
3
3
  require 'rainbow/ext/string'
4
- require 'trade-o-matic/adapters/base/raw_account_order'
5
- require 'trade-o-matic/adapters/base/raw_balance'
4
+
5
+ module Trader
6
+ # This is needed to prevent one of the subclass files from defining
7
+ # the class without the superclass.
8
+ class GameBackend < BaseBackend; end
9
+ end
6
10
 
7
11
  require 'trade-o-matic/adapters/game_backend/configuration'
8
12
  require 'trade-o-matic/adapters/game_backend/sfm'
@@ -40,6 +44,7 @@ module Trader
40
44
  attr_reader :verbose, :state
41
45
 
42
46
  def initialize
47
+ super :game
43
48
  @state = State.new
44
49
  end
45
50
 
@@ -81,7 +86,7 @@ module Trader
81
86
  end
82
87
 
83
88
  def get_session(_config)
84
- raise ArgumentError, 'must provide login information' if _config.nil? or _config[:name].nil?
89
+ raise AssertError, 'must provide login information' if _config.nil? or _config[:name].nil?
85
90
  _config[:name]
86
91
  end
87
92
 
@@ -3,7 +3,7 @@ require 'json'
3
3
  require 'time'
4
4
 
5
5
  module Trader
6
- class ItbitBackend
6
+ class ItbitBackend < BaseBackend
7
7
  def fill_book(_book)
8
8
  # TODO: consider book pair
9
9
 
@@ -1,10 +1,8 @@
1
1
  require 'rest-client'
2
2
  require 'json'
3
- require 'trade-o-matic/adapters/base/raw_account_order'
4
- require 'trade-o-matic/adapters/base/raw_balance'
5
3
 
6
4
  module Trader
7
- class SurbtcBackend
5
+ class SurbtcBackend < BaseBackend
8
6
  API_PREFIX = 'https://www.surbtc.com/api/v1'
9
7
 
10
8
  TYPE_MAP = {
@@ -43,16 +41,12 @@ module Trader
43
41
  attr_mapped(:limit?) { |r| r['price_type'] == 'limit' }
44
42
  end
45
43
 
46
- def get_available_markets
47
- [MAIN_MARKET]
48
- end
49
-
50
- def fill_book(_book)
51
- # TODO
44
+ def initialize
45
+ super :surbtc
52
46
  end
53
47
 
54
- def get_session(_credentials)
55
- _credentials
48
+ def get_available_markets
49
+ [MAIN_MARKET]
56
50
  end
57
51
 
58
52
  def get_balance(_session, _currency)
@@ -74,8 +68,6 @@ module Trader
74
68
  end
75
69
 
76
70
  def create_order(_session, _pair, _volume, _price, _instruction)
77
- raise 'market not supported' unless _pair == MAIN_MARKET
78
-
79
71
  res = resource_for "markets/#{market_code_for(_pair)}/orders", _session
80
72
 
81
73
  raw_order = postprocess res.post({
@@ -14,7 +14,7 @@ module Trader
14
14
 
15
15
  proxy_market = find_exact_market _pair
16
16
  proxy_market = find_compatible_market _pair if proxy_market.nil?
17
- raise StandardError, 'market not supported' if proxy_market.nil?
17
+ backend.not_supported _pair if proxy_market.nil?
18
18
 
19
19
  proxy = AccountProxy.new self, proxy_market, _pair
20
20
 
@@ -59,7 +59,7 @@ module Trader
59
59
  # TODO.
60
60
  end
61
61
 
62
- private
62
+ private
63
63
 
64
64
  attr_reader :session
65
65
 
@@ -70,6 +70,5 @@ module Trader
70
70
  def find_compatible_market(_pair)
71
71
  available_markets.find { |p| p.compatible_with? _pair }
72
72
  end
73
-
74
73
  end
75
74
  end
@@ -1,6 +1,5 @@
1
1
  module Trader
2
2
  class AccountOrder
3
-
4
3
  PENDING = :pending
5
4
  OPEN = :open
6
5
  CLOSED = :closed
@@ -81,7 +80,7 @@ module Trader
81
80
  status == CLOSED or status == CANCELED
82
81
  end
83
82
 
84
- private
83
+ private
85
84
 
86
85
  attr_reader :backend, :session, :forced_pair
87
86
 
@@ -94,6 +93,5 @@ module Trader
94
93
  return _price if forced_pair.nil?
95
94
  _price.convert_to forced_pair.quote
96
95
  end
97
-
98
96
  end
99
97
  end
@@ -1,6 +1,5 @@
1
1
  module Trader
2
2
  class AccountProxy
3
-
4
3
  attr_reader :account, :proxy, :pair
5
4
 
6
5
  def initialize(_account, _proxy, _pair)
@@ -1,6 +1,5 @@
1
1
  module Trader
2
2
  class Balance
3
-
4
3
  def initialize(_backend, _session, _currency, _forced_currency=nil)
5
4
  @backend = _backend
6
5
  @session = _session
@@ -37,15 +36,31 @@ module Trader
37
36
  end
38
37
 
39
38
  def refresh!
40
- self.raw = backend.get_balance(session, currency)
39
+ self.raw = backend.get_balance session, currency
41
40
  self
42
41
  end
43
42
 
44
- protected
43
+ def new_deposit_endpoint
44
+ backend.generate_endpoint session, original_currency
45
+ end
46
+
47
+ def withdraw(_amount, to: nil)
48
+ _amount = currency.pack _amount
49
+ _amount = _amount.convert_to original_currency
50
+
51
+ backend.withdraw_to_endpoint session, currency, _amount.amount, to
52
+ self
53
+ end
54
+
55
+ def transfer(_amount, to: nil)
56
+ withdraw _amount, to: to.new_deposit_endpoint
57
+ end
58
+
59
+ protected
45
60
 
46
61
  attr_accessor :raw
47
62
 
48
- private
63
+ private
49
64
 
50
65
  attr_reader :backend, :session, :forced_currency
51
66
 
@@ -11,9 +11,8 @@ module Trader
11
11
  Account.new backend, session
12
12
  end
13
13
 
14
- private
14
+ private
15
15
 
16
16
  attr_reader :backend
17
-
18
17
  end
19
18
  end
@@ -1,6 +1,5 @@
1
1
  module Trader
2
2
  class Market < Book
3
-
4
3
  attr_reader :backend
5
4
 
6
5
  def initialize(_backend, _pair)
@@ -24,6 +23,5 @@ module Trader
24
23
  backend.fill_book(book)
25
24
  self
26
25
  end
27
-
28
26
  end
29
27
  end
@@ -15,15 +15,16 @@ module Trader
15
15
  @markets ||= backend.get_available_markets
16
16
  end
17
17
 
18
- private
18
+ private
19
19
 
20
20
  def ensure_supported_market(_pair)
21
- raise ArgumentError, 'market not supported' unless has_market_for? _pair
21
+ backend.not_supported _pair unless has_market_for? _pair
22
22
  end
23
23
 
24
24
  def ensure_supported_currency(_currency)
25
- raise ArgumentError, 'currency not supported' unless available_markets.any? { |m| m.quote == _currency || m.base == _currency }
25
+ unless available_markets.any? { |m| m.quote == _currency || m.base == _currency }
26
+ backend.not_supported _currency
27
+ end
26
28
  end
27
-
28
29
  end
29
30
  end
@@ -0,0 +1,5 @@
1
+ module Trader
2
+ class BaseEndpoint
3
+ # nothing for now.
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Trader
2
+ class BitcoinAddress < BaseEndpoint
3
+ attr_accessor :address
4
+
5
+ def initialize(_address)
6
+ @address = _address
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module Trader
2
+ class Error < StandardError; end
3
+
4
+ class AssertError < Error; end
5
+
6
+ class BackendError < Error
7
+ attr_reader :backend
8
+
9
+ def initialize(_backend, _message)
10
+ super "#{_backend}: #{_message}"
11
+ @backend = _backend
12
+ end
13
+ end
14
+
15
+ class NotSupportedError < BackendError
16
+ attr_reader :feature
17
+
18
+ def initialize(_backend, _feature)
19
+ super _backend, "#{_feature} not supported"
20
+ @feature = _feature
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Trader
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/trade-o-matic.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "trade-o-matic/version"
2
2
  require 'trade-o-matic/standard'
3
3
  require 'trade-o-matic/command'
4
+ require 'trade-o-matic/errors'
4
5
 
5
6
  require 'trade-o-matic/structs/currency'
6
7
  require 'trade-o-matic/structs/currency_pair'
@@ -23,6 +24,11 @@ require 'trade-o-matic/core/account_proxy'
23
24
  require 'trade-o-matic/core/account_order'
24
25
  require 'trade-o-matic/core/balance'
25
26
 
27
+ require 'trade-o-matic/endpoints/base_endpoint'
28
+ require 'trade-o-matic/endpoints/bitcoin_address'
29
+
30
+ require 'trade-o-matic/adapters/base_backend'
31
+
26
32
  require 'trade-o-matic/converters/fixed_converter'
27
33
  require 'trade-o-matic/converters/sync_converter'
28
34
  require 'trade-o-matic/converters/inverse_converter'
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.3.2
4
+ version: 0.4.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-04-29 00:00:00.000000000 Z
11
+ date: 2016-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -253,6 +253,7 @@ files:
253
253
  - lib/trade-o-matic/adapters/base/raw_account_order.rb
254
254
  - lib/trade-o-matic/adapters/base/raw_balance.rb
255
255
  - lib/trade-o-matic/adapters/base/raw_resource.rb
256
+ - lib/trade-o-matic/adapters/base_backend.rb
256
257
  - lib/trade-o-matic/adapters/bitfinex_backend.rb
257
258
  - lib/trade-o-matic/adapters/bitstamp_backend.rb
258
259
  - lib/trade-o-matic/adapters/fake_backend.rb
@@ -279,6 +280,9 @@ files:
279
280
  - lib/trade-o-matic/core/exchange.rb
280
281
  - lib/trade-o-matic/core/market.rb
281
282
  - lib/trade-o-matic/core/market_loader.rb
283
+ - lib/trade-o-matic/endpoints/base_endpoint.rb
284
+ - lib/trade-o-matic/endpoints/bitcoin_address.rb
285
+ - lib/trade-o-matic/errors.rb
282
286
  - lib/trade-o-matic/services/backend_factory.rb
283
287
  - lib/trade-o-matic/standard.rb
284
288
  - lib/trade-o-matic/structs/ask_slope.rb