bitex_bot 0.3.7 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +63 -0
- data/.rubocop.yml +33 -0
- data/Gemfile +1 -1
- data/Rakefile +1 -1
- data/bin/bitex_bot +1 -1
- data/bitex_bot.gemspec +34 -34
- data/lib/bitex_bot/database.rb +67 -67
- data/lib/bitex_bot/models/api_wrappers/api_wrapper.rb +142 -0
- data/lib/bitex_bot/models/api_wrappers/bitstamp/bitstamp_api_wrapper.rb +137 -0
- data/lib/bitex_bot/models/api_wrappers/itbit/itbit_api_wrapper.rb +116 -0
- data/lib/bitex_bot/models/api_wrappers/kraken/kraken_api_wrapper.rb +111 -0
- data/lib/bitex_bot/models/api_wrappers/kraken/kraken_order.rb +117 -0
- data/lib/bitex_bot/models/buy_closing_flow.rb +23 -16
- data/lib/bitex_bot/models/buy_opening_flow.rb +48 -54
- data/lib/bitex_bot/models/close_buy.rb +2 -2
- data/lib/bitex_bot/models/closing_flow.rb +98 -79
- data/lib/bitex_bot/models/open_buy.rb +11 -10
- data/lib/bitex_bot/models/open_sell.rb +11 -10
- data/lib/bitex_bot/models/opening_flow.rb +157 -99
- data/lib/bitex_bot/models/order_book_simulator.rb +62 -67
- data/lib/bitex_bot/models/sell_closing_flow.rb +25 -20
- data/lib/bitex_bot/models/sell_opening_flow.rb +47 -54
- data/lib/bitex_bot/models/store.rb +3 -1
- data/lib/bitex_bot/robot.rb +203 -176
- data/lib/bitex_bot/settings.rb +71 -12
- data/lib/bitex_bot/version.rb +1 -1
- data/lib/bitex_bot.rb +40 -16
- data/settings.rb.sample +43 -66
- data/spec/bitex_bot/settings_spec.rb +87 -15
- data/spec/factories/bitex_buy.rb +3 -3
- data/spec/factories/bitex_sell.rb +3 -3
- data/spec/factories/buy_opening_flow.rb +1 -1
- data/spec/factories/open_buy.rb +12 -10
- data/spec/factories/open_sell.rb +12 -10
- data/spec/factories/sell_opening_flow.rb +1 -1
- data/spec/models/api_wrappers/bitstamp_api_wrapper_spec.rb +200 -0
- data/spec/models/api_wrappers/itbit_api_wrapper_spec.rb +176 -0
- data/spec/models/api_wrappers/kraken_api_wrapper_spec.rb +209 -0
- data/spec/models/bitex_api_spec.rb +1 -1
- data/spec/models/buy_closing_flow_spec.rb +140 -71
- data/spec/models/buy_opening_flow_spec.rb +126 -56
- data/spec/models/order_book_simulator_spec.rb +10 -10
- data/spec/models/robot_spec.rb +61 -47
- data/spec/models/sell_closing_flow_spec.rb +130 -62
- data/spec/models/sell_opening_flow_spec.rb +129 -60
- data/spec/spec_helper.rb +19 -16
- data/spec/support/bitex_stubs.rb +13 -14
- data/spec/support/bitstamp/bitstamp_api_wrapper_stubs.rb +35 -0
- data/spec/support/bitstamp/bitstamp_stubs.rb +91 -0
- metadata +60 -42
- data/lib/bitex_bot/models/bitfinex_api_wrapper.rb +0 -118
- data/lib/bitex_bot/models/bitstamp_api_wrapper.rb +0 -82
- data/lib/bitex_bot/models/itbit_api_wrapper.rb +0 -68
- data/lib/bitex_bot/models/kraken_api_wrapper.rb +0 -188
- data/spec/models/bitfinex_api_wrapper_spec.rb +0 -17
- data/spec/models/bitstamp_api_wrapper_spec.rb +0 -15
- data/spec/models/itbit_api_wrapper_spec.rb +0 -15
- data/spec/support/bitstamp_stubs.rb +0 -110
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitex_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nubis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-06-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -26,7 +26,21 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '4.2'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: hashie
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 3.5.4
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 3.5.4
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: mail
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
31
45
|
requirements:
|
32
46
|
- - ">="
|
@@ -40,7 +54,7 @@ dependencies:
|
|
40
54
|
- !ruby/object:Gem::Version
|
41
55
|
version: '0'
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
57
|
+
name: sqlite3
|
44
58
|
requirement: !ruby/object:Gem::Requirement
|
45
59
|
requirements:
|
46
60
|
- - ">="
|
@@ -59,30 +73,30 @@ dependencies:
|
|
59
73
|
requirements:
|
60
74
|
- - '='
|
61
75
|
- !ruby/object:Gem::Version
|
62
|
-
version: '0.
|
76
|
+
version: '0.5'
|
63
77
|
type: :runtime
|
64
78
|
prerelease: false
|
65
79
|
version_requirements: !ruby/object:Gem::Requirement
|
66
80
|
requirements:
|
67
81
|
- - '='
|
68
82
|
- !ruby/object:Gem::Version
|
69
|
-
version: '0.
|
83
|
+
version: '0.5'
|
70
84
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
85
|
+
name: bitstamp
|
72
86
|
requirement: !ruby/object:Gem::Requirement
|
73
87
|
requirements:
|
74
|
-
- -
|
88
|
+
- - ">="
|
75
89
|
- !ruby/object:Gem::Version
|
76
|
-
version: 0
|
90
|
+
version: '0'
|
77
91
|
type: :runtime
|
78
92
|
prerelease: false
|
79
93
|
version_requirements: !ruby/object:Gem::Requirement
|
80
94
|
requirements:
|
81
|
-
- -
|
95
|
+
- - ">="
|
82
96
|
- !ruby/object:Gem::Version
|
83
|
-
version: 0
|
97
|
+
version: '0'
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
|
-
name:
|
99
|
+
name: itbit
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
87
101
|
requirements:
|
88
102
|
- - '='
|
@@ -110,13 +124,13 @@ dependencies:
|
|
110
124
|
- !ruby/object:Gem::Version
|
111
125
|
version: 1.2.1
|
112
126
|
- !ruby/object:Gem::Dependency
|
113
|
-
name:
|
127
|
+
name: bundler
|
114
128
|
requirement: !ruby/object:Gem::Requirement
|
115
129
|
requirements:
|
116
130
|
- - ">="
|
117
131
|
- !ruby/object:Gem::Version
|
118
132
|
version: '0'
|
119
|
-
type: :
|
133
|
+
type: :development
|
120
134
|
prerelease: false
|
121
135
|
version_requirements: !ruby/object:Gem::Requirement
|
122
136
|
requirements:
|
@@ -124,21 +138,21 @@ dependencies:
|
|
124
138
|
- !ruby/object:Gem::Version
|
125
139
|
version: '0'
|
126
140
|
- !ruby/object:Gem::Dependency
|
127
|
-
name:
|
141
|
+
name: rake
|
128
142
|
requirement: !ruby/object:Gem::Requirement
|
129
143
|
requirements:
|
130
|
-
- - "
|
144
|
+
- - ">="
|
131
145
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
133
|
-
type: :
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
134
148
|
prerelease: false
|
135
149
|
version_requirements: !ruby/object:Gem::Requirement
|
136
150
|
requirements:
|
137
|
-
- - "
|
151
|
+
- - ">="
|
138
152
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
153
|
+
version: '0'
|
140
154
|
- !ruby/object:Gem::Dependency
|
141
|
-
name:
|
155
|
+
name: byebug
|
142
156
|
requirement: !ruby/object:Gem::Requirement
|
143
157
|
requirements:
|
144
158
|
- - ">="
|
@@ -152,7 +166,7 @@ dependencies:
|
|
152
166
|
- !ruby/object:Gem::Version
|
153
167
|
version: '0'
|
154
168
|
- !ruby/object:Gem::Dependency
|
155
|
-
name:
|
169
|
+
name: database_cleaner
|
156
170
|
requirement: !ruby/object:Gem::Requirement
|
157
171
|
requirements:
|
158
172
|
- - ">="
|
@@ -166,7 +180,7 @@ dependencies:
|
|
166
180
|
- !ruby/object:Gem::Version
|
167
181
|
version: '0'
|
168
182
|
- !ruby/object:Gem::Dependency
|
169
|
-
name:
|
183
|
+
name: factory_bot
|
170
184
|
requirement: !ruby/object:Gem::Requirement
|
171
185
|
requirements:
|
172
186
|
- - ">="
|
@@ -208,7 +222,7 @@ dependencies:
|
|
208
222
|
- !ruby/object:Gem::Version
|
209
223
|
version: '0'
|
210
224
|
- !ruby/object:Gem::Dependency
|
211
|
-
name:
|
225
|
+
name: rspec_junit_formatter
|
212
226
|
requirement: !ruby/object:Gem::Requirement
|
213
227
|
requirements:
|
214
228
|
- - ">="
|
@@ -222,7 +236,7 @@ dependencies:
|
|
222
236
|
- !ruby/object:Gem::Version
|
223
237
|
version: '0'
|
224
238
|
- !ruby/object:Gem::Dependency
|
225
|
-
name:
|
239
|
+
name: rubocop
|
226
240
|
requirement: !ruby/object:Gem::Requirement
|
227
241
|
requirements:
|
228
242
|
- - ">="
|
@@ -236,7 +250,7 @@ dependencies:
|
|
236
250
|
- !ruby/object:Gem::Version
|
237
251
|
version: '0'
|
238
252
|
- !ruby/object:Gem::Dependency
|
239
|
-
name:
|
253
|
+
name: shoulda-matchers
|
240
254
|
requirement: !ruby/object:Gem::Requirement
|
241
255
|
requirements:
|
242
256
|
- - ">="
|
@@ -250,7 +264,7 @@ dependencies:
|
|
250
264
|
- !ruby/object:Gem::Version
|
251
265
|
version: '0'
|
252
266
|
- !ruby/object:Gem::Dependency
|
253
|
-
name:
|
267
|
+
name: timecop
|
254
268
|
requirement: !ruby/object:Gem::Requirement
|
255
269
|
requirements:
|
256
270
|
- - ">="
|
@@ -278,9 +292,8 @@ dependencies:
|
|
278
292
|
- !ruby/object:Gem::Version
|
279
293
|
version: '0'
|
280
294
|
description: |-
|
281
|
-
Both a trading robot and a library to build trading
|
282
|
-
|
283
|
-
sell on another exchange and vice versa.
|
295
|
+
Both a trading robot and a library to build trading robots. The bitex-bot lets you buy cheap on bitex
|
296
|
+
and sell on another exchange and vice versa.
|
284
297
|
email:
|
285
298
|
- nb@bitex.la
|
286
299
|
- tr@bitex.la
|
@@ -289,8 +302,10 @@ executables:
|
|
289
302
|
extensions: []
|
290
303
|
extra_rdoc_files: []
|
291
304
|
files:
|
305
|
+
- ".circleci/config.yml"
|
292
306
|
- ".gitignore"
|
293
307
|
- ".rspec"
|
308
|
+
- ".rubocop.yml"
|
294
309
|
- Gemfile
|
295
310
|
- LICENSE.txt
|
296
311
|
- README.md
|
@@ -299,15 +314,16 @@ files:
|
|
299
314
|
- bitex_bot.gemspec
|
300
315
|
- lib/bitex_bot.rb
|
301
316
|
- lib/bitex_bot/database.rb
|
302
|
-
- lib/bitex_bot/models/
|
303
|
-
- lib/bitex_bot/models/bitstamp_api_wrapper.rb
|
317
|
+
- lib/bitex_bot/models/api_wrappers/api_wrapper.rb
|
318
|
+
- lib/bitex_bot/models/api_wrappers/bitstamp/bitstamp_api_wrapper.rb
|
319
|
+
- lib/bitex_bot/models/api_wrappers/itbit/itbit_api_wrapper.rb
|
320
|
+
- lib/bitex_bot/models/api_wrappers/kraken/kraken_api_wrapper.rb
|
321
|
+
- lib/bitex_bot/models/api_wrappers/kraken/kraken_order.rb
|
304
322
|
- lib/bitex_bot/models/buy_closing_flow.rb
|
305
323
|
- lib/bitex_bot/models/buy_opening_flow.rb
|
306
324
|
- lib/bitex_bot/models/close_buy.rb
|
307
325
|
- lib/bitex_bot/models/close_sell.rb
|
308
326
|
- lib/bitex_bot/models/closing_flow.rb
|
309
|
-
- lib/bitex_bot/models/itbit_api_wrapper.rb
|
310
|
-
- lib/bitex_bot/models/kraken_api_wrapper.rb
|
311
327
|
- lib/bitex_bot/models/open_buy.rb
|
312
328
|
- lib/bitex_bot/models/open_sell.rb
|
313
329
|
- lib/bitex_bot/models/opening_flow.rb
|
@@ -326,19 +342,20 @@ files:
|
|
326
342
|
- spec/factories/open_buy.rb
|
327
343
|
- spec/factories/open_sell.rb
|
328
344
|
- spec/factories/sell_opening_flow.rb
|
345
|
+
- spec/models/api_wrappers/bitstamp_api_wrapper_spec.rb
|
346
|
+
- spec/models/api_wrappers/itbit_api_wrapper_spec.rb
|
347
|
+
- spec/models/api_wrappers/kraken_api_wrapper_spec.rb
|
329
348
|
- spec/models/bitex_api_spec.rb
|
330
|
-
- spec/models/bitfinex_api_wrapper_spec.rb
|
331
|
-
- spec/models/bitstamp_api_wrapper_spec.rb
|
332
349
|
- spec/models/buy_closing_flow_spec.rb
|
333
350
|
- spec/models/buy_opening_flow_spec.rb
|
334
|
-
- spec/models/itbit_api_wrapper_spec.rb
|
335
351
|
- spec/models/order_book_simulator_spec.rb
|
336
352
|
- spec/models/robot_spec.rb
|
337
353
|
- spec/models/sell_closing_flow_spec.rb
|
338
354
|
- spec/models/sell_opening_flow_spec.rb
|
339
355
|
- spec/spec_helper.rb
|
340
356
|
- spec/support/bitex_stubs.rb
|
341
|
-
- spec/support/
|
357
|
+
- spec/support/bitstamp/bitstamp_api_wrapper_stubs.rb
|
358
|
+
- spec/support/bitstamp/bitstamp_stubs.rb
|
342
359
|
homepage: ''
|
343
360
|
licenses:
|
344
361
|
- MIT
|
@@ -371,16 +388,17 @@ test_files:
|
|
371
388
|
- spec/factories/open_buy.rb
|
372
389
|
- spec/factories/open_sell.rb
|
373
390
|
- spec/factories/sell_opening_flow.rb
|
391
|
+
- spec/models/api_wrappers/bitstamp_api_wrapper_spec.rb
|
392
|
+
- spec/models/api_wrappers/itbit_api_wrapper_spec.rb
|
393
|
+
- spec/models/api_wrappers/kraken_api_wrapper_spec.rb
|
374
394
|
- spec/models/bitex_api_spec.rb
|
375
|
-
- spec/models/bitfinex_api_wrapper_spec.rb
|
376
|
-
- spec/models/bitstamp_api_wrapper_spec.rb
|
377
395
|
- spec/models/buy_closing_flow_spec.rb
|
378
396
|
- spec/models/buy_opening_flow_spec.rb
|
379
|
-
- spec/models/itbit_api_wrapper_spec.rb
|
380
397
|
- spec/models/order_book_simulator_spec.rb
|
381
398
|
- spec/models/robot_spec.rb
|
382
399
|
- spec/models/sell_closing_flow_spec.rb
|
383
400
|
- spec/models/sell_opening_flow_spec.rb
|
384
401
|
- spec/spec_helper.rb
|
385
402
|
- spec/support/bitex_stubs.rb
|
386
|
-
- spec/support/
|
403
|
+
- spec/support/bitstamp/bitstamp_api_wrapper_stubs.rb
|
404
|
+
- spec/support/bitstamp/bitstamp_stubs.rb
|
@@ -1,118 +0,0 @@
|
|
1
|
-
require "bigdecimal"
|
2
|
-
require "bigdecimal/util"
|
3
|
-
|
4
|
-
module Bitfinex
|
5
|
-
module WithUserAgent
|
6
|
-
def new_rest_connection
|
7
|
-
super.tap do |conn|
|
8
|
-
conn.headers['User-Agent'] = BitexBot.user_agent
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class Client
|
14
|
-
prepend WithUserAgent
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class BitfinexApiWrapper
|
19
|
-
def self.setup(settings)
|
20
|
-
Bitfinex::Client.configure do |conf|
|
21
|
-
conf.api_key = settings.bitfinex.api_key
|
22
|
-
conf.secret = settings.bitfinex.api_secret
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.with_retry(action, &block)
|
27
|
-
begin
|
28
|
-
block.call
|
29
|
-
rescue StandardError, Bitfinex::ClientError => e
|
30
|
-
raise e if BitexBot::Robot.test_mode
|
31
|
-
BitexBot::Robot.logger.info("Bitfinex #{action} failed. Retrying in 5 seconds.")
|
32
|
-
sleep 5
|
33
|
-
retry
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.transactions
|
38
|
-
with_retry 'transactions' do
|
39
|
-
Bitfinex::Client.new.trades.collect do |t|
|
40
|
-
Hashie::Mash.new({
|
41
|
-
tid: t['tid'].to_i,
|
42
|
-
price: t['price'],
|
43
|
-
amount: t['amount'],
|
44
|
-
date: t['timestamp']
|
45
|
-
})
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.order_book
|
51
|
-
with_retry 'order_book' do
|
52
|
-
book = Bitfinex::Client.new.orderbook
|
53
|
-
{ 'bids' => book['bids'].collect{|b| [b['price'], b['amount']] },
|
54
|
-
'asks' => book['asks'].collect{|a| [a['price'], a['amount']] } }
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.balance
|
59
|
-
with_retry 'balance' do
|
60
|
-
balances = Bitfinex::Client.new.balances(type: 'exchange')
|
61
|
-
sleep 1 # Sleep to avoid sending two consecutive requests to bitfinex.
|
62
|
-
fee = Bitfinex::Client.new.account_info.first['taker_fees']
|
63
|
-
btc = balances.find{|b| b['currency'] == 'btc' } || {}
|
64
|
-
usd = balances.find{|b| b['currency'] == 'usd' } || {}
|
65
|
-
{ "btc_balance" => btc['amount'].to_d,
|
66
|
-
"btc_reserved" => btc['amount'].to_d - btc['available'].to_d,
|
67
|
-
"btc_available" => btc['available'].to_d,
|
68
|
-
"usd_balance" => usd['amount'].to_d,
|
69
|
-
"usd_reserved" => usd['amount'].to_d - usd['available'].to_d,
|
70
|
-
"usd_available" => usd['available'].to_d,
|
71
|
-
"fee" => fee.to_d
|
72
|
-
}
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.orders
|
77
|
-
with_retry 'orders' do
|
78
|
-
Bitfinex::Client.new.orders.collect{|o| BitfinexOrder.new(o) }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# We don't need to fetch the list of transactions
|
83
|
-
# for bitfinex
|
84
|
-
def self.user_transactions
|
85
|
-
[]
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.amount_and_quantity(order_id, transactions)
|
89
|
-
with_retry "find order #{order_id}" do
|
90
|
-
order = Bitfinex::Client.new.order_status(order_id)
|
91
|
-
[order['avg_execution_price'].to_d * order['executed_amount'].to_d, order['executed_amount'].to_d]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.place_order(type, price, quantity)
|
96
|
-
with_retry "place order #{type} #{price} #{quantity}" do
|
97
|
-
order_data = Bitfinex::Client.new
|
98
|
-
.new_order('btcusd', quantity.round(4), 'exchange limit', type.to_s, price.round(2))
|
99
|
-
BitfinexOrder.new(order_data)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class BitfinexOrder
|
105
|
-
attr_accessor :id, :amount, :price, :type, :datetime
|
106
|
-
def initialize(order_data)
|
107
|
-
self.id = order_data['id'].to_i
|
108
|
-
self.amount = order_data['original_amount'].to_d
|
109
|
-
self.price = order_data['price'].to_d
|
110
|
-
self.type = order_data['side'].to_sym
|
111
|
-
self.datetime = order_data['timestamp'].to_i
|
112
|
-
end
|
113
|
-
|
114
|
-
def cancel!
|
115
|
-
Bitfinex::Client.new.cancel_orders(id)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
@@ -1,82 +0,0 @@
|
|
1
|
-
class BitstampApiWrapper
|
2
|
-
def self.setup(settings)
|
3
|
-
Bitstamp.setup do |config|
|
4
|
-
config.key = settings.bitstamp.api_key
|
5
|
-
config.secret = settings.bitstamp.secret
|
6
|
-
config.client_id = settings.bitstamp.client_id.to_s
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
#{
|
11
|
-
# tid:i,
|
12
|
-
# date: (i+1).seconds.ago.to_i.to_s,
|
13
|
-
# price: price.to_s,
|
14
|
-
# amount: amount.to_s
|
15
|
-
#}
|
16
|
-
def self.transactions
|
17
|
-
Bitstamp.transactions
|
18
|
-
end
|
19
|
-
|
20
|
-
# { 'timestamp' => DateTime.now.to_i.to_s,
|
21
|
-
# 'bids' =>
|
22
|
-
# [['30', '3'], ['25', '2'], ['20', '1.5'], ['15', '4'], ['10', '5']],
|
23
|
-
# 'asks' =>
|
24
|
-
# [['10', '2'], ['15', '3'], ['20', '1.5'], ['25', '3'], ['30', '3']]
|
25
|
-
# }
|
26
|
-
def self.order_book(retries = 20)
|
27
|
-
begin
|
28
|
-
book = Bitstamp.order_book
|
29
|
-
age = Time.now.to_i - book["timestamp"].to_i
|
30
|
-
if age > 300
|
31
|
-
BitexBot::Robot.logger.info("Refusing to continue as orderbook is #{age} seconds old")
|
32
|
-
self.order_book(retries)
|
33
|
-
else
|
34
|
-
book
|
35
|
-
end
|
36
|
-
rescue StandardError => e
|
37
|
-
if retries == 0
|
38
|
-
raise
|
39
|
-
else
|
40
|
-
BitexBot::Robot.logger.info("Bitstamp order_book failed, retrying #{retries} more times")
|
41
|
-
sleep 1
|
42
|
-
self.order_book(retries - 1)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# {"btc_balance"=> "10.0", "btc_reserved"=> "0", "btc_available"=> "10.0",
|
48
|
-
# "usd_balance"=> "100.0", "usd_reserved"=>"0", "usd_available"=> "100.0",
|
49
|
-
# "fee"=> "0.5000"}
|
50
|
-
def self.balance
|
51
|
-
Bitstamp.balance
|
52
|
-
end
|
53
|
-
|
54
|
-
# ask = double(amount: args[:amount], price: args[:price],
|
55
|
-
# type: 1, id: remote_id, datetime: DateTime.now.to_s)
|
56
|
-
# ask.stub(:cancel!) do
|
57
|
-
def self.orders
|
58
|
-
Bitstamp.orders.all
|
59
|
-
end
|
60
|
-
|
61
|
-
# double(usd: (usd * ratio).to_s, btc: (btc * ratio).to_s,
|
62
|
-
# btc_usd: o.price.to_s, order_id: o.id, fee: "0.5", type: 2,
|
63
|
-
# datetime: DateTime.now.to_s)
|
64
|
-
def self.user_transactions
|
65
|
-
Bitstamp.user_transactions.all
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.order_is_done?(order)
|
69
|
-
order.nil?
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.amount_and_quantity(order_id, transactions)
|
73
|
-
closes = transactions.select{|t| t.order_id.to_s == order_id}
|
74
|
-
amount = closes.collect{|x| x.usd.to_d }.sum.abs
|
75
|
-
quantity = closes.collect{|x| x.btc.to_d }.sum.abs
|
76
|
-
[amount, quantity]
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.place_order(type, price, quantity)
|
80
|
-
Bitstamp.orders.send(type, amount: quantity.round(4), price: price.round(2))
|
81
|
-
end
|
82
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
class ItbitApiWrapper
|
2
|
-
def self.setup(settings)
|
3
|
-
Itbit.client_key = settings.itbit.client_key
|
4
|
-
Itbit.secret = settings.itbit.secret
|
5
|
-
Itbit.user_id = settings.itbit.user_id
|
6
|
-
Itbit.default_wallet_id = settings.itbit.default_wallet_id
|
7
|
-
Itbit.sandbox = settings.sandbox
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.transactions
|
11
|
-
Itbit::XBTUSDMarketData.trades.collect{|t| Hashie::Mash.new(t) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.order_book
|
15
|
-
Itbit::XBTUSDMarketData.orders.stringify_keys
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.balance
|
19
|
-
balances = Itbit::Wallet.all
|
20
|
-
.find{|i| i[:id] == Itbit.default_wallet_id }[:balances]
|
21
|
-
usd = balances.find{|x| x[:currency] == :usd }
|
22
|
-
btc = balances.find{|x| x[:currency] == :xbt }
|
23
|
-
{ "btc_balance" => btc[:total_balance],
|
24
|
-
"btc_reserved" => btc[:total_balance] - btc[:available_balance],
|
25
|
-
"btc_available" => btc[:available_balance],
|
26
|
-
"usd_balance" => usd[:total_balance],
|
27
|
-
"usd_reserved" => usd[:total_balance] - usd[:available_balance],
|
28
|
-
"usd_available" => usd[:available_balance],
|
29
|
-
"fee" => 0.5
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.orders
|
34
|
-
Itbit::Order.all(status: :open)
|
35
|
-
end
|
36
|
-
|
37
|
-
# We don't need to fetch the list of transactions
|
38
|
-
# for itbit since we wont actually use them later.
|
39
|
-
def self.user_transactions
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.amount_and_quantity(order_id, transactions)
|
44
|
-
order = Itbit::Order.find(order_id)
|
45
|
-
[order.volume_weighted_average_price * order.amount_filled, order.amount_filled]
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.place_order(type, price, quantity)
|
49
|
-
begin
|
50
|
-
return Itbit::Order.create!(type, :xbtusd, quantity.round(4), price.round(2), wait: true)
|
51
|
-
rescue RestClient::RequestTimeout => e
|
52
|
-
# On timeout errors, we still look for the latest active closing order
|
53
|
-
# that may be available. We have a magic threshold of 5 minutes
|
54
|
-
# and also use the price to recognize an order as the current one.
|
55
|
-
# TODO: Maybe we can identify the order using metadata instead of price.
|
56
|
-
BitexBot::Robot.logger.error("Captured Timeout on itbit")
|
57
|
-
latest = Itbit::Order.all.select do |x|
|
58
|
-
x.price == price && (x.created_time - Time.now.to_i).abs < 500
|
59
|
-
end.first
|
60
|
-
if latest
|
61
|
-
return latest
|
62
|
-
else
|
63
|
-
BitexBot::Robot.logger.error("Could not find my order")
|
64
|
-
raise e
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|