bitex_bot 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/bitex_bot.gemspec CHANGED
@@ -27,7 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "sqlite3"
28
28
  spec.add_dependency "bitstamp"
29
29
  spec.add_dependency "bitex", "0.1.4"
30
+ spec.add_dependency "itbit", "0.0.2"
30
31
  spec.add_dependency "mail"
32
+ spec.add_dependency "hashie"
31
33
 
32
34
  spec.add_development_dependency "bundler", "~> 1.3"
33
35
  spec.add_development_dependency "rake"
@@ -73,7 +73,7 @@ module BitexBot
73
73
  t.belongs_to :closing_flow
74
74
  t.decimal :amount, precision: 30, scale: 15
75
75
  t.decimal :quantity, precision: 30, scale: 15
76
- t.integer :order_id
76
+ t.string :order_id
77
77
  t.timestamps
78
78
  end
79
79
  add_index :close_buys, :order_id
@@ -82,7 +82,7 @@ module BitexBot
82
82
  t.belongs_to :closing_flow
83
83
  t.decimal :amount, precision: 30, scale: 15
84
84
  t.decimal :quantity, precision: 30, scale: 15
85
- t.integer :order_id
85
+ t.string :order_id
86
86
  t.timestamps
87
87
  end
88
88
  add_index :close_sells, :order_id
@@ -90,8 +90,8 @@ module BitexBot
90
90
 
91
91
  unless ActiveRecord::Base.connection.table_exists?('stores')
92
92
  create_table "stores", force: true do |t|
93
- t.decimal "bitstamp_usd", precision: 20, scale: 8
94
- t.decimal "bitstamp_btc", precision: 20, scale: 8
93
+ t.decimal "taker_usd", precision: 20, scale: 8
94
+ t.decimal "taker_btc", precision: 20, scale: 8
95
95
  t.boolean "hold", default: false
96
96
  t.text "log"
97
97
  t.decimal "usd_stop", precision: 20, scale: 8
@@ -0,0 +1,65 @@
1
+ class BitstampApiWrapper
2
+ def self.setup(settings)
3
+ Bitstamp.setup do |config|
4
+ config.key = settings.bitstamp.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
27
+ Bitstamp.order_book
28
+ end
29
+
30
+ # {"btc_balance"=> "10.0", "btc_reserved"=> "0", "btc_available"=> "10.0",
31
+ # "usd_balance"=> "100.0", "usd_reserved"=>"0", "usd_available"=> "100.0",
32
+ # "fee"=> "0.5000"}
33
+ def self.balance
34
+ Bitstamp.balance
35
+ end
36
+
37
+ # ask = double(amount: args[:amount], price: args[:price],
38
+ # type: 1, id: remote_id, datetime: DateTime.now.to_s)
39
+ # ask.stub(:cancel!) do
40
+ def self.orders
41
+ Bitstamp.orders.all
42
+ end
43
+
44
+ # double(usd: (usd * ratio).to_s, btc: (btc * ratio).to_s,
45
+ # btc_usd: o.price.to_s, order_id: o.id, fee: "0.5", type: 2,
46
+ # datetime: DateTime.now.to_s)
47
+ def self.user_transactions
48
+ Bitstamp.user_transactions.all
49
+ end
50
+
51
+ def self.order_is_done?(order)
52
+ order.nil?
53
+ end
54
+
55
+ def self.amount_and_quantity(order_id, transactions)
56
+ closes = transactions.select{|t| t.order_id.to_s == order_id}
57
+ amount = closes.collect{|x| x.usd.to_d }.sum.abs
58
+ quantity = closes.collect{|x| x.btc.to_d }.sum.abs
59
+ [amount, quantity]
60
+ end
61
+
62
+ def self.place_order(type, price, quantity)
63
+ Bitstamp.orders.send(type, amount: quantity, price: price)
64
+ end
65
+ end
@@ -34,8 +34,8 @@ module BitexBot
34
34
  end
35
35
 
36
36
  def create_order_and_close_position(quantity, price)
37
- order = Bitstamp.orders.send(order_method,
38
- amount: quantity.round(4), price: price.round(2))
37
+ order = BitexBot::Robot.taker.place_order(
38
+ order_method, price.round(2), quantity.round(4))
39
39
  if order.nil? || order.id.nil?
