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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +63 -0
  3. data/.rubocop.yml +33 -0
  4. data/Gemfile +1 -1
  5. data/Rakefile +1 -1
  6. data/bin/bitex_bot +1 -1
  7. data/bitex_bot.gemspec +34 -34
  8. data/lib/bitex_bot/database.rb +67 -67
  9. data/lib/bitex_bot/models/api_wrappers/api_wrapper.rb +142 -0
  10. data/lib/bitex_bot/models/api_wrappers/bitstamp/bitstamp_api_wrapper.rb +137 -0
  11. data/lib/bitex_bot/models/api_wrappers/itbit/itbit_api_wrapper.rb +116 -0
  12. data/lib/bitex_bot/models/api_wrappers/kraken/kraken_api_wrapper.rb +111 -0
  13. data/lib/bitex_bot/models/api_wrappers/kraken/kraken_order.rb +117 -0
  14. data/lib/bitex_bot/models/buy_closing_flow.rb +23 -16
  15. data/lib/bitex_bot/models/buy_opening_flow.rb +48 -54
  16. data/lib/bitex_bot/models/close_buy.rb +2 -2
  17. data/lib/bitex_bot/models/closing_flow.rb +98 -79
  18. data/lib/bitex_bot/models/open_buy.rb +11 -10
  19. data/lib/bitex_bot/models/open_sell.rb +11 -10
  20. data/lib/bitex_bot/models/opening_flow.rb +157 -99
  21. data/lib/bitex_bot/models/order_book_simulator.rb +62 -67
  22. data/lib/bitex_bot/models/sell_closing_flow.rb +25 -20
  23. data/lib/bitex_bot/models/sell_opening_flow.rb +47 -54
  24. data/lib/bitex_bot/models/store.rb +3 -1
  25. data/lib/bitex_bot/robot.rb +203 -176
  26. data/lib/bitex_bot/settings.rb +71 -12
  27. data/lib/bitex_bot/version.rb +1 -1
  28. data/lib/bitex_bot.rb +40 -16
  29. data/settings.rb.sample +43 -66
  30. data/spec/bitex_bot/settings_spec.rb +87 -15
  31. data/spec/factories/bitex_buy.rb +3 -3
  32. data/spec/factories/bitex_sell.rb +3 -3
  33. data/spec/factories/buy_opening_flow.rb +1 -1
  34. data/spec/factories/open_buy.rb +12 -10
  35. data/spec/factories/open_sell.rb +12 -10
  36. data/spec/factories/sell_opening_flow.rb +1 -1
  37. data/spec/models/api_wrappers/bitstamp_api_wrapper_spec.rb +200 -0
  38. data/spec/models/api_wrappers/itbit_api_wrapper_spec.rb +176 -0
  39. data/spec/models/api_wrappers/kraken_api_wrapper_spec.rb +209 -0
  40. data/spec/models/bitex_api_spec.rb +1 -1
  41. data/spec/models/buy_closing_flow_spec.rb +140 -71
  42. data/spec/models/buy_opening_flow_spec.rb +126 -56
  43. data/spec/models/order_book_simulator_spec.rb +10 -10
  44. data/spec/models/robot_spec.rb +61 -47
  45. data/spec/models/sell_closing_flow_spec.rb +130 -62
  46. data/spec/models/sell_opening_flow_spec.rb +129 -60
  47. data/spec/spec_helper.rb +19 -16
  48. data/spec/support/bitex_stubs.rb +13 -14
  49. data/spec/support/bitstamp/bitstamp_api_wrapper_stubs.rb +35 -0
  50. data/spec/support/bitstamp/bitstamp_stubs.rb +91 -0
  51. metadata +60 -42
  52. data/lib/bitex_bot/models/bitfinex_api_wrapper.rb +0 -118
  53. data/lib/bitex_bot/models/bitstamp_api_wrapper.rb +0 -82
  54. data/lib/bitex_bot/models/itbit_api_wrapper.rb +0 -68
  55. data/lib/bitex_bot/models/kraken_api_wrapper.rb +0 -188
  56. data/spec/models/bitfinex_api_wrapper_spec.rb +0 -17
  57. data/spec/models/bitstamp_api_wrapper_spec.rb +0 -15
  58. data/spec/models/itbit_api_wrapper_spec.rb +0 -15
  59. data/spec/support/bitstamp_stubs.rb +0 -110
