bitex_bot 0.2.12 → 0.2.13
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/bitex_bot.gemspec +1 -0
- data/lib/bitex_bot/models/bitfinex_api_wrapper.rb +102 -0
- data/lib/bitex_bot/robot.rb +8 -1
- data/lib/bitex_bot/version.rb +1 -1
- data/lib/bitex_bot.rb +1 -0
- data/settings.yml.sample +12 -5
- data/spec/models/buy_closing_flow_spec.rb +1 -1
- data/spec/models/buy_opening_flow_spec.rb +4 -4
- data/spec/models/sell_closing_flow_spec.rb +1 -1
- data/spec/models/sell_opening_flow_spec.rb +4 -4
- data/spec/spec_helper.rb +2 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8994e54974f11a72d84fe860f4089d59561e6ac
|
4
|
+
data.tar.gz: 70e62bb47abb627a4b1f71312bc7b5b9f6c3389e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a26decc7d2f8f81c37e6bf3a751f9b3f84acdc4be6149320869a0343c36801d6e94dc8ec43d0bd52e03599c3b1262b75c26b1f060e84f2740887e9f54d132c21
|
7
|
+
data.tar.gz: 34359e33f27d99d5be888e8c4fe641c4031adf8787b1629aa82958c0376df67fd385c3025b950368b8c690ac3af2db9bc5be17b222c0891010475a5da326b0e0
|
data/bitex_bot.gemspec
CHANGED
@@ -0,0 +1,102 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
require "bigdecimal/util"
|
3
|
+
|
4
|
+
class BitfinexApiWrapper
|
5
|
+
def self.setup(settings)
|
6
|
+
Bitfinex::Client.configure do |conf|
|
7
|
+
conf.api_key = settings.bitfinex.api_key
|
8
|
+
conf.secret = settings.bitfinex.api_secret
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.with_retry(action, &block)
|
13
|
+
begin
|
14
|
+
block.call
|
15
|
+
rescue StandardError, Bitfinex::ClientError => e
|
16
|
+
BitexBot::Robot.logger.info("Bitfinex #{action} failed. Retrying in 5 seconds.")
|
17
|
+
sleep 5
|
18
|
+
retry
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.transactions
|
23
|
+
with_retry 'transactions' do
|
24
|
+
Bitfinex::Client.new.trades.collect do |t|
|
25
|
+
{ tid: t['tid'].to_i,
|
26
|
+
price: t['price'],
|
27
|
+
amount: t['amount'],
|
28
|
+
date: t['timestamp']
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.order_book
|
35
|
+
with_retry 'order_book' do
|
36
|
+
book = Bitfinex::Client.new.orderbook
|
37
|
+
{ 'bids' => book['bids'].collect{|b| [b['price'], b['amount']] },
|
38
|
+
'asks' => book['asks'].collect{|a| [a['price'], a['amount']] } }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.balance
|
43
|
+
with_retry 'balance' do
|
44
|
+
balances = Bitfinex::Client.new.balances(type: 'exchange')
|
45
|
+
sleep 1 # Sleep to avoid sending two consecutive requests to bitfinex.
|
46
|
+
fee = Bitfinex::Client.new.account_info.first['taker_fees']
|
47
|
+
btc = balances.find{|b| b['currency'] == 'btc' } || {}
|
48
|
+
usd = balances.find{|b| b['currency'] == 'usd' } || {}
|
49
|
+
{ "btc_balance" => btc['amount'].to_d,
|
50
|
+
"btc_reserved" => btc['amount'].to_d - btc['available'].to_d,
|
51
|
+
"btc_available" => btc['available'].to_d,
|
52
|
+
"usd_balance" => usd['amount'].to_d,
|
53
|
+
"usd_reserved" => usd['amount'].to_d - usd['available'].to_d,
|
54
|
+
"usd_available" => usd['available'].to_d,
|
55
|
+
"fee" => fee.to_d
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.orders
|
61
|
+
with_retry 'orders' do
|
62
|
+
Bitfinex::Client.new.orders.collect{|o| BitfinexOrder.new(o) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# We don't need to fetch the list of transactions
|
67
|
+
# for bitfinex
|
68
|
+
def self.user_transactions
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.amount_and_quantity(order_id, transactions)
|
73
|
+
with_retry "find order #{order_id}" do
|
74
|
+
order = Bitfinex::Client.new.order_status(order_id)
|
75
|
+
[order['avg_execution_price'].to_d * order['executed_amount'].to_d, order['executed_amount'].to_d]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.place_order(type, price, quantity)
|
80
|
+
with_retry "place order #{type} #{price} #{quantity}" do
|
81
|
+
order_data = Bitfinex::Client.new
|
82
|
+
.new_order('btcusd', quantity, 'exchange limit', type.to_s, price)
|
83
|
+
BitfinexOrder.new(order_data)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class BitfinexOrder
|
89
|
+
attr_accessor :id, :amount, :price, :type, :datetime
|
90
|
+
def initialize(order_data)
|
91
|
+
self.id = order_data['id'].to_i
|
92
|
+
self.amount = order_data['original_amount'].to_d
|
93
|
+
self.price = order_data['price'].to_d
|
94
|
+
self.type = order_data['side'].to_sym
|
95
|
+
self.datetime = order_data['timestamp'].to_i
|
96
|
+
end
|
97
|
+
|
98
|
+
def cancel!
|
99
|
+
Bitfinex::Client.new.cancel_orders(id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
data/lib/bitex_bot/robot.rb
CHANGED
@@ -14,7 +14,14 @@ module BitexBot
|
|
14
14
|
cattr_accessor :cooldown_until
|
15
15
|
cattr_accessor :test_mode
|
16
16
|
cattr_accessor :taker do
|
17
|
-
Settings.taker
|
17
|
+
case Settings.taker
|
18
|
+
when 'itbit'
|
19
|
+
ItbitApiWrapper
|
20
|
+
when 'bitstamp'
|
21
|
+
BitstampApiWrapper
|
22
|
+
when 'bitfinex'
|
23
|
+
BitfinexApiWrapper
|
24
|
+
end
|
18
25
|
end
|
19
26
|
cattr_accessor :logger do
|
20
27
|
Logger.new(Settings.log.try(:file) || STDOUT, 10, 10240000).tap do |l|
|
data/lib/bitex_bot/version.rb
CHANGED
data/lib/bitex_bot.rb
CHANGED
data/settings.yml.sample
CHANGED
@@ -17,7 +17,7 @@ time_to_live: 20
|
|
17
17
|
sandbox: false
|
18
18
|
|
19
19
|
# Which market to use for taking (we're always makers on bitex)
|
20
|
-
# itbit or
|
20
|
+
# itbit, bitstamp or bitfinex
|
21
21
|
taker: bitstamp
|
22
22
|
|
23
23
|
# Settings for buying on bitex and selling on bitstamp.
|
@@ -69,10 +69,17 @@ bitstamp:
|
|
69
69
|
# These are passed in to the itbit gem:
|
70
70
|
# see https://github.com/bitex-la/itbit for more info.
|
71
71
|
itbit:
|
72
|
-
client_key
|
73
|
-
secret
|
74
|
-
user_id
|
75
|
-
default_wallet_id
|
72
|
+
client_key: 'the-client-key'
|
73
|
+
secret: 'the-secret'
|
74
|
+
user_id: 'the-user-id'
|
75
|
+
default_wallet_id: 'wallet-000'
|
76
|
+
|
77
|
+
# These are passed in to the bitfinex gem:
|
78
|
+
# see https://github.com/bitfinexcom/bitfinex-api-rb for more info.
|
79
|
+
bitfinex:
|
80
|
+
api_key: 'your_api_key'
|
81
|
+
api_secret: 'your_api_secret'
|
82
|
+
|
76
83
|
|
77
84
|
# Settings for the ActiveRecord Database to use.
|
78
85
|
# sqlite is just fine. Check this link for more options:
|
@@ -26,7 +26,7 @@ describe BitexBot::BuyClosingFlow do
|
|
26
26
|
open_one.reload.closing_flow.should == flow
|
27
27
|
open_two.reload.closing_flow.should == flow
|
28
28
|
flow.open_positions.should == [open_one, open_two]
|
29
|
-
flow.desired_price.should == '310.
|
29
|
+
flow.desired_price.round(15).should == '310.497512437810945'.to_d
|
30
30
|
flow.quantity.should == 2.01
|
31
31
|
flow.btc_profit.should be_nil
|
32
32
|
flow.usd_profit.should be_nil
|
@@ -10,7 +10,7 @@ describe BitexBot::BuyOpeningFlow do
|
|
10
10
|
it { should validate_presence_of :price }
|
11
11
|
it { should validate_presence_of :value_to_use }
|
12
12
|
it { should validate_presence_of :order_id }
|
13
|
-
it { should(
|
13
|
+
it { should(validate_inclusion_of(:status)
|
14
14
|
.in_array(BitexBot::BuyOpeningFlow.statuses)) }
|
15
15
|
|
16
16
|
describe "when creating a buying flow" do
|
@@ -24,7 +24,7 @@ describe BitexBot::BuyOpeningFlow do
|
|
24
24
|
|
25
25
|
flow.value_to_use.should == 50
|
26
26
|
flow.price.should <= flow.suggested_closing_price
|
27
|
-
flow.price.should == "19.85074626865672".to_d
|
27
|
+
flow.price.round(14).should == "19.85074626865672".to_d
|
28
28
|
flow.suggested_closing_price.should == 20
|
29
29
|
flow.order_id.should == 12345
|
30
30
|
end
|
@@ -52,7 +52,7 @@ describe BitexBot::BuyOpeningFlow do
|
|
52
52
|
bitstamp_order_book_stub['bids'], bitstamp_transactions_stub, 0.5, 0.25, store)
|
53
53
|
flow.value_to_use.should == 100
|
54
54
|
flow.price.should <= flow.suggested_closing_price
|
55
|
-
flow.price.should == "7.
|
55
|
+
flow.price.round(15).should == "7.44402985074627".to_d
|
56
56
|
flow.suggested_closing_price.should == 15
|
57
57
|
flow.order_id.should == 12345
|
58
58
|
end
|
@@ -95,7 +95,7 @@ describe BitexBot::BuyOpeningFlow do
|
|
95
95
|
flow = BitexBot::BuyOpeningFlow.create_for_market(100,
|
96
96
|
bitstamp_order_book_stub['bids'], bitstamp_transactions_stub, 0.5, 0.25, store)
|
97
97
|
|
98
|
-
flow.price.should == "19.
|
98
|
+
flow.price.round(13).should == "19.7514925373134".to_d
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -27,7 +27,7 @@ describe BitexBot::SellClosingFlow do
|
|
27
27
|
open_one.reload.closing_flow.should == flow
|
28
28
|
open_two.reload.closing_flow.should == flow
|
29
29
|
flow.open_positions.should == [open_one, open_two]
|
30
|
-
flow.desired_price.should == '290.
|
30
|
+
flow.desired_price.round(15).should == '290.497512437810945'.to_d
|
31
31
|
flow.quantity.should == 2.01
|
32
32
|
flow.amount.should == 604
|
33
33
|
flow.btc_profit.should be_nil
|
@@ -10,7 +10,7 @@ describe BitexBot::SellOpeningFlow do
|
|
10
10
|
it { should validate_presence_of :price }
|
11
11
|
it { should validate_presence_of :value_to_use }
|
12
12
|
it { should validate_presence_of :order_id }
|
13
|
-
it { should(
|
13
|
+
it { should(validate_inclusion_of(:status)
|
14
14
|
.in_array(BitexBot::SellOpeningFlow.statuses)) }
|
15
15
|
|
16
16
|
describe "when creating a selling flow" do
|
@@ -39,7 +39,7 @@ describe BitexBot::SellOpeningFlow do
|
|
39
39
|
|
40
40
|
flow.value_to_use.should == 4
|
41
41
|
flow.price.should >= flow.suggested_closing_price
|
42
|
-
flow.price.should == "25.18796992481203".to_d
|
42
|
+
flow.price.round(14).should == "25.18796992481203".to_d
|
43
43
|
flow.suggested_closing_price.should == 25
|
44
44
|
flow.order_id.should == 12345
|
45
45
|
end
|
@@ -54,7 +54,7 @@ describe BitexBot::SellOpeningFlow do
|
|
54
54
|
|
55
55
|
flow.value_to_use.should == 4
|
56
56
|
flow.price.should >= flow.suggested_closing_price
|
57
|
-
flow.price.should == "37.78195488721804".to_d
|
57
|
+
flow.price.round(14).should == "37.78195488721804".to_d
|
58
58
|
flow.suggested_closing_price.should == 25
|
59
59
|
flow.order_id.should == 12345
|
60
60
|
end
|
@@ -97,7 +97,7 @@ describe BitexBot::SellOpeningFlow do
|
|
97
97
|
flow = BitexBot::SellOpeningFlow.create_for_market(1000,
|
98
98
|
bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
|
99
99
|
|
100
|
-
flow.price.should == "20.25112781954887".to_d
|
100
|
+
flow.price.round(14).should == "20.25112781954887".to_d
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
data/spec/spec_helper.rb
CHANGED
@@ -22,6 +22,8 @@ DatabaseCleaner.strategy = :truncation
|
|
22
22
|
|
23
23
|
RSpec.configure do |config|
|
24
24
|
config.include(FactoryGirl::Syntax::Methods)
|
25
|
+
config.include(Shoulda::Matchers::ActiveModel)
|
26
|
+
config.include(Shoulda::Matchers::ActiveRecord)
|
25
27
|
config.mock_with :rspec do |mocks|
|
26
28
|
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
27
29
|
mocks.syntax = [:expect, :should]
|
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.2.
|
4
|
+
version: 0.2.13
|
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: 2016-04-
|
12
|
+
date: 2016-04-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: settingslogic
|
@@ -109,6 +109,20 @@ dependencies:
|
|
109
109
|
- - '='
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: 0.0.6
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: bitfinex-rb
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 0.0.6
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.0.6
|
112
126
|
- !ruby/object:Gem::Dependency
|
113
127
|
name: mail
|
114
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -285,6 +299,7 @@ files:
|
|
285
299
|
- bitex_bot.gemspec
|
286
300
|
- lib/bitex_bot.rb
|
287
301
|
- lib/bitex_bot/database.rb
|
302
|
+
- lib/bitex_bot/models/bitfinex_api_wrapper.rb
|
288
303
|
- lib/bitex_bot/models/bitstamp_api_wrapper.rb
|
289
304
|
- lib/bitex_bot/models/buy_closing_flow.rb
|
290
305
|
- lib/bitex_bot/models/buy_opening_flow.rb
|