bitex_bot 0.6.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/Gemfile +3 -1
- data/bitex_bot.gemspec +5 -2
- data/lib/bitex_bot/database.rb +2 -2
- data/lib/bitex_bot/models/api_wrappers/api_wrapper.rb +47 -35
- data/lib/bitex_bot/models/api_wrappers/bitex/bitex_api_wrapper.rb +178 -0
- data/lib/bitex_bot/models/api_wrappers/bitstamp/bitstamp_api_wrapper.rb +62 -45
- data/lib/bitex_bot/models/api_wrappers/itbit/itbit_api_wrapper.rb +52 -28
- data/lib/bitex_bot/models/api_wrappers/kraken/kraken_api_wrapper.rb +61 -28
- data/lib/bitex_bot/models/api_wrappers/kraken/kraken_order.rb +12 -6
- data/lib/bitex_bot/models/buy_closing_flow.rb +3 -2
- data/lib/bitex_bot/models/buy_opening_flow.rb +31 -6
- data/lib/bitex_bot/models/closing_flow.rb +37 -22
- data/lib/bitex_bot/models/open_buy.rb +1 -3
- data/lib/bitex_bot/models/open_sell.rb +1 -3
- data/lib/bitex_bot/models/opening_flow.rb +42 -28
- data/lib/bitex_bot/models/order_book_simulator.rb +14 -13
- data/lib/bitex_bot/models/sell_closing_flow.rb +3 -2
- data/lib/bitex_bot/models/sell_opening_flow.rb +29 -4
- data/lib/bitex_bot/robot.rb +28 -43
- data/lib/bitex_bot/settings.rb +2 -0
- data/lib/bitex_bot/version.rb +1 -1
- data/settings.rb.sample +23 -5
- data/spec/bitex_bot/settings_spec.rb +13 -6
- data/spec/factories/bitex_ask.rb +14 -0
- data/spec/factories/bitex_bid.rb +14 -0
- data/spec/factories/bitex_buy.rb +7 -7
- data/spec/factories/bitex_sell.rb +7 -7
- data/spec/factories/buy_opening_flow.rb +10 -10
- data/spec/factories/open_buy.rb +8 -8
- data/spec/factories/open_sell.rb +8 -8
- data/spec/factories/sell_opening_flow.rb +10 -10
- data/spec/fixtures/bitstamp/balance.yml +63 -0
- data/spec/fixtures/bitstamp/order_book.yml +60 -0
- data/spec/fixtures/bitstamp/orders/all.yml +62 -0
- data/spec/fixtures/bitstamp/orders/failure_sell.yml +60 -0
- data/spec/fixtures/bitstamp/orders/successful_buy.yml +62 -0
- data/spec/fixtures/bitstamp/transactions.yml +244 -0
- data/spec/fixtures/bitstamp/user_transactions.yml +223 -0
- data/spec/models/api_wrappers/bitex_api_wrapper_spec.rb +147 -0
- data/spec/models/api_wrappers/bitstamp_api_wrapper_spec.rb +134 -140
- data/spec/models/api_wrappers/itbit_api_wrapper_spec.rb +9 -3
- data/spec/models/api_wrappers/kraken_api_wrapper_spec.rb +142 -73
- data/spec/models/bitex_api_spec.rb +4 -4
- data/spec/models/buy_closing_flow_spec.rb +19 -24
- data/spec/models/buy_opening_flow_spec.rb +102 -83
- data/spec/models/order_book_simulator_spec.rb +5 -0
- data/spec/models/robot_spec.rb +7 -4
- data/spec/models/sell_closing_flow_spec.rb +21 -25
- data/spec/models/sell_opening_flow_spec.rb +100 -80
- data/spec/spec_helper.rb +3 -1
- data/spec/support/bitex_stubs.rb +80 -40
- data/spec/support/bitstamp/bitstamp_api_wrapper_stubs.rb +2 -2
- data/spec/support/bitstamp/bitstamp_stubs.rb +3 -3
- data/spec/support/vcr.rb +8 -0
- data/spec/support/webmock.rb +8 -0
- metadata +77 -10
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe KrakenApiWrapper do
|
4
|
-
let(:api_wrapper) {
|
4
|
+
let(:api_wrapper) { BitexBot::Robot.taker }
|
5
5
|
let(:api_client) { api_wrapper.client }
|
6
6
|
let(:taker_settings) do
|
7
7
|
BitexBot::SettingsClass.new(
|
8
8
|
kraken: {
|
9
|
-
api_key: 'your_api_key',
|
9
|
+
api_key: 'your_api_key',
|
10
|
+
api_secret: 'your_api_secret',
|
11
|
+
order_book: 'xbtusd'
|
10
12
|
}
|
11
13
|
)
|
12
14
|
end
|
@@ -16,63 +18,118 @@ describe KrakenApiWrapper do
|
|
16
18
|
BitexBot::Robot.setup
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
+
def stub_request_helper(method:, path: '', status: 200, result: {}, error: [], header_params: {})
|
22
|
+
stub_request(method, "https://api.kraken.com/0#{path}")
|
23
|
+
.with(headers: { 'User-Agent': BitexBot.user_agent }.merge(header_params))
|
24
|
+
.to_return(
|
25
|
+
status: status,
|
26
|
+
body: { error: error, result: result }.to_json,
|
27
|
+
headers: { 'Content-Type': 'application/json' }
|
28
|
+
)
|
21
29
|
end
|
22
30
|
|
23
|
-
def
|
24
|
-
|
31
|
+
def stub_assets
|
32
|
+
stub_request_helper(
|
33
|
+
method: :get,
|
34
|
+
path: '/public/AssetPairs',
|
35
|
+
result: {
|
36
|
+
XXBTZUSD: {
|
37
|
+
altname: 'XBTUSD',
|
38
|
+
aclass_base: 'currency',
|
39
|
+
base: 'XXBT',
|
40
|
+
aclass_quote: 'currency',
|
41
|
+
quote: 'ZUSD',
|
42
|
+
lot: 'unit',
|
43
|
+
pair_decimals: 1,
|
44
|
+
lot_decimals: 8,
|
45
|
+
lot_multiplier: 1,
|
46
|
+
leverage_buy: [2, 3, 4, 5],
|
47
|
+
leverage_sell: [2, 3, 4, 5],
|
48
|
+
fees: [
|
49
|
+
[0, 0.26],
|
50
|
+
[50_000, 0.24],
|
51
|
+
[100_000, 0.22],
|
52
|
+
[250_000, 0.2],
|
53
|
+
[500_000, 0.18],
|
54
|
+
[1_000_000, 0.16],
|
55
|
+
[2_500_000, 0.14],
|
56
|
+
[5_000_000, 0.12],
|
57
|
+
[10_000_000, 0.1]
|
58
|
+
],
|
59
|
+
fees_maker: [
|
60
|
+
[0, 0.16],
|
61
|
+
[50_000, 0.14],
|
62
|
+
[100_000, 0.12],
|
63
|
+
[250_000, 0.1],
|
64
|
+
[500_000, 0.08],
|
65
|
+
[1_000_000, 0.06],
|
66
|
+
[2_500_000, 0.04],
|
67
|
+
[5_000_000, 0.02],
|
68
|
+
[10_000_000, 0]
|
69
|
+
],
|
70
|
+
fee_volume_currency: 'ZUSD',
|
71
|
+
margin_call: 80,
|
72
|
+
margin_stop: 40
|
73
|
+
}
|
74
|
+
}
|
75
|
+
)
|
25
76
|
end
|
26
77
|
|
27
78
|
it 'Sends User-Agent header' do
|
28
|
-
|
29
|
-
stub_stuff =
|
79
|
+
stub_assets
|
80
|
+
stub_stuff = stub_order_book
|
30
81
|
|
31
82
|
# We don't care about the response
|
32
|
-
|
83
|
+
api_wrapper.order_book
|
33
84
|
|
34
|
-
|
85
|
+
stub_stuff.should have_been_requested
|
35
86
|
end
|
36
87
|
|
37
88
|
def stub_balance
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
89
|
+
stub_request_helper(
|
90
|
+
method: :post,
|
91
|
+
path: '/private/Balance',
|
92
|
+
header_params: { 'Api-Key': api_wrapper.api_key },
|
93
|
+
result: { XXBT: '1433.0939', ZUSD: '1230.0233', ETH: '99.7497224800' }
|
94
|
+
)
|
42
95
|
end
|
43
96
|
|
44
97
|
def stub_trade_volume
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
98
|
+
stub_request_helper(
|
99
|
+
method: :post,
|
100
|
+
path: '/private/TradeVolume',
|
101
|
+
header_params: { 'Api-Key': api_wrapper.api_key },
|
102
|
+
result: {
|
103
|
+
currency: 'ZUSD',
|
104
|
+
volume: '3878.8703',
|
105
|
+
fees: {
|
106
|
+
XXBTZUSD: {
|
107
|
+
fee: '0.2600',
|
108
|
+
minfee: '0.1000',
|
109
|
+
maxfee: '0.2600',
|
110
|
+
nextfee: '0.2400',
|
111
|
+
nextvolume: '10000.0000',
|
112
|
+
tiervolume: '0.0000'
|
56
113
|
}
|
57
114
|
},
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
115
|
+
fees_maker: {
|
116
|
+
XETHZEUR: {
|
117
|
+
fee: '0.1600',
|
118
|
+
minfee: '0.0000',
|
119
|
+
maxfee: '0.1600',
|
120
|
+
nextfee: '0.1400',
|
121
|
+
nextvolume: '10000.0000',
|
122
|
+
tiervolume: '0.0000'
|
66
123
|
}
|
67
124
|
}
|
68
|
-
}
|
69
|
-
|
125
|
+
}
|
126
|
+
)
|
70
127
|
end
|
71
128
|
|
72
129
|
it '#balance' do
|
73
|
-
|
74
|
-
stub_orders
|
130
|
+
stub_assets
|
75
131
|
stub_balance
|
132
|
+
stub_orders
|
76
133
|
stub_trade_volume
|
77
134
|
|
78
135
|
balance = api_wrapper.balance
|
@@ -94,25 +151,26 @@ describe KrakenApiWrapper do
|
|
94
151
|
end
|
95
152
|
|
96
153
|
it '#cancel' do
|
97
|
-
stub_private_client
|
98
154
|
stub_orders
|
99
155
|
|
100
|
-
|
156
|
+
api_wrapper.orders.sample.should respond_to(:cancel!)
|
101
157
|
end
|
102
158
|
|
103
159
|
def stub_order_book(count: 3, price: 1.5, amount: 2.5)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
160
|
+
stub_request_helper(
|
161
|
+
method: :get,
|
162
|
+
path: '/public/Depth?pair=XBTUSD',
|
163
|
+
result: {
|
164
|
+
XXBTZUSD: {
|
165
|
+
bids: count.times.map { |i| [(price + i).to_d, (amount + i).to_d, 1.seconds.ago.to_i.to_s] },
|
166
|
+
asks: count.times.map { |i| [(price + i).to_d, (amount + i).to_d, 1.seconds.ago.to_i.to_s] }
|
109
167
|
}
|
110
|
-
}
|
111
|
-
|
168
|
+
}
|
169
|
+
)
|
112
170
|
end
|
113
171
|
|
114
172
|
it '#order_book' do
|
115
|
-
|
173
|
+
stub_assets
|
116
174
|
stub_order_book
|
117
175
|
|
118
176
|
order_book = api_wrapper.order_book
|
@@ -131,34 +189,36 @@ describe KrakenApiWrapper do
|
|
131
189
|
end
|
132
190
|
|
133
191
|
def stub_orders
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
192
|
+
stub_request_helper(
|
193
|
+
method: :post,
|
194
|
+
path: '/private/OpenOrders',
|
195
|
+
header_params: { 'Api-Key': api_wrapper.api_key },
|
196
|
+
result: {
|
197
|
+
open: {
|
198
|
+
'O5TDV2-WDYB2-6OGJRD': {
|
199
|
+
refid: nil, userref: nil, status: 'open', opentm: 1_440_292_821.839, starttm: 0, expiretm: 0,
|
200
|
+
descr: {
|
201
|
+
pair: 'ETHEUR', type: 'buy', ordertype: 'limit', price: '1.19000', price2: '0',
|
202
|
+
leverage: 'none', order: 'buy 1204.00000000 ETHEUR @ limit 1.19000'
|
142
203
|
},
|
143
|
-
|
144
|
-
|
204
|
+
vol: '1204.00000000', vol_exec: '0.00000000', cost: '0.00000', fee: '0.00000',
|
205
|
+
price: '0.00008', misc: '', oflags: 'fciq'
|
145
206
|
},
|
146
|
-
'OGAEYL-LVSPL-BYGGRR'
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
207
|
+
'OGAEYL-LVSPL-BYGGRR': {
|
208
|
+
refid: nil, userref: nil, status: 'open', opentm: 1_440_254_004.621, starttm: 0, expiretm: 0,
|
209
|
+
descr: {
|
210
|
+
pair: 'ETHEUR', type: 'sell', ordertype: 'limit', price: '1.29000', price2: '0',
|
211
|
+
leverage: 'none', order: 'sell 99.74972000 ETHEUR @ limit 1.29000'
|
151
212
|
},
|
152
|
-
|
153
|
-
|
213
|
+
vol: '99.74972000', vol_exec: '0.00000000', cost: '0.00000', fee: '0.00000',
|
214
|
+
price: '0.00009', misc: '', oflags: 'fciq'
|
154
215
|
}
|
155
216
|
}
|
156
|
-
}
|
157
|
-
|
217
|
+
}
|
218
|
+
)
|
158
219
|
end
|
159
220
|
|
160
221
|
it '#orders' do
|
161
|
-
stub_private_client
|
162
222
|
stub_orders
|
163
223
|
|
164
224
|
api_wrapper.orders.all? { |o| o.should be_a(ApiWrapper::Order) }
|
@@ -172,18 +232,20 @@ describe KrakenApiWrapper do
|
|
172
232
|
end
|
173
233
|
|
174
234
|
def stub_transactions(count: 1, price: 1.5, amount: 2.5)
|
175
|
-
|
176
|
-
|
235
|
+
stub_request_helper(
|
236
|
+
method: :get,
|
237
|
+
path: '/public/Trades?pair=XBTUSD',
|
238
|
+
result: {
|
177
239
|
XXBTZUSD: [
|
178
240
|
['202.51626', '0.01440000', 1_440_277_319.1_922, 'b', 'l', ''],
|
179
241
|
['202.54000', '0.10000000', 1_440_277_322.8_993, 'b', 'l', '']
|
180
242
|
]
|
181
243
|
}
|
182
|
-
|
244
|
+
)
|
183
245
|
end
|
184
246
|
|
185
247
|
it '#transactions' do
|
186
|
-
|
248
|
+
stub_assets
|
187
249
|
stub_transactions
|
188
250
|
|
189
251
|
api_wrapper.transactions.all? { |o| o.should be_a(ApiWrapper::Transaction) }
|
@@ -201,9 +263,16 @@ describe KrakenApiWrapper do
|
|
201
263
|
end
|
202
264
|
|
203
265
|
it '#find_lost' do
|
204
|
-
stub_private_client
|
205
266
|
stub_orders
|
206
267
|
|
207
|
-
|
268
|
+
api_wrapper.orders.all? { |o| api_wrapper.find_lost(o.type, o.price, o.amount).present? }
|
269
|
+
end
|
270
|
+
|
271
|
+
it '#currency_pair' do
|
272
|
+
stub_assets
|
273
|
+
BitexBot::Settings.taker.kraken.order_book.should eq taker_settings.kraken.order_book
|
274
|
+
|
275
|
+
api_wrapper.currency_pair.should be_a(HashWithIndifferentAccess)
|
276
|
+
api_wrapper.currency_pair.keys.should include(*%w[altname base quote name])
|
208
277
|
end
|
209
278
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'BitexApi' do
|
4
|
-
before(:each)
|
5
|
-
|
6
|
-
end
|
4
|
+
before(:each) { BitexBot::Robot.setup }
|
5
|
+
let(:maker) { BitexBot::Robot.maker }
|
7
6
|
|
8
7
|
it 'Sends User-Agent header' do
|
9
8
|
stub_request(:get, 'https://bitex.la/api-v1/rest/private/profile?api_key=your_bitex_api_key_which_should_be_kept_safe')
|
10
9
|
.with(headers: { 'User-Agent': BitexBot.user_agent })
|
11
|
-
|
10
|
+
|
11
|
+
maker.profile rescue nil # we don't care about the response
|
12
12
|
end
|
13
13
|
end
|
@@ -4,7 +4,10 @@ describe BitexBot::BuyClosingFlow do
|
|
4
4
|
let(:taker_settings) do
|
5
5
|
BitexBot::SettingsClass.new(
|
6
6
|
bitstamp: {
|
7
|
-
api_key: 'YOUR_API_KEY',
|
7
|
+
api_key: 'YOUR_API_KEY',
|
8
|
+
secret: 'YOUR_API_SECRET',
|
9
|
+
client_id: 'YOUR_BITSTAMP_USERNAME',
|
10
|
+
order_book: 'btcusd'
|
8
11
|
}
|
9
12
|
)
|
10
13
|
end
|
@@ -85,7 +88,7 @@ describe BitexBot::BuyClosingFlow do
|
|
85
88
|
flow = BitexBot::BuyClosingFlow.last
|
86
89
|
stub_bitstamp_orders_into_transactions
|
87
90
|
|
88
|
-
flow.sync_closed_positions
|
91
|
+
flow.sync_closed_positions
|
89
92
|
|
90
93
|
close = flow.close_positions.last
|
91
94
|
close.amount.should == 624.105
|
@@ -106,7 +109,7 @@ describe BitexBot::BuyClosingFlow do
|
|
106
109
|
subject.class.close_open_positions
|
107
110
|
|
108
111
|
stub_bitstamp_orders_into_transactions
|
109
|
-
flow.sync_closed_positions
|
112
|
+
flow.sync_closed_positions
|
110
113
|
end
|
111
114
|
|
112
115
|
it 'syncs the executed orders, calculates profit with other fx rate' do
|
@@ -120,13 +123,11 @@ describe BitexBot::BuyClosingFlow do
|
|
120
123
|
BitexBot::BuyClosingFlow.close_open_positions
|
121
124
|
flow = BitexBot::BuyClosingFlow.last
|
122
125
|
|
123
|
-
expect
|
124
|
-
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
125
|
-
end.not_to change { BitexBot::CloseBuy.count }
|
126
|
+
expect { flow.sync_closed_positions }.not_to change { BitexBot::CloseBuy.count }
|
126
127
|
flow.should_not be_done
|
127
128
|
|
128
129
|
# Immediately calling sync again does not try to cancel the ask.
|
129
|
-
flow.sync_closed_positions
|
130
|
+
flow.sync_closed_positions
|
130
131
|
Bitstamp.orders.all.size.should == 1
|
131
132
|
|
132
133
|
# Partially executes order, and 61 seconds after that
|
@@ -134,18 +135,14 @@ describe BitexBot::BuyClosingFlow do
|
|
134
135
|
stub_bitstamp_orders_into_transactions(ratio: 0.5)
|
135
136
|
Timecop.travel 61.seconds.from_now
|
136
137
|
Bitstamp.orders.all.size.should == 1
|
137
|
-
expect
|
138
|
-
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
139
|
-
end.not_to change { BitexBot::CloseBuy.count }
|
138
|
+
expect { flow.sync_closed_positions }.not_to change { BitexBot::CloseBuy.count }
|
140
139
|
Bitstamp.orders.all.size.should be_zero
|
141
140
|
flow.should_not be_done
|
142
141
|
|
143
142
|
# Next time we try to sync_closed_positions the flow
|
144
143
|
# detects the previous close_buy was cancelled correctly so
|
145
144
|
# it syncs it's total amounts and tries to place a new one.
|
146
|
-
expect
|
147
|
-
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
148
|
-
end.to change { BitexBot::CloseBuy.count }.by(1)
|
145
|
+
expect { flow.sync_closed_positions }.to change { BitexBot::CloseBuy.count }.by(1)
|
149
146
|
|
150
147
|
flow.close_positions.first.tap do |close|
|
151
148
|
close.amount.should == 312.0_525
|
@@ -155,7 +152,7 @@ describe BitexBot::BuyClosingFlow do
|
|
155
152
|
# The second ask is executed completely so we can wrap it up and consider
|
156
153
|
# this closing flow done.
|
157
154
|
stub_bitstamp_orders_into_transactions
|
158
|
-
flow.sync_closed_positions
|
155
|
+
flow.sync_closed_positions
|
159
156
|
flow.close_positions.last.tap do |close|
|
160
157
|
close.amount.should == 312.02_235
|
161
158
|
close.quantity.should == 1.005
|
@@ -171,9 +168,7 @@ describe BitexBot::BuyClosingFlow do
|
|
171
168
|
stub_bitstamp_orders_into_transactions(ratio: 0.999)
|
172
169
|
Bitstamp.orders.all.first.cancel!
|
173
170
|
|
174
|
-
expect
|
175
|
-
flow.sync_closed_positions(Bitstamp.orders.all, Bitstamp.user_transactions.all)
|
176
|
-
end.not_to change { BitexBot::CloseBuy.count }
|
171
|
+
expect { flow.sync_closed_positions }.not_to change { BitexBot::CloseBuy.count }
|
177
172
|
|
178
173
|
flow.should be_done
|
179
174
|
flow.crypto_profit.should == 0.00_201
|
@@ -188,12 +183,12 @@ describe BitexBot::BuyClosingFlow do
|
|
188
183
|
|
189
184
|
60.times do
|
190
185
|
Timecop.travel 60.seconds.from_now
|
191
|
-
flow.sync_closed_positions
|
186
|
+
flow.sync_closed_positions
|
192
187
|
end
|
193
188
|
|
194
189
|
stub_bitstamp_orders_into_transactions
|
195
190
|
|
196
|
-
flow.sync_closed_positions
|
191
|
+
flow.sync_closed_positions
|
197
192
|
flow.reload.should be_done
|
198
193
|
flow.crypto_profit.should be_zero
|
199
194
|
flow.fiat_profit.should == -34.165
|
@@ -202,8 +197,8 @@ describe BitexBot::BuyClosingFlow do
|
|
202
197
|
|
203
198
|
describe 'when there are errors placing the closing order' do
|
204
199
|
it 'keeps trying to place a closed position on bitstamp errors' do
|
205
|
-
BitstampApiWrapper.stub(send_order: nil)
|
206
|
-
BitstampApiWrapper.stub(find_lost: nil)
|
200
|
+
BitstampApiWrapper.any_instance.stub(send_order: nil)
|
201
|
+
BitstampApiWrapper.any_instance.stub(find_lost: nil)
|
207
202
|
|
208
203
|
open = create :open_buy
|
209
204
|
expect do
|
@@ -222,9 +217,9 @@ describe BitexBot::BuyClosingFlow do
|
|
222
217
|
end
|
223
218
|
|
224
219
|
it 'retries until it finds the lost order' do
|
225
|
-
BitstampApiWrapper.stub(send_order: nil)
|
226
|
-
BitstampApiWrapper.stub(:orders) do
|
227
|
-
[
|
220
|
+
BitstampApiWrapper.any_instance.stub(send_order: nil)
|
221
|
+
BitstampApiWrapper.any_instance.stub(:orders) do
|
222
|
+
[ApiWrapper::Order.new(1, :sell, 310, 2.5, 1.minute.ago.to_i)]
|
228
223
|
end
|
229
224
|
|
230
225
|
open = create(:open_buy)
|