bitex_bot 0.3.7 → 0.4.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.
- 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
data/spec/models/robot_spec.rb
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe BitexBot::Robot do
|
4
|
+
let(:taker_settings) do
|
5
|
+
BitexBot::SettingsClass.new(
|
6
|
+
bitstamp: {
|
7
|
+
api_key: 'YOUR_API_KEY', secret: 'YOUR_API_SECRET', client_id: 'YOUR_BITSTAMP_USERNAME'
|
8
|
+
}
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
4
12
|
before(:each) do
|
13
|
+
BitexBot::Settings.stub(taker: taker_settings)
|
14
|
+
BitexBot::Robot.setup
|
5
15
|
BitexBot::Settings.stub(
|
6
16
|
time_to_live: 10,
|
7
|
-
buying: double(
|
8
|
-
|
9
|
-
profit: 0),
|
10
|
-
selling: double(
|
11
|
-
quantity_to_sell_per_order: 1,
|
12
|
-
profit: 0),
|
17
|
+
buying: double(amount_to_spend_per_order: 50, profit: 0),
|
18
|
+
selling: double(quantity_to_sell_per_order: 1, profit: 0),
|
13
19
|
mailer: double(
|
14
20
|
from: 'test@test.com',
|
15
21
|
to: 'test@test.com',
|
@@ -17,7 +23,6 @@ describe BitexBot::Robot do
|
|
17
23
|
options: {}
|
18
24
|
)
|
19
25
|
)
|
20
|
-
Bitex.api_key = "valid_key"
|
21
26
|
Bitex::Profile.stub(get: {
|
22
27
|
fee: 0.5,
|
23
28
|
usd_balance: 10000.00, # Total USD balance
|
@@ -28,20 +33,22 @@ describe BitexBot::Robot do
|
|
28
33
|
btc_available: 15.00000000, # BTC available for trading
|
29
34
|
ltc_balance: 250.00000000, # Total LTC balance
|
30
35
|
ltc_reserved: 100.00000000, # LTC reserved in open orders
|
31
|
-
ltc_available: 150.00000000
|
36
|
+
ltc_available: 150.00000000 # LTC available for trading
|
32
37
|
})
|
33
38
|
stub_bitex_orders
|
34
39
|
stub_bitstamp_sell
|
35
40
|
stub_bitstamp_buy
|
36
|
-
|
37
|
-
|
41
|
+
stub_bitstamp_api_wrapper_balance
|
42
|
+
stub_bitstamp_api_wrapper_order_book
|
38
43
|
stub_bitstamp_transactions
|
39
|
-
|
44
|
+
stub_bitstamp_empty_user_transactions
|
40
45
|
end
|
41
|
-
|
46
|
+
|
47
|
+
let(:bot) { BitexBot::Robot.new }
|
42
48
|
|
43
49
|
it 'Starts out by creating opening flows that timeout' do
|
44
50
|
stub_bitex_orders
|
51
|
+
stub_bitstamp_api_wrapper_order_book
|
45
52
|
bot.trade!
|
46
53
|
stub_bitex_transactions
|
47
54
|
buying = BitexBot::BuyOpeningFlow.last
|
@@ -49,7 +56,7 @@ describe BitexBot::Robot do
|
|
49
56
|
|
50
57
|
Timecop.travel 10.minutes.from_now
|
51
58
|
bot.trade!
|
52
|
-
|
59
|
+
|
53
60
|
buying.reload.should be_settling
|
54
61
|
selling.reload.should be_settling
|
55
62
|
|
@@ -57,7 +64,7 @@ describe BitexBot::Robot do
|
|
57
64
|
buying.reload.should be_finalised
|
58
65
|
selling.reload.should be_finalised
|
59
66
|
end
|
60
|
-
|
67
|
+
|
61
68
|
it 'creates alternating opening flows' do
|
62
69
|
Bitex::Trade.stub(all: [])
|
63
70
|
bot.trade!
|
@@ -68,7 +75,7 @@ describe BitexBot::Robot do
|
|
68
75
|
Timecop.travel 5.seconds.from_now
|
69
76
|
bot.trade!
|
70
77
|
BitexBot::BuyOpeningFlow.active.count.should == 2
|
71
|
-
|
78
|
+
|
72
79
|
# When transactions appear, all opening flows
|
73
80
|
# should get old and die.
|
74
81
|
# We stub our finder to make it so all orders
|
@@ -89,7 +96,7 @@ describe BitexBot::Robot do
|
|
89
96
|
stub_bitex_transactions
|
90
97
|
expect do
|
91
98
|
bot.trade!
|
92
|
-
end.to change{ BitexBot::BuyClosingFlow.count }.by(1)
|
99
|
+
end.to change { BitexBot::BuyClosingFlow.count }.by(1)
|
93
100
|
|
94
101
|
Timecop.travel 15.seconds.from_now
|
95
102
|
bot.trade!
|
@@ -101,25 +108,25 @@ describe BitexBot::Robot do
|
|
101
108
|
expect do
|
102
109
|
bot.trade!
|
103
110
|
bot.should_not be_active_closing_flows
|
104
|
-
end.to change{ BitexBot::BuyOpeningFlow.count }.by(1)
|
111
|
+
end.to change { BitexBot::BuyOpeningFlow.count }.by(1)
|
105
112
|
end
|
106
|
-
|
113
|
+
|
107
114
|
it 'does not place new opening flows when ordered to hold' do
|
108
115
|
other_bot = BitexBot::Robot.new
|
109
116
|
other_bot.store.hold = true
|
110
117
|
other_bot.store.save!
|
111
118
|
expect do
|
112
119
|
bot.trade!
|
113
|
-
end.not_to change{ BitexBot::BuyOpeningFlow.count }
|
120
|
+
end.not_to change { BitexBot::BuyOpeningFlow.count }
|
114
121
|
end
|
115
122
|
|
116
|
-
it 'stops trading when
|
123
|
+
it 'stops trading when fiat stop is reached' do
|
117
124
|
other_bot = BitexBot::Robot.new
|
118
|
-
other_bot.store.
|
125
|
+
other_bot.store.btc_stop = 30
|
119
126
|
other_bot.store.save!
|
120
127
|
expect do
|
121
128
|
bot.trade!
|
122
|
-
end.not_to change{ BitexBot::BuyOpeningFlow.count }
|
129
|
+
end.not_to change { BitexBot::BuyOpeningFlow.count }
|
123
130
|
end
|
124
131
|
|
125
132
|
it 'stops trading when usd stop is reached' do
|
@@ -128,27 +135,36 @@ describe BitexBot::Robot do
|
|
128
135
|
other_bot.store.save!
|
129
136
|
expect do
|
130
137
|
bot.trade!
|
131
|
-
end.not_to change{ BitexBot::BuyOpeningFlow.count }
|
138
|
+
end.not_to change { BitexBot::BuyOpeningFlow.count }
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'stops trading when btc stop is reached' do
|
142
|
+
other_bot = BitexBot::Robot.new
|
143
|
+
other_bot.store.fiat_stop = 11000
|
144
|
+
other_bot.store.save!
|
145
|
+
expect do
|
146
|
+
bot.trade!
|
147
|
+
end.not_to change { BitexBot::BuyOpeningFlow.count }
|
132
148
|
end
|
133
149
|
|
134
150
|
it 'warns every 30 minutes when usd warn is reached' do
|
135
151
|
Bitex::Trade.stub(all: [])
|
136
152
|
other_bot = BitexBot::Robot.new
|
137
|
-
other_bot.store.
|
153
|
+
other_bot.store.fiat_warning = 11000
|
138
154
|
other_bot.store.save!
|
139
155
|
expect do
|
140
156
|
bot.trade!
|
141
|
-
end.to change{ Mail::TestMailer.deliveries.count }.by(1)
|
157
|
+
end.to change { Mail::TestMailer.deliveries.count }.by(1)
|
142
158
|
Timecop.travel 1.minute.from_now
|
143
|
-
stub_bitstamp_order_book # Re-stub so
|
159
|
+
stub_bitstamp_order_book # Re-stub so order book does not get old
|
144
160
|
expect do
|
145
161
|
bot.trade!
|
146
|
-
end.not_to change{ Mail::TestMailer.deliveries.count }
|
162
|
+
end.not_to change { Mail::TestMailer.deliveries.count }
|
147
163
|
Timecop.travel 31.minutes.from_now
|
148
|
-
stub_bitstamp_order_book # Re-stub so
|
164
|
+
stub_bitstamp_order_book # Re-stub so order book does not get old
|
149
165
|
expect do
|
150
166
|
bot.trade!
|
151
|
-
end.to change{ Mail::TestMailer.deliveries.count }.by(1)
|
167
|
+
end.to change { Mail::TestMailer.deliveries.count }.by(1)
|
152
168
|
end
|
153
169
|
|
154
170
|
it 'warns every 30 minutes when btc warn is reached' do
|
@@ -156,38 +172,36 @@ describe BitexBot::Robot do
|
|
156
172
|
other_bot = BitexBot::Robot.new
|
157
173
|
other_bot.store.btc_warning = 30
|
158
174
|
other_bot.store.save!
|
175
|
+
|
159
176
|
expect do
|
160
177
|
bot.trade!
|
161
|
-
end.to change{ Mail::TestMailer.deliveries.count }.by(1)
|
178
|
+
end.to change { Mail::TestMailer.deliveries.count }.by(1)
|
179
|
+
|
162
180
|
Timecop.travel 1.minute.from_now
|
163
|
-
stub_bitstamp_order_book # Re-stub so
|
181
|
+
stub_bitstamp_order_book # Re-stub so order book does not get old
|
164
182
|
expect do
|
165
183
|
bot.trade!
|
166
|
-
end.not_to change{ Mail::TestMailer.deliveries.count }
|
184
|
+
end.not_to change { Mail::TestMailer.deliveries.count }
|
185
|
+
|
167
186
|
Timecop.travel 31.minutes.from_now
|
168
|
-
stub_bitstamp_order_book # Re-stub so
|
187
|
+
stub_bitstamp_order_book # Re-stub so order book does not get old
|
188
|
+
|
169
189
|
expect do
|
170
190
|
bot.trade!
|
171
|
-
end.to change{ Mail::TestMailer.deliveries.count }.by(1)
|
191
|
+
end.to change { Mail::TestMailer.deliveries.count }.by(1)
|
172
192
|
end
|
173
|
-
|
174
|
-
it 'updates
|
193
|
+
|
194
|
+
it 'updates taker_fiat and taker_btc' do
|
175
195
|
bot.trade!
|
176
|
-
bot.store.
|
196
|
+
bot.store.taker_fiat.should_not be_nil
|
177
197
|
bot.store.taker_btc.should_not be_nil
|
178
198
|
end
|
179
|
-
|
199
|
+
|
180
200
|
it 'notifies exceptions and sleeps' do
|
181
|
-
|
182
|
-
|
183
|
-
end
|
201
|
+
BitstampApiWrapper.stub(:balance) { raise StandardError.new('oh moova') }
|
202
|
+
|
184
203
|
expect do
|
185
204
|
bot.trade!
|
186
|
-
end.to change{ Mail::TestMailer.deliveries.count }.by(1)
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'knows how to setup sandbox mode for both gems' do
|
190
|
-
pending
|
191
|
-
fail
|
205
|
+
end.to change { Mail::TestMailer.deliveries.count }.by(1)
|
192
206
|
end
|
193
207
|
end
|
@@ -1,101 +1,166 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe BitexBot::SellClosingFlow do
|
4
|
-
|
4
|
+
let(:taker_settings) do
|
5
|
+
BitexBot::SettingsClass.new(
|
6
|
+
bitstamp: {
|
7
|
+
api_key: 'YOUR_API_KEY', secret: 'YOUR_API_SECRET', client_id: 'YOUR_BITSTAMP_USERNAME'
|
8
|
+
}
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
BitexBot::Settings.stub(taker: taker_settings)
|
14
|
+
BitexBot::Robot.setup
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'closes a single open position completely' do
|
5
18
|
stub_bitstamp_buy
|
6
19
|
open = create :open_sell
|
7
|
-
|
20
|
+
BitexBot::SellClosingFlow.close_open_positions
|
21
|
+
flow = BitexBot::SellClosingFlow.last
|
22
|
+
|
8
23
|
open.reload.closing_flow.should == flow
|
24
|
+
|
9
25
|
flow.open_positions.should == [open]
|
10
26
|
flow.desired_price.should == 290
|
11
27
|
flow.quantity.should == 2
|
12
28
|
flow.amount.should == 600
|
13
29
|
flow.btc_profit.should be_nil
|
14
|
-
flow.
|
30
|
+
flow.fiat_profit.should be_nil
|
31
|
+
|
15
32
|
close = flow.close_positions.first
|
16
33
|
close.order_id.should == '1'
|
17
34
|
close.amount.should be_nil
|
18
35
|
close.quantity.should be_nil
|
19
36
|
end
|
20
|
-
|
21
|
-
it
|
37
|
+
|
38
|
+
it 'closes an aggregate of several open positions' do
|
22
39
|
stub_bitstamp_buy
|
23
40
|
open_one = create :tiny_open_sell
|
24
41
|
open_two = create :open_sell
|
25
|
-
|
42
|
+
BitexBot::SellClosingFlow.close_open_positions
|
43
|
+
flow = BitexBot::SellClosingFlow.last
|
44
|
+
|
26
45
|
close = flow.close_positions.first
|
46
|
+
|
27
47
|
open_one.reload.closing_flow.should == flow
|
28
48
|
open_two.reload.closing_flow.should == flow
|
49
|
+
|
29
50
|
flow.open_positions.should == [open_one, open_two]
|
30
|
-
flow.desired_price.round(
|
51
|
+
flow.desired_price.round(10).should == '290.4975124378'.to_d
|
31
52
|
flow.quantity.should == 2.01
|
32
53
|
flow.amount.should == 604
|
33
54
|
flow.btc_profit.should be_nil
|
34
|
-
flow.
|
55
|
+
flow.fiat_profit.should be_nil
|
56
|
+
|
35
57
|
close.order_id.should == '1'
|
36
58
|
close.amount.should be_nil
|
37
59
|
close.quantity.should be_nil
|
38
60
|
end
|
39
61
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
62
|
+
describe 'when there are errors placing the closing order' do
|
63
|
+
it 'keeps trying to place a closed position on bitstamp errors' do
|
64
|
+
BitstampApiWrapper.stub(send_order: nil)
|
65
|
+
BitstampApiWrapper.stub(find_lost: nil)
|
66
|
+
|
67
|
+
open = create :open_sell
|
68
|
+
expect do
|
69
|
+
flow = BitexBot::SellClosingFlow.close_open_positions
|
70
|
+
end.to raise_exception(OrderNotFound)
|
71
|
+
flow = BitexBot::SellClosingFlow.last
|
72
|
+
|
73
|
+
open.reload.closing_flow.should == flow
|
74
|
+
|
75
|
+
flow.open_positions.should == [open]
|
76
|
+
flow.desired_price.should == 290
|
77
|
+
flow.quantity.should == 2
|
78
|
+
flow.btc_profit.should be_nil
|
79
|
+
flow.fiat_profit.should be_nil
|
80
|
+
flow.close_positions.should be_empty
|
44
81
|
end
|
45
|
-
open = create :open_sell
|
46
|
-
flow = BitexBot::SellClosingFlow.close_open_positions
|
47
|
-
open.reload.closing_flow.should == flow
|
48
|
-
flow.open_positions.should == [open]
|
49
|
-
flow.desired_price.should == 290
|
50
|
-
flow.quantity.should == 2
|
51
|
-
flow.btc_profit.should be_nil
|
52
|
-
flow.usd_profit.should be_nil
|
53
|
-
flow.close_positions.should be_empty
|
54
82
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
83
|
+
it 'retries until it finds the lost order' do
|
84
|
+
BitstampApiWrapper.stub(send_order: nil)
|
85
|
+
BitstampApiWrapper.stub(:orders) do
|
86
|
+
[BitstampApiWrapper::Order.new(1, :buy, 290, 2, 1.minute.ago.to_i)]
|
87
|
+
end
|
88
|
+
|
89
|
+
open = create(:open_sell)
|
90
|
+
BitexBot::SellClosingFlow.close_open_positions
|
91
|
+
flow = BitexBot::SellClosingFlow.last
|
92
|
+
|
93
|
+
flow.close_positions.should_not be_empty
|
94
|
+
flow.close_positions.first do |position|
|
95
|
+
position.id.should eq 1234
|
96
|
+
position.type.should eq 1
|
97
|
+
position.amount.should eq 1000
|
98
|
+
position.price.should eq 2000
|
99
|
+
end
|
100
|
+
end
|
62
101
|
end
|
63
|
-
|
64
|
-
it
|
102
|
+
|
103
|
+
it 'does not try to close if the amount is too low' do
|
65
104
|
open = create :tiny_open_sell
|
66
105
|
expect do
|
67
106
|
BitexBot::SellClosingFlow.close_open_positions.should be_nil
|
68
107
|
end.not_to change{ BitexBot::SellClosingFlow.count }
|
69
108
|
end
|
70
|
-
|
71
|
-
it
|
109
|
+
|
110
|
+
it 'does not try to close if there are no open positions' do
|
72
111
|
expect do
|
73
112
|
BitexBot::SellClosingFlow.close_open_positions.should be_nil
|
74
113
|
end.not_to change{ BitexBot::SellClosingFlow.count }
|
75
114
|
end
|
76
|
-
|
77
|
-
describe
|
115
|
+
|
116
|
+
describe 'when syncinc executed orders' do
|
78
117
|
before(:each) do
|
79
118
|
stub_bitstamp_buy
|
80
|
-
|
119
|
+
stub_bitstamp_empty_user_transactions
|
81
120
|
create :tiny_open_sell
|
82
121
|
create :open_sell
|
83
122
|
end
|
84
|
-
|
85
|
-
it
|
86
|
-
|
123
|
+
|
124
|
+
it 'syncs the executed orders, calculates profit' do
|
125
|
+
BitexBot::SellClosingFlow.close_open_positions
|
126
|
+
flow = BitexBot::SellClosingFlow.last
|
87
127
|
stub_bitstamp_orders_into_transactions
|
128
|
+
|
88
129
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
130
|
+
|
89
131
|
close = flow.close_positions.last
|
90
|
-
close.amount.should ==
|
132
|
+
close.amount.should == '583.905'.to_d
|
91
133
|
close.quantity.should == 2.01
|
134
|
+
|
92
135
|
flow.should be_done
|
93
136
|
flow.btc_profit.should == 0
|
94
|
-
flow.
|
137
|
+
flow.fiat_profit.should == '20.095'.to_d
|
95
138
|
end
|
96
|
-
|
97
|
-
|
98
|
-
|
139
|
+
|
140
|
+
context 'with other fx rate and closed open positions' do
|
141
|
+
let(:fx_rate) { 10.to_d }
|
142
|
+
let(:flow) { subject.class.last }
|
143
|
+
let(:positions_balance_amount) { flow.open_positions.sum(:amount) - flow.positions_balance_amount }
|
144
|
+
|
145
|
+
before(:each) do
|
146
|
+
BitexBot::Settings.stub(fx_rate: fx_rate)
|
147
|
+
subject.class.close_open_positions
|
148
|
+
|
149
|
+
stub_bitstamp_orders_into_transactions
|
150
|
+
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'syncs the executed orders, calculates profit with other fx rate' do
|
154
|
+
flow.should be_done
|
155
|
+
flow.btc_profit.should be_zero
|
156
|
+
flow.fiat_profit.should eq positions_balance_amount
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'retries closing at a higher price every minute' do
|
161
|
+
BitexBot::SellClosingFlow.close_open_positions
|
162
|
+
flow = BitexBot::SellClosingFlow.last
|
163
|
+
|
99
164
|
expect do
|
100
165
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
101
166
|
end.not_to change{ BitexBot::CloseSell.count }
|
@@ -115,36 +180,38 @@ describe BitexBot::SellClosingFlow do
|
|
115
180
|
end.not_to change{ BitexBot::CloseSell.count }
|
116
181
|
Bitstamp.orders.all.size.should == 0
|
117
182
|
flow.should_not be_done
|
118
|
-
|
183
|
+
|
119
184
|
# Next time we try to sync_closed_positions the flow
|
120
185
|
# detects the previous close_buy was cancelled correctly so
|
121
186
|
# it syncs it's total amounts and tries to place a new one.
|
122
187
|
expect do
|
123
188
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
124
189
|
end.to change{ BitexBot::CloseSell.count }.by(1)
|
190
|
+
|
125
191
|
flow.close_positions.first.tap do |close|
|
126
|
-
close.amount.should ==
|
192
|
+
close.amount.should == '291.9525'.to_d
|
127
193
|
close.quantity.should == 1.005
|
128
194
|
end
|
129
195
|
|
130
196
|
# The second ask is executed completely so we can wrap it up and consider
|
131
197
|
# this closing flow done.
|
132
198
|
stub_bitstamp_orders_into_transactions
|
199
|
+
|
133
200
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
134
201
|
flow.close_positions.last.tap do |close|
|
135
|
-
close.amount.should ==
|
202
|
+
close.amount.should == '291.953597'.to_d
|
136
203
|
close.quantity.should == '1.0049'.to_d
|
137
204
|
end
|
138
205
|
flow.should be_done
|
139
206
|
flow.btc_profit.should == '-0.0001'.to_d
|
140
|
-
flow.
|
141
|
-
|
207
|
+
flow.fiat_profit.should == '20.093903'.to_d
|
142
208
|
end
|
143
|
-
|
144
|
-
it "does not retry for an amount less than minimum_for_closing" do
|
145
|
-
flow = BitexBot::SellClosingFlow.close_open_positions
|
146
209
|
|
147
|
-
|
210
|
+
it 'does not retry for an amount less than minimum_for_closing' do
|
211
|
+
BitexBot::SellClosingFlow.close_open_positions
|
212
|
+
flow = BitexBot::SellClosingFlow.last
|
213
|
+
|
214
|
+
20.times do
|
148
215
|
Timecop.travel 60.seconds.from_now
|
149
216
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
150
217
|
end
|
@@ -158,14 +225,16 @@ describe BitexBot::SellClosingFlow do
|
|
158
225
|
|
159
226
|
flow.should be_done
|
160
227
|
flow.btc_profit.should == '-0.0224895'.to_d
|
161
|
-
flow.
|
228
|
+
flow.fiat_profit.should == '20.66566825'.to_d
|
162
229
|
end
|
163
|
-
|
164
|
-
it
|
230
|
+
|
231
|
+
it 'can lose BTC if price had to be raised dramatically' do
|
165
232
|
# This flow is forced to spend the original USD amount paying more than
|
166
233
|
# expected, thus regaining less BTC than what was sold on bitex.
|
167
|
-
|
168
|
-
|
234
|
+
BitexBot::SellClosingFlow.close_open_positions
|
235
|
+
flow = BitexBot::SellClosingFlow.last
|
236
|
+
|
237
|
+
60.times do
|
169
238
|
Timecop.travel 60.seconds.from_now
|
170
239
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
171
240
|
end
|
@@ -173,13 +242,12 @@ describe BitexBot::SellClosingFlow do
|
|
173
242
|
stub_bitstamp_orders_into_transactions
|
174
243
|
|
175
244
|
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
176
|
-
|
177
245
|
flow.reload.should be_done
|
178
|
-
flow.btc_profit.should ==
|
179
|
-
flow.
|
246
|
+
flow.btc_profit.should == '-0.1709'.to_d
|
247
|
+
flow.fiat_profit.should == '20.08575'.to_d
|
248
|
+
|
180
249
|
close = flow.close_positions.last
|
181
|
-
(close.amount / close.quantity)
|
182
|
-
.should == '317.5'.to_d
|
250
|
+
(close.amount / close.quantity).should == '317.5'.to_d
|
183
251
|
end
|
184
252
|
end
|
185
253
|
end
|