@@ -1,114 +1,164 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe BitexBot::SellOpeningFlow do
4
- before(:each) do
5
- Bitex.api_key = "valid_key"
6
- end
7
- let(:store){ BitexBot::Store.create }
4
+ before(:each) { Bitex.api_key = 'valid_key' }
5
+
6
+ let(:store) { BitexBot::Store.create }
8
7
 
9
8
  it { should validate_presence_of :status }
10
9
  it { should validate_presence_of :price }
11
10
  it { should validate_presence_of :value_to_use }
12
11
  it { should validate_presence_of :order_id }
13
- it { should(validate_inclusion_of(:status)
14
- .in_array(BitexBot::SellOpeningFlow.statuses)) }
12
+ it { should(validate_inclusion_of(:status).in_array(BitexBot::SellOpeningFlow.statuses)) }
15
13
 
16
- describe "when creating a selling flow" do
17
- it "sells 2 bitcoin" do
14
+ describe 'when creating a selling flow' do
15
+ it 'sells 2 bitcoin' do
18
16
  stub_bitex_orders
19
17
  BitexBot::Settings.stub(time_to_live: 3,
20
18
  selling: double(quantity_to_sell_per_order: 2, profit: 0))
21
19
 
22
20
  flow = BitexBot::SellOpeningFlow.create_for_market(1000,
23
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
24
-
21
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
22
+ store)
23
+
24
+ flow.order_id.should == 12345
25
25
  flow.value_to_use.should == 2
26
26
  flow.price.should >= flow.suggested_closing_price
27
- flow.price.should == "20.15037593984962".to_d
27
+ flow.price.truncate(14).should == '20.15037593984962'.to_d
28
28
  flow.suggested_closing_price.should == 20
29
- flow.order_id.should == 12345
30
29
  end
31
30
 
32
- it "sells 4 bitcoin" do
31
+ let(:order_id) { 12_345 }
32
+ let(:usd_price) { '25.18_796_992_481_203'.to_d }
33
+ let(:suggested_closing_price) { 25.to_d }
34
+ let(:amount_to_sell) { 4.to_d }
35
+ let(:btc_balance) { 100_000.to_d }
36
+ let(:maker_fee) { 0.5.to_d }
37
+ let(:taker_fee) { 0.25.to_d }
38
+ let(:orderbook) { bitstamp_api_wrapper_order_book.asks }
39
+ let(:transactions) { bitstamp_api_wrapper_transactions_stub }
40
+
41
+ it 'sells 4 bitcoin' do
42
+ BitexBot::Settings.stub(
43
+ time_to_live: 3,
44
+ selling: double(quantity_to_sell_per_order: amount_to_sell, profit: 0)
45
+ )
33
46
  stub_bitex_orders
34
- BitexBot::Settings.stub(time_to_live: 3,
35
- selling: double(quantity_to_sell_per_order: 4, profit: 0))
36
47
 
