trade-o-matic 0.3.1 → 0.3.2
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/trade-o-matic/adapters/bitfinex_backend.rb +162 -0
- data/lib/trade-o-matic/converters/sync_converter.rb +2 -2
- data/lib/trade-o-matic/converters/web_converter.rb +20 -0
- data/lib/trade-o-matic/services/backend_factory.rb +5 -0
- data/lib/trade-o-matic/support/converter_configurator.rb +5 -0
- data/lib/trade-o-matic/version.rb +1 -1
- metadata +22 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffa9eaa9a1e1e4a7ae37faf694d4882fb95a356c
|
|
4
|
+
data.tar.gz: c184b0499a3414f1155ef69ddd22717456093075
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f8ba8f453091a648e7f953f9f7375e55c1c223ea15508867122371786b414aa0c03c1c2b467aba83f5136a37dfdffa17c201b172b2d25012d12be8a67939ede
|
|
7
|
+
data.tar.gz: c4caec6d3f480b81e0f81bc2e692cb63d4c8e0af80bc2883247ad826bbc8f5e35cb9ffe4fbcc294a9e1a1097e0ba8a40bf7ad2084dbb746d8815bd90bbf60371
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
require 'rest-client'
|
|
2
|
+
require 'base64'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'trade-o-matic/adapters/base/raw_account_order'
|
|
5
|
+
require 'trade-o-matic/adapters/base/raw_balance'
|
|
6
|
+
|
|
7
|
+
module Trader
|
|
8
|
+
class BitfinexBackend
|
|
9
|
+
BASE_CUR = Currency.for_code(:BTC)
|
|
10
|
+
QUOTE_CUR = Currency.for_code(:BITFINEX_USD)
|
|
11
|
+
MAIN_MARKET = CurrencyPair.new BASE_CUR, QUOTE_CUR
|
|
12
|
+
|
|
13
|
+
CUR_EQUIV = {
|
|
14
|
+
'usd' => QUOTE_CUR,
|
|
15
|
+
'btc' => BASE_CUR
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class BalanceAdaptor < RawBalance
|
|
19
|
+
attr_mapped(:amount)
|
|
20
|
+
attr_mapped(:available_amount, 'available')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class OrderAdaptor < RawAccountOrder
|
|
24
|
+
attr_mapped(:id)
|
|
25
|
+
attr_mapped(:pair) { |r| MAIN_MARKET }
|
|
26
|
+
attr_mapped(:price)
|
|
27
|
+
attr_mapped(:volume, 'original_amount')
|
|
28
|
+
attr_mapped(:executed_volume, 'executed_amount')
|
|
29
|
+
attr_mapped(:instruction) { |r| r['side'] == 'buy' ? Order::BID : Order::ASK }
|
|
30
|
+
attr_mapped(:status) do |r|
|
|
31
|
+
if r['is_live']
|
|
32
|
+
AccountOrder::OPEN
|
|
33
|
+
elsif r['is_cancelled']
|
|
34
|
+
AccountOrder::CANCELED
|
|
35
|
+
else
|
|
36
|
+
AccountOrder::CLOSED
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def limit?
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def initialize(_session=nil)
|
|
46
|
+
@session = _session
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def get_available_markets
|
|
50
|
+
[MAIN_MARKET]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def fill_book(_book)
|
|
54
|
+
# TODO: consider book pair
|
|
55
|
+
|
|
56
|
+
_book.prepare Time.now
|
|
57
|
+
|
|
58
|
+
ob = public_get('book/BTCUSD')
|
|
59
|
+
ob['bids'].each { |o| _book.add_bid(o['price'], o['amount']) }
|
|
60
|
+
ob['asks'].each { |o| _book.add_ask(o['price'], o['amount']) }
|
|
61
|
+
|
|
62
|
+
tx = public_get('trades/BTCUSD', { timestamp: one_hour_ago })
|
|
63
|
+
tx.each do |t|
|
|
64
|
+
_book.add_transaction t['price'], t['amount'], Time.at(t['timestamp'])
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def get_session(_credentials)
|
|
69
|
+
_credentials
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def get_balance(_session, _currency)
|
|
73
|
+
raise "#{_currency} not supported" unless _currency == BASE_CUR || _currency == QUOTE_CUR
|
|
74
|
+
|
|
75
|
+
raw = auth_post(_session, 'balances')
|
|
76
|
+
wrap_balance raw, _currency
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_orders(_session, _pair)
|
|
80
|
+
raise 'market not supported' unless _pair == MAIN_MARKET
|
|
81
|
+
|
|
82
|
+
raw = auth_post(_session, 'orders')
|
|
83
|
+
raw = raw.select { |o| o['type'].include? 'limit' }
|
|
84
|
+
raw.map { |o| wrap_order o }
|
|
85
|
+
end
|
|
86
|
+
|
|
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?
|
|
90
|
+
|
|
91
|
+
wrap_order auth_post(_session, 'order/new', {
|
|
92
|
+
exchange: "bitfinex",
|
|
93
|
+
symbol: "BTCUSD",
|
|
94
|
+
amount: _volume.to_s('F'),
|
|
95
|
+
price: _price.to_s('F'),
|
|
96
|
+
side: _type == Order::BID ? 'buy' : 'sell',
|
|
97
|
+
type: "exchange limit"
|
|
98
|
+
})
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def fetch_order(_session, _id)
|
|
102
|
+
wrap_order auth_post(_session, 'order/status', { order_id: _id })
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def cancel_order(_session, _id)
|
|
106
|
+
order = wrap_order auth_post(_session, 'order/cancel', { order_id: _id })
|
|
107
|
+
order = fetch_order(_session, _id) while order.status == AccountOrder::OPEN
|
|
108
|
+
order
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
attr_reader :session
|
|
114
|
+
|
|
115
|
+
def public_get(_url, _query = {})
|
|
116
|
+
resp = RestClient.get "https://api.bitfinex.com/v1/#{_url}/", params: _query
|
|
117
|
+
JSON.parse resp
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def auth_post(_creds, _url, _data = {})
|
|
121
|
+
raise ArgumentError if !_creds.key?(:api_key) or !_creds.key?(:secret)
|
|
122
|
+
|
|
123
|
+
payload = build_payload("/v1/#{_url}", _data)
|
|
124
|
+
headers = {
|
|
125
|
+
'Content-Type' => 'application/json',
|
|
126
|
+
'Accept' => 'application/json',
|
|
127
|
+
'X-BFX-PAYLOAD' => payload,
|
|
128
|
+
'X-BFX-SIGNATURE' => sign_payload(_creds, payload),
|
|
129
|
+
'X-BFX-APIKEY' => _creds[:api_key],
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
resp = RestClient.post "https://api.bitfinex.com/v1/#{_url}/", nil, headers
|
|
133
|
+
JSON.parse resp
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def build_payload(_url, _params = {})
|
|
137
|
+
payload = {}
|
|
138
|
+
payload['nonce'] = (Time.now.to_f * 10_000).to_i.to_s
|
|
139
|
+
payload['request'] = _url
|
|
140
|
+
payload.merge!(_params) if _params
|
|
141
|
+
Base64.strict_encode64(payload.to_json)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def sign_payload(_creds, _payload)
|
|
145
|
+
OpenSSL::HMAC.hexdigest('sha384', _creds[:secret], _payload)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def one_hour_ago
|
|
149
|
+
Time.now.to_i - 3600
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def wrap_balance(_raw, _currency)
|
|
153
|
+
_raw = _raw.find { |b| b["type"] == "exchange" && CUR_EQUIV[b["currency"]] == _currency }
|
|
154
|
+
_raw = { "amount"=> "0.0", "available" => "0.0" } if _raw.nil?
|
|
155
|
+
BalanceAdaptor.new _raw
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def wrap_order(_raw)
|
|
159
|
+
OrderAdaptor.new _raw
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'pincers'
|
|
2
|
+
|
|
3
|
+
module Trader
|
|
4
|
+
class WebConverter < SyncConverter
|
|
5
|
+
attr_reader :url, :path
|
|
6
|
+
|
|
7
|
+
def initialize(_url, _path, _ttl=30)
|
|
8
|
+
@url = _url
|
|
9
|
+
@path = _path
|
|
10
|
+
|
|
11
|
+
super(_ttl) do
|
|
12
|
+
pincers = Pincers.for_chenso
|
|
13
|
+
pincers.goto _url
|
|
14
|
+
el = pincers.search(_path).first
|
|
15
|
+
raise "No element found at #{_path}" if el.nil?
|
|
16
|
+
Standard.amount el.text.gsub(/[^\d\s\.\,]+/,'').strip
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -23,6 +23,11 @@ module Trader
|
|
|
23
23
|
JsonApiConverter.new(_params['url'], _params['path'].split('.'), _params['ttl'] || 30)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def configure_yaml_web(_params)
|
|
27
|
+
require 'trade-o-matic/converters/web_converter'
|
|
28
|
+
WebConverter.new(_params['url'], _params['path'], _params['ttl'] || 30)
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def invert(_converter)
|
|
27
32
|
InverseConverter.new _converter
|
|
28
33
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trade-o-matic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
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-
|
|
11
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rest-client
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ~>
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '1.8'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ~>
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '1.8'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: gli
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ~>
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '2.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pincers
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ~>
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0.7'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.7'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: bundler
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -239,6 +253,7 @@ files:
|
|
|
239
253
|
- lib/trade-o-matic/adapters/base/raw_account_order.rb
|
|
240
254
|
- lib/trade-o-matic/adapters/base/raw_balance.rb
|
|
241
255
|
- lib/trade-o-matic/adapters/base/raw_resource.rb
|
|
256
|
+
- lib/trade-o-matic/adapters/bitfinex_backend.rb
|
|
242
257
|
- lib/trade-o-matic/adapters/bitstamp_backend.rb
|
|
243
258
|
- lib/trade-o-matic/adapters/fake_backend.rb
|
|
244
259
|
- lib/trade-o-matic/adapters/game_backend.rb
|
|
@@ -256,6 +271,7 @@ files:
|
|
|
256
271
|
- lib/trade-o-matic/converters/inverse_converter.rb
|
|
257
272
|
- lib/trade-o-matic/converters/json_api_converter.rb
|
|
258
273
|
- lib/trade-o-matic/converters/sync_converter.rb
|
|
274
|
+
- lib/trade-o-matic/converters/web_converter.rb
|
|
259
275
|
- lib/trade-o-matic/core/account.rb
|
|
260
276
|
- lib/trade-o-matic/core/account_order.rb
|
|
261
277
|
- lib/trade-o-matic/core/account_proxy.rb
|