bitex_bot 0.1.6 → 0.2.0

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.
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