37
- flow = BitexBot::SellOpeningFlow.create_for_market(1000,
38
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
39
-
40
- flow.value_to_use.should == 4
48
+ flow =
49
+ BitexBot::SellOpeningFlow.create_for_market(
50
+ btc_balance,
51
+ orderbook,
52
+ transactions,
53
+ maker_fee,
54
+ taker_fee,
55
+ store
56
+ )
57
+
58
+ flow.order_id.should eq order_id
59
+ flow.value_to_use.should eq amount_to_sell
41
60
  flow.price.should >= flow.suggested_closing_price
42
- flow.price.round(14).should == "25.18796992481203".to_d
43
- flow.suggested_closing_price.should == 25
44
- flow.order_id.should == 12345
61
+ flow.price.should eq usd_price
62
+ flow.suggested_closing_price.should eq suggested_closing_price
63
+ end
64
+
65
+ let(:other_fx_rate) { 10.to_d }
66
+
67
+ it 'sells 4 bitcoin' do
68
+ BitexBot::Settings.stub(
69
+ fx_rate: other_fx_rate,
70
+ time_to_live: 3,
71
+ selling: double(quantity_to_sell_per_order: amount_to_sell, profit: 0)
72
+ )
73
+ stub_bitex_orders
74
+
75
+ flow =
76
+ BitexBot::SellOpeningFlow.create_for_market(
77
+ btc_balance,
78
+ orderbook,
79
+ transactions,
80
+ maker_fee,
81
+ taker_fee,
82
+ store
83
+ )
84
+
85
+ flow.order_id.should eq order_id
86
+ flow.value_to_use.should eq amount_to_sell
87
+ flow.price.should >= flow.suggested_closing_price * other_fx_rate
88
+ flow.price.truncate(13).should eq usd_price * other_fx_rate
89
+ flow.suggested_closing_price.should eq suggested_closing_price
45
90
  end
46
-
47
- it "raises the price to charge on bitex to take a profit" do
91
+
92
+ it 'raises the price to charge on bitex to take a profit' do
48
93
  stub_bitex_orders
49
94
  BitexBot::Settings.stub(time_to_live: 3,
50
- selling: double(quantity_to_sell_per_order: 4, profit: 50))
95
+ selling: double(quantity_to_sell_per_order: 4, profit: 50.to_d))
51
96
 
52
97
  flow = BitexBot::SellOpeningFlow.create_for_market(1000,
53
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
54
-
98
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
99
+ store)
100
+
101
+ flow.order_id.should == 12345
55
102
  flow.value_to_use.should == 4
56
103
  flow.price.should >= flow.suggested_closing_price
57
- flow.price.round(14).should == "37.78195488721804".to_d
104
+ flow.price.round(14).should == '37.78195488721804'.to_d
58
105
  flow.suggested_closing_price.should == 25
59
- flow.order_id.should == 12345
60
106
  end
61
-
62
- it "fails when there is a problem placing the ask on bitex" do
63
- Bitex::Ask.stub(:create!) do
64
- raise StandardError.new("Cannot Create")
65
- end
66
107
 
108
+ it 'fails when there is a problem placing the ask on bitex' do
109
+ Bitex::Ask.stub(:create!) { raise StandardError.new('Cannot Create') }
67
110
  BitexBot::Settings.stub(time_to_live: 3,
68
111
  selling: double(quantity_to_sell_per_order: 4, profit: 50))
69
112
 
70
113
  expect do
71
114
  flow = BitexBot::SellOpeningFlow.create_for_market(100000,
72
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
115
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
116
+ store)
117
+
73
118
  flow.should be_nil
74
119
  BitexBot::SellOpeningFlow.count.should == 0
75
120
  end.to raise_exception(BitexBot::CannotCreateFlow)
76
121
  end
77
-
78
- it "fails when there are not enough USD to re-buy in the other exchange" do
122
+
123
+ it 'fails when there are not enough USD to re-buy in the other exchange' do
79
124
  stub_bitex_orders
80
125
  BitexBot::Settings.stub(time_to_live: 3,
81
126
  selling: double(quantity_to_sell_per_order: 4, profit: 50))
82
127
 
83
128
  expect do
84
129
  flow = BitexBot::SellOpeningFlow.create_for_market(1,
85
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
130
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
131
+ store)
132
+
86
133
  flow.should be_nil
87
134
  BitexBot::SellOpeningFlow.count.should == 0
88
135
  end.to raise_exception(BitexBot::CannotCreateFlow)
89
136
  end
90
137
 
91
- it "Prioritizes profit from store" do
92
- store = BitexBot::Store.new(selling_profit: 0.5)
138
+ it 'Prioritizes profit from store' do
93
139
  stub_bitex_orders
94
140
  BitexBot::Settings.stub(time_to_live: 3,
95
141
  selling: double(quantity_to_sell_per_order: 2, profit: 0))
96
142
 
143
+ store = BitexBot::Store.new(selling_profit: 0.5)
97
144
  flow = BitexBot::SellOpeningFlow.create_for_market(1000,
98
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
99
-
100
- flow.price.round(14).should == "20.25112781954887".to_d
145
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
146
+ store)
147
+
148
+ flow.price.round(14).should == '20.25112781954887'.to_d
101
149
  end