40
40
  Robot.logger.error("Closing: Error on #{order_method} for "\
41
41
  "#{self.class.name} ##{id} #{quantity} BTC @ $#{price}."\
@@ -44,7 +44,7 @@ module BitexBot
44
44
  end
45
45
  Robot.logger.info("Closing: Going to #{order_method} ##{order.id} for"\
46
46
  "#{self.class.name} ##{id} #{quantity} BTC @ $#{price}")
47
- close_positions.create!(order_id: order.id.to_i)
47
+ close_positions.create!(order_id: order.id)
48
48
  end
49
49
 
50
50
  def sync_closed_positions(orders, transactions)
@@ -57,14 +57,14 @@ module BitexBot
57
57
  return
58
58
  end
59
59
 
60
- order = orders.find{|x| x.id.to_s == latest_close.order_id.to_s }
61
-
60
+ order_id = latest_close.order_id.to_s
61
+ order = orders.find{|x| x.id.to_s == order_id }
62
+
62
63
  # When ask is nil it means the other exchange is done executing it
63
64
  # so we can now have a look of all the sales that were spawned from it.
64
65
  if order.nil?
65
- closes = transactions.select{|t| t.order_id.to_s == latest_close.order_id.to_s}
66
- latest_close.amount = closes.collect{|x| x.usd.to_d }.sum.abs
67
- latest_close.quantity = closes.collect{|x| x.btc.to_d }.sum.abs
66
+ latest_close.amount, latest_close.quantity =
67
+ BitexBot::Robot.taker.amount_and_quantity(order_id, transactions)
68
68
  latest_close.save!
69
69
 
70
70
  next_price, next_quantity = get_next_price_and_quantity
@@ -0,0 +1,51 @@
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
+ Itbit::Order.create!(type, :xbtusd, quantity, price)
50
+ end
51
+ end
@@ -13,6 +13,9 @@ module BitexBot
13
13
  cattr_accessor :graceful_shutdown
14
14
  cattr_accessor :cooldown_until
15
15
  cattr_accessor :test_mode
16
+ cattr_accessor :taker do
17
+ Settings.taker == 'itbit' ? ItbitApiWrapper : BitstampApiWrapper
18
+ end
16
19
  cattr_accessor :logger do
17
20
  Logger.new(Settings.log.try(:file) || STDOUT, 10, 10240000).tap do |l|
18
21
  l.level = Logger.const_get(Settings.log.level.upcase)
@@ -45,11 +48,8 @@ module BitexBot
45
48
 
46
49
  def self.setup
47
50
  Bitex.api_key = Settings.bitex
48
- Bitstamp.setup do |config|
49
- config.key = Settings.bitstamp.key
50
- config.secret = Settings.bitstamp.secret
51
- config.client_id = Settings.bitstamp.client_id.to_s
52
- end
51
+ Bitex.sandbox = Settings.sandbox
52
+ taker.setup(Settings)
53
53
  end
54
54
 
55
55
  def self.with_cooldown(&block)
@@ -99,8 +99,8 @@ module BitexBot
99
99
  end
100
100
 
101
101
  def sync_closing_flows
102
- orders = with_cooldown{ Bitstamp.orders.all }
103
- transactions = with_cooldown{ Bitstamp.user_transactions.all }
102
+ orders = with_cooldown{ BitexBot::Robot.taker.orders }
103
+ transactions = with_cooldown{ BitexBot::Robot.taker.user_transactions }
104
104
 
105
105
  [BuyClosingFlow, SellClosingFlow].each do |kind|
106
106
  kind.active.each do |flow|
@@ -140,14 +140,14 @@ module BitexBot
140
140
  return
141
141
  end
142
142
 
143
- balances = with_cooldown{ Bitstamp.balance }
143
+ balances = with_cooldown{ BitexBot::Robot.taker.balance }
144
144
  profile = Bitex::Profile.get
145
145
 
146
146
  total_usd = balances['usd_balance'].to_d + profile[:usd_balance]
147
147
  total_btc = balances['btc_balance'].to_d + profile[:btc_balance]
148
148
 
149
- store.update_attributes(bitstamp_usd: balances['usd_balance'],
150
- bitstamp_btc: balances['btc_balance'])
149
+ store.update_attributes(taker_usd: balances['usd_balance'],
150
+ taker_btc: balances['btc_balance'])
151
151
 
152
152
  if store.last_warning.nil? || store.last_warning < 30.minutes.ago
153
153
  if store.usd_warning && total_usd <= store.usd_warning
@@ -172,8 +172,8 @@ module BitexBot
172
172
  return
173
173
  end
174
174
 
175
- order_book = with_cooldown{ Bitstamp.order_book }
176
- transactions = with_cooldown{ Bitstamp.transactions }
175
+ order_book = with_cooldown{ BitexBot::Robot.taker.order_book }
176
+ transactions = with_cooldown{ BitexBot::Robot.taker.transactions }
177
177
 
178
178
  unless recent_buying
179
179
  BuyOpeningFlow.create_for_market(
@@ -1,3 +1,3 @@
1
1
  module BitexBot
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/bitex_bot.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "bitex_bot/version"
2
+ require 'hashie'
2
3
  require "active_support"
3
4
  require "active_record"
4
5
  require "active_model"
@@ -6,6 +7,7 @@ require "mail"
6
7
  require "logger"
7
8
  require "bitex"
8
9
  require "bitstamp"
10
+ require "itbit"
9
11
  require "bitex_bot/settings"
10
12
  require "bitex_bot/database"
11
13
  require "bitex_bot/models/opening_flow.rb"
data/settings.yml.sample CHANGED
@@ -12,6 +12,14 @@ log:
12
12
  # competitive. About 20 seconds is a good number here.
13
13
  time_to_live: 20
14
14
 
15
+ # Use sandbox environments instead of live environments
16
+ # only available for bitex and itbit
17
+ sandbox: false
18
+
19
+ # Which market to use for taking (we're always makers on bitex)
20
+ # itbit or bitstamp
21
+ taker: bitstamp
22
+
15
23
  # Settings for buying on bitex and selling on bitstamp.
16
24
  buying:
17
25
  # Dollars to spend on each initial bitex bid.
@@ -58,6 +66,14 @@ bitstamp:
58
66
  secret: YOUR_API_SECRET
59
67
  client_id: YOUR_BITSTAMP_USERNAME
60
68
 
69
+ # These are passed in to the itbit gem:
70
+ # see https://github.com/bitex-la/itbit for more info.
71
+ itbit:
72
+ client_key = 'the-client-key'
73
+ secret = 'the-secret'
74
+ user_id = 'the-user-id'
75
+ default_wallet_id = 'wallet-000'
76
+
61
77
  # Settings for the ActiveRecord Database to use.
62
78
  # sqlite is just fine. Check this link for more options:
63
79
  # http://apidock.com/rails/ActiveRecord/Base/establish_connection/class
@@ -12,7 +12,7 @@ describe BitexBot::BuyClosingFlow do
12
12
  flow.btc_profit.should be_nil
13
13
  flow.usd_profit.should be_nil
14
14
  close = flow.close_positions.first
15
- close.order_id.should == 1
15
+ close.order_id.should == '1'
16
16
  close.amount.should be_nil
17
17
  close.quantity.should be_nil
18
18
  end
@@ -30,7 +30,7 @@ describe BitexBot::BuyClosingFlow do
30
30
  flow.quantity.should == 2.01
31
31
  flow.btc_profit.should be_nil
32
32
  flow.usd_profit.should be_nil
33
- close.order_id.should == 1
33
+ close.order_id.should == '1'
34
34
  close.amount.should be_nil
35
35
  close.quantity.should be_nil
36
36
  end
@@ -54,7 +54,7 @@ describe BitexBot::BuyClosingFlow do
54
54
  stub_bitstamp_sell
55
55
  flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
56
56
  close = flow.close_positions.first
57
- close.order_id.should == 1
57
+ close.order_id.should == '1'
58
58
  close.amount.should be_nil
59
59
  close.quantity.should be_nil
60
60
  end
@@ -167,10 +167,10 @@ describe BitexBot::Robot do
167
167
  end.to change{ Mail::TestMailer.deliveries.count }.by(1)
168
168
  end
169
169
 
170
- it 'updates bitstamp_usd and bitstamp_btc' do
170
+ it 'updates taker_usd and taker_btc' do
171
171
  bot.trade!
172
- bot.store.bitstamp_usd.should_not be_nil
173
- bot.store.bitstamp_btc.should_not be_nil
172
+ bot.store.taker_usd.should_not be_nil
173
+ bot.store.taker_btc.should_not be_nil
174
174
  end
175
175
 
176
176
  it 'notifies exceptions and sleeps' do
@@ -182,4 +182,8 @@ describe BitexBot::Robot do
182
182
  end.to change{ Mail::TestMailer.deliveries.count }.by(1)
183
183
  end
184
184
 
185
+ it 'knows how to setup sandbox mode for both gems' do
186
+ pending
187
+ fail
188
+ end
185
189
  end
@@ -13,7 +13,7 @@ describe BitexBot::SellClosingFlow do
13
13
  flow.btc_profit.should be_nil
14
14
  flow.usd_profit.should be_nil
15
15
  close = flow.close_positions.first
16
- close.order_id.should == 1
16
+ close.order_id.should == '1'
17
17
  close.amount.should be_nil
18
18
  close.quantity.should be_nil
19
19
  end
@@ -32,7 +32,7 @@ describe BitexBot::SellClosingFlow do
32
32
  flow.amount.should == 604
33
33
  flow.btc_profit.should be_nil
34
34
  flow.usd_profit.should be_nil
35
- close.order_id.should == 1
35
+ close.order_id.should == '1'
36
36
  close.amount.should be_nil
37
37
  close.quantity.should be_nil
38
38
  end
@@ -56,7 +56,7 @@ describe BitexBot::SellClosingFlow do
56
56
  stub_bitstamp_buy
57
57
  flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
58
58
  close = flow.close_positions.first
59
- close.order_id.should == 1
59
+ close.order_id.should == '1'
60
60
  close.amount.should be_nil
61
61
  close.quantity.should be_nil
62
62
  end
data/spec/spec_helper.rb CHANGED
@@ -43,3 +43,5 @@ RSpec.configure do |config|
43
43
  config.order = "random"
44
44
  end
45
45
 
46
+ I18n.enforce_available_locales = false
47
+
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.1.6
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-10-17 00:00:00.000000000 Z
13
+ date: 2014-11-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: settingslogic
@@ -108,6 +108,22 @@ dependencies:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
110
  version: 0.1.4
111
+ - !ruby/object:Gem::Dependency
112
+ name: itbit
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - '='
117
+ - !ruby/object:Gem::Version
118
+ version: 0.0.2
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - '='
125
+ - !ruby/object:Gem::Version
126
+ version: 0.0.2
111
127
  - !ruby/object:Gem::Dependency
112
128
  name: mail
113
129
  requirement: !ruby/object:Gem::Requirement
@@ -124,6 +140,22 @@ dependencies:
124
140
  - - ! '>='
125
141
  - !ruby/object:Gem::Version
126
142
  version: '0'
143
+ - !ruby/object:Gem::Dependency
144
+ name: hashie
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :runtime
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
127
159
  - !ruby/object:Gem::Dependency
128
160
  name: bundler
129
161
  requirement: !ruby/object:Gem::Requirement
@@ -289,11 +321,13 @@ files:
289
321
  - bitex_bot.gemspec
290
322
  - lib/bitex_bot.rb
291
323
  - lib/bitex_bot/database.rb
324
+ - lib/bitex_bot/models/bitstamp_api_wrapper.rb
292
325
  - lib/bitex_bot/models/buy_closing_flow.rb
293
326
  - lib/bitex_bot/models/buy_opening_flow.rb
294
327
  - lib/bitex_bot/models/close_buy.rb
295
328
  - lib/bitex_bot/models/close_sell.rb
296
329
  - lib/bitex_bot/models/closing_flow.rb
330
+ - lib/bitex_bot/models/itbit_api_wrapper.rb
297
331
  - lib/bitex_bot/models/open_buy.rb
298
332
  - lib/bitex_bot/models/open_sell.rb
299
333
  - lib/bitex_bot/models/opening_flow.rb