102
150
  end
103
-
104
- describe "when fetching open positions" do
105
- let(:flow){ create(:sell_opening_flow) }
151
+
152
+ describe 'when fetching open positions' do
153
+ let(:flow) { create(:sell_opening_flow) }
106
154
 
107
155
  it 'only gets sells' do
108
- flow.order_id.should == 12345
109
156
  stub_bitex_transactions
157
+
158
+ flow.order_id.should == 12345
110
159
  expect do
111
160
  all = BitexBot::SellOpeningFlow.sync_open_positions
161
+
112
162
  all.size.should == 1
113
163
  all.first.tap do |o|
114
164
  o.price.should == 300.0
@@ -117,50 +167,69 @@ describe BitexBot::SellOpeningFlow do
117
167
  o.transaction_id.should == 12345678
118
168
  o.opening_flow.should == flow
119
169
  end
120
- end.to change{ BitexBot::OpenSell.count }.by(1)
170
+ end.to change { BitexBot::OpenSell.count }.by(1)
121
171
  end
122
-
172
+
123
173
  it 'does not register the same buy twice' do
124
- flow.order_id.should == 12345
125
174
  stub_bitex_transactions
175
+
176
+ flow.order_id.should == 12345
126
177
  BitexBot::SellOpeningFlow.sync_open_positions
127
178
  BitexBot::OpenSell.count.should == 1
179
+
128
180
  Timecop.travel 1.second.from_now
129
181
  stub_bitex_transactions(build(:bitex_sell, id: 23456))
182
+
130
183
  expect do
131
184
  news = BitexBot::SellOpeningFlow.sync_open_positions
132
185
  news.first.transaction_id.should == 23456
133
- end.to change{ BitexBot::OpenSell.count }.by(1)
186
+ end.to change { BitexBot::OpenSell.count }.by(1)
134
187
  end
135
-
136
- it 'does not register litecoin buys' do
188
+
189
+ it 'does not register buys from another order book' do
190
+ Bitex::Trade.stub(all: [build(:bitex_sell, id: 23456, order_book: :btc_ars)])
191
+
137
192
  flow.order_id.should == 12345
138
- Bitex::Trade.stub(all: [build(:bitex_sell, id: 23456, specie: :ltc)])
139
193
  expect do
140
194
  BitexBot::SellOpeningFlow.sync_open_positions.should be_empty
141
- end.not_to change{ BitexBot::OpenSell.count }
195
+ end.not_to change { BitexBot::OpenSell.count }
142
196
  BitexBot::OpenSell.count.should == 0
143
197
  end
144
-
198
+
145
199
  it 'does not register buys from unknown bids' do
146
200
  stub_bitex_transactions
201
+
147
202
  expect do
148
203
  BitexBot::SellOpeningFlow.sync_open_positions.should be_empty
149
- end.not_to change{ BitexBot::OpenSell.count }
204
+ end.not_to change { BitexBot::OpenSell.count }
150
205
  end
151
206
  end
152
-
207
+
153
208
  it 'cancels the associated bitex bid' do
154
209
  stub_bitex_orders
155
210
  BitexBot::Settings.stub(time_to_live: 3,
156
211
  selling: double(quantity_to_sell_per_order: 4, profit: 50))
157
212
 
158
213
  flow = BitexBot::SellOpeningFlow.create_for_market(1000,
159
- bitstamp_order_book_stub['asks'], bitstamp_transactions_stub, 0.5, 0.25, store)
160
-
214
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
215
+ store)
216
+
161
217
  flow.finalise!
162
218
  flow.should be_settling
163
219
  flow.finalise!
164
220
  flow.should be_finalised
165
221
  end
222
+
223
+ it 'order has expected order book' do
224
+ stub_bitex_orders
225
+ BitexBot::Settings.stub(time_to_live: 3,
226
+ selling: double(quantity_to_sell_per_order: 2, profit: 0))
227
+
228
+ flow = subject.class.create_for_market(1000,
229
+ bitstamp_api_wrapper_order_book.asks, bitstamp_api_wrapper_transactions_stub, 0.5, 0.25,
230
+ store)
231
+
232
+ order = subject.class.order_class.find(flow.order_id)
233
+ order.order_book.should eq BitexBot::Settings.maker_settings.order_book
234
+ end
166
235
  end
data/spec/spec_helper.rb CHANGED
@@ -1,50 +1,53 @@
1
1
  require 'bundler/setup'
2
2
  Bundler.setup
3
3
 
4
- require "bitex_bot/settings"
4
+ require 'bitex_bot/settings'
5
5
  BitexBot::Settings.load_test
6
- require 'bitex_bot'
7
- require 'factory_girl'
6
+
7
+ require 'byebug'
8
8
  require 'database_cleaner'
9
+ require 'factory_bot'
9
10
  require 'shoulda/matchers'
10
11
  require 'timecop'
11
12
  require 'webmock/rspec'
12
- FactoryGirl.find_definitions
13
13
 
14
- Dir[File.dirname(__FILE__) + '/support/*.rb'].each {|file| require file }
14
+ require 'bitex_bot'
15
+ FactoryBot.find_definitions
16
+ Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |file| require file }
15
17
 
16
18
  # Automatically do rake db:test:prepare
17
19
  ActiveRecord::Migration.maintain_test_schema!
18
20
 
19
- # Transactional fixtures do not work with Selenium tests, because Capybara
20
- # uses a separate server thread, which the transactions would be hidden
21
- # from. We hence use DatabaseCleaner to truncate our test database.
21
+ # Transactional fixtures do not work with Selenium tests, because Capybara uses a separate server thread, which the transactions
22
+ # would be hidden from. We hence use DatabaseCleaner to truncate our test database.
22
23
  DatabaseCleaner.strategy = :truncation
23
24
 
24
25
  RSpec.configure do |config|
25
- config.include(FactoryGirl::Syntax::Methods)
26
+ config.include(FactoryBot::Syntax::Methods)
26
27
  config.include(Shoulda::Matchers::ActiveModel)
27
28
  config.include(Shoulda::Matchers::ActiveRecord)
28
29
  config.mock_with :rspec do |mocks|
29
30
  mocks.yield_receiver_to_any_instance_implementation_blocks = true
30
- mocks.syntax = [:expect, :should]
31
+ mocks.syntax = %i[expect should]
31
32
  end
32
33
  config.expect_with :rspec do |c|
33
- c.syntax = [:expect, :should]
34
+ c.syntax = %i[expect should]
34
35
  end
35
-
36
+
36
37
  config.before(:all) do
37
38
  BitexBot::Robot.logger = Logger.new('/dev/null')
38
- BitexBot::Robot.test_mode = true
39
+ end
40
+
41
+ config.before(:each) do
42
+ BitexBot::Robot.stub(:sleep_for)
39
43
  end
40
44
 
41
45
  config.after(:each) do
42
- DatabaseCleaner.clean # Truncate the database
46
+ DatabaseCleaner.clean
43
47
  Timecop.return
44
48
  end
45
49
 
46
- config.order = "random"
50
+ config.order = 'random'
47
51
  end
48
52
 
49
53
  I18n.enforce_available_locales = false
50
-
@@ -1,8 +1,8 @@
1
1
  module BitexStubs
2
- mattr_accessor(:bids){ {} }
3
- mattr_accessor(:asks){ {} }
4
- mattr_accessor(:active_bids){ {} }
5
- mattr_accessor(:active_asks){ {} }
2
+ mattr_accessor(:bids) { {} }
3
+ mattr_accessor(:asks) { {} }
4
+ mattr_accessor(:active_bids) { {} }
5
+ mattr_accessor(:active_asks) { {} }
6
6
 
7
7
  def stub_bitex_orders
8
8
  Bitex::Order.stub(:all) do
@@ -17,15 +17,15 @@ module BitexStubs
17
17
  BitexStubs.asks[id]
18
18
  end
19
19
 
20
- Bitex::Bid.stub(:create!) do |specie, to_spend, price|
20
+ Bitex::Bid.stub(:create!) do |order_book, to_spend, price|
21
21
  bid = Bitex::Bid.new
22
22
  bid.id = 12345
23
23
  bid.created_at = Time.now
24
24
  bid.price = price
25
25
  bid.amount = to_spend
26
26
  bid.remaining_amount = to_spend
27
- bid.status = :executing
28
- bid.specie = specie
27
+ bid.status = :executing
28
+ bid.order_book = order_book
29
29
  bid.stub(:cancel!) do
30
30
  bid.status = :cancelled
31
31
  BitexStubs.active_bids.delete(bid.id)
@@ -36,15 +36,15 @@ module BitexStubs
36
36
  bid
37
37
  end
38
38
 
39
- Bitex::Ask.stub(:create!) do |specie, to_sell, price|
39
+ Bitex::Ask.stub(:create!) do |order_book, to_sell, price|
40
40
  ask = Bitex::Ask.new
41
41
  ask.id = 12345
42
42
  ask.created_at = Time.now
43
43
  ask.price = price
44
44
  ask.quantity = to_sell
45
45
  ask.remaining_quantity = to_sell
46
- ask.status = :executing
47
- ask.specie = specie
46
+ ask.status = :executing
47
+ ask.order_book = order_book
48
48
  ask.stub(:cancel!) do
49
49
  ask.status = :cancelled
50
50
  BitexStubs.active_asks.delete(ask.id)
@@ -55,11 +55,10 @@ module BitexStubs
55
55
  ask
56
56
  end
57
57
  end
58
-
58
+
59
59
  def stub_bitex_transactions(*extra_transactions)
60
- Bitex::Trade.stub(all: extra_transactions + [
61
- build(:bitex_buy), build(:bitex_sell)
62
- ])
60
+ Bitex::Trade.stub(all: extra_transactions + [build(:bitex_buy), build(:bitex_sell)])
63
61
  end
64
62
  end
63
+
65
64
  RSpec.configuration.include BitexStubs
@@ -0,0 +1,35 @@
1
+ module BitstampApiWrapperStubs
2
+ def stub_bitstamp_api_wrapper_order_book
3
+ BitstampApiWrapper.stub(order_book: bitstamp_api_wrapper_order_book)
4
+ end
5
+
6
+ def bitstamp_api_wrapper_order_book
7
+ ApiWrapper::OrderBook.new(
8
+ Time.now.to_i,
9
+ [['30', '3'], ['25', '2'], ['20', '1.5'], ['15', '4'], ['10', '5']].map do |price, quantity|
10
+ ApiWrapper::OrderSummary.new(price.to_d, quantity.to_d)
11
+ end,
12
+ [['10', '2'], ['15', '3'], ['20', '1.5'], ['25', '3'], ['30', '3']].map do |price, quantity|
13
+ ApiWrapper::OrderSummary.new(price.to_d, quantity.to_d)
14
+ end
15
+ )
16
+ end
17
+
18
+ def stub_bitstamp_api_wrapper_balance(usd = nil, coin = nil, fee = nil)
19
+ BitstampApiWrapper.stub(:balance) do
20
+ ApiWrapper::BalanceSummary.new(
21
+ ApiWrapper::Balance.new((coin || 10).to_d, 0.to_d, (coin || 10).to_d),
22
+ ApiWrapper::Balance.new((usd || 100).to_d, 0.to_d, (usd || 100).to_d),
23
+ 0.5.to_d
24
+ )
25
+ end
26
+ end
27
+
28
+ def bitstamp_api_wrapper_transactions_stub(price = 30.to_d, amount = 1.to_d)
29
+ transactions = 5.times.collect do |i|
30
+ ApiWrapper::Transaction.new(i, price, amount, (i+1).seconds.ago.to_i)
31
+ end
32
+ end
33
+ end
34
+
35
+ RSpec.configuration.include BitstampApiWrapperStubs
@@ -0,0 +1,91 @@
1
+ module BitstampStubs
2
+ def stub_bitstamp_order_book
3
+ Bitstamp.stub(:order_book) do
4
+ {
5
+ 'timestamp' => Time.now.to_i.to_s,
6
+ 'bids' => [['30', '3'], ['25', '2'], ['20', '1.5'], ['15', '4'], ['10', '5']],
7
+ 'asks' => [['10', '2'], ['15', '3'], ['20', '1.5'], ['25', '3'], ['30', '3']]
8
+ }
9
+ end
10
+ end
11
+
12
+ # [<Bitstamp::Transactions @date="1380648951", @tid=14, @price="1.9", @amount="1.1">]
13
+ def stub_bitstamp_transactions(price = 0.2, amount = 1 )
14
+ Bitstamp.stub(:transactions) do
15
+ 5.times.collect do |i|
16
+ double(tid: i, date: (i+1).seconds.ago.to_i.to_s, price: price.to_s, amount: amount.to_s)
17
+ end
18
+ end
19
+ end
20
+
21
+ # TODO It's only used into robot_spec buy/sell_closing_flow
22
+ def stub_bitstamp_empty_user_transactions
23
+ Bitstamp.stub(user_transactions: double(all: []))
24
+ end
25
+
26
+ # TODO It's only used into robot_spec buy/sell_closing_flow
27
+ # Takes all active orders and mockes them as executed in a single transaction.
28
+ # If a ratio is provided then each order is only partially executed and added
29
+ # as a transaction and the order itself is kept in the order list.
30
+ def stub_bitstamp_orders_into_transactions(options = {})
31
+ ratio = options[:ratio] || 1
32
+ orders = Bitstamp.orders.all
33
+ transactions = orders.collect do |o|
34
+ usd = o.amount * o.price
35
+ usd, btc = o.type == 0 ? [-usd, o.amount] : [usd, -o.amount]
36
+ double(usd: (usd * ratio).to_s, btc: (btc * ratio).to_s,
37
+ btc_usd: o.price.to_s, order_id: o.id, fee: '0.5', type: 2,
38
+ datetime: DateTime.now.to_s)
39
+ end
40
+ Bitstamp.stub(user_transactions: double(all: transactions))
41
+
42
+ return unless ratio == 1
43
+ stub_bitstamp_sell
44
+ stub_bitstamp_buy
45
+ end
46
+
47
+ # TODO It's only used into robot_spec buy/sell_closing_flow_spec
48
+ def stub_bitstamp_sell(remote_id = nil, orders = [])
49
+ ensure_bitstamp_orders_stub
50
+ Bitstamp.orders.stub(all: orders)
51
+ Bitstamp.orders.stub(:sell) do |args|
52
+ remote_id = Bitstamp.orders.all.size + 1 if remote_id.nil?
53
+ ask = double(amount: args[:amount], price: args[:price], type: 1, id: remote_id,
54
+ datetime: DateTime.now.to_s)
55
+ ask.stub(:cancel!) do
56
+ orders = Bitstamp.orders.all.reject { |o| o.id.to_s == ask.id.to_s && o.type == 1 }
57
+ stub_bitstamp_sell(remote_id + 1, orders)
58
+ end
59
+ stub_bitstamp_sell(remote_id + 1, Bitstamp.orders.all + [ask])
60
+ ask
61
+ end
62
+ end
63
+
64
+ # TODO It's only used into robot_spec buy/sell_closing_flow_spec
65
+ def stub_bitstamp_buy(remote_id = nil, orders = [])
66
+ ensure_bitstamp_orders_stub
67
+ Bitstamp.orders.stub(all: orders)
68
+ Bitstamp.orders.stub(:buy) do |args|
69
+ remote_id = Bitstamp.orders.all.size + 1 if remote_id.nil?
70
+ bid = double(amount: args[:amount], price: args[:price], type: 0, id: remote_id,
71
+ datetime: DateTime.now.to_s)
72
+ bid.stub(:cancel!) do
73
+ orders = Bitstamp.orders.all.reject { |o| o.id.to_s == bid.id.to_s && o.type == 0 }
74
+ stub_bitstamp_buy(remote_id + 1, orders)
75
+ end
76
+ stub_bitstamp_buy(remote_id + 1, Bitstamp.orders.all + [bid])
77
+ bid
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ # TODO It's only used into robot_spec buy/sell_closing_flow_spec
84
+ def ensure_bitstamp_orders_stub
85
+ Bitstamp.orders
86
+ rescue Exception => e
87
+ Bitstamp.stub(orders: double)
88
+ end
89
+ end
90
+
91
+ RSpec.configuration.include BitstampStubs