]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - tests/test_acceptance.py
Move tests to separate files
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / tests / test_acceptance.py
1 from .helper import *
2
3 @unittest.skipUnless("acceptance" in limits, "Acceptance skipped")
4 class AcceptanceTest(WebMockTestCase):
5 @unittest.expectedFailure
6 def test_success_sell_only_necessary(self):
7 # FIXME: catch stdout
8 self.m.report.verbose_print = False
9 fetch_balance = {
10 "ETH": {
11 "exchange_free": D("1.0"),
12 "exchange_used": D("0.0"),
13 "exchange_total": D("1.0"),
14 "total": D("1.0"),
15 },
16 "ETC": {
17 "exchange_free": D("4.0"),
18 "exchange_used": D("0.0"),
19 "exchange_total": D("4.0"),
20 "total": D("4.0"),
21 },
22 "XVG": {
23 "exchange_free": D("1000.0"),
24 "exchange_used": D("0.0"),
25 "exchange_total": D("1000.0"),
26 "total": D("1000.0"),
27 },
28 }
29 repartition = {
30 "ETH": (D("0.25"), "long"),
31 "ETC": (D("0.25"), "long"),
32 "BTC": (D("0.4"), "long"),
33 "BTD": (D("0.01"), "short"),
34 "B2X": (D("0.04"), "long"),
35 "USDT": (D("0.05"), "long"),
36 }
37
38 def fetch_ticker(symbol):
39 if symbol == "ETH/BTC":
40 return {
41 "symbol": "ETH/BTC",
42 "bid": D("0.14"),
43 "ask": D("0.16")
44 }
45 if symbol == "ETC/BTC":
46 return {
47 "symbol": "ETC/BTC",
48 "bid": D("0.002"),
49 "ask": D("0.003")
50 }
51 if symbol == "XVG/BTC":
52 return {
53 "symbol": "XVG/BTC",
54 "bid": D("0.00003"),
55 "ask": D("0.00005")
56 }
57 if symbol == "BTD/BTC":
58 return {
59 "symbol": "BTD/BTC",
60 "bid": D("0.0008"),
61 "ask": D("0.0012")
62 }
63 if symbol == "B2X/BTC":
64 return {
65 "symbol": "B2X/BTC",
66 "bid": D("0.0008"),
67 "ask": D("0.0012")
68 }
69 if symbol == "USDT/BTC":
70 raise helper.ExchangeError
71 if symbol == "BTC/USDT":
72 return {
73 "symbol": "BTC/USDT",
74 "bid": D("14000"),
75 "ask": D("16000")
76 }
77 self.fail("Shouldn't have been called with {}".format(symbol))
78
79 market = mock.Mock()
80 market.fetch_all_balances.return_value = fetch_balance
81 market.fetch_ticker.side_effect = fetch_ticker
82 with mock.patch.object(market.Portfolio, "repartition", return_value=repartition):
83 # Action 1
84 helper.prepare_trades(market)
85
86 balances = portfolio.BalanceStore.all
87 self.assertEqual(portfolio.Amount("ETH", 1), balances["ETH"].total)
88 self.assertEqual(portfolio.Amount("ETC", 4), balances["ETC"].total)
89 self.assertEqual(portfolio.Amount("XVG", 1000), balances["XVG"].total)
90
91
92 trades = portfolio.TradeStore.all
93 self.assertEqual(portfolio.Amount("BTC", D("0.15")), trades[0].value_from)
94 self.assertEqual(portfolio.Amount("BTC", D("0.05")), trades[0].value_to)
95 self.assertEqual("dispose", trades[0].action)
96
97 self.assertEqual(portfolio.Amount("BTC", D("0.01")), trades[1].value_from)
98 self.assertEqual(portfolio.Amount("BTC", D("0.05")), trades[1].value_to)
99 self.assertEqual("acquire", trades[1].action)
100
101 self.assertEqual(portfolio.Amount("BTC", D("0.04")), trades[2].value_from)
102 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[2].value_to)
103 self.assertEqual("dispose", trades[2].action)
104
105 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[3].value_from)
106 self.assertEqual(portfolio.Amount("BTC", D("-0.002")), trades[3].value_to)
107 self.assertEqual("acquire", trades[3].action)
108
109 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[4].value_from)
110 self.assertEqual(portfolio.Amount("BTC", D("0.008")), trades[4].value_to)
111 self.assertEqual("acquire", trades[4].action)
112
113 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[5].value_from)
114 self.assertEqual(portfolio.Amount("BTC", D("0.01")), trades[5].value_to)
115 self.assertEqual("acquire", trades[5].action)
116
117 # Action 2
118 portfolio.TradeStore.prepare_orders(only="dispose", compute_value=lambda x, y: x["bid"] * D("1.001"))
119
120 all_orders = portfolio.TradeStore.all_orders(state="pending")
121 self.assertEqual(2, len(all_orders))
122 self.assertEqual(2, 3*all_orders[0].amount.value)
123 self.assertEqual(D("0.14014"), all_orders[0].rate)
124 self.assertEqual(1000, all_orders[1].amount.value)
125 self.assertEqual(D("0.00003003"), all_orders[1].rate)
126
127
128 def create_order(symbol, type, action, amount, price=None, account="exchange"):
129 self.assertEqual("limit", type)
130 if symbol == "ETH/BTC":
131 self.assertEqual("sell", action)
132 self.assertEqual(D('0.66666666'), amount)
133 self.assertEqual(D("0.14014"), price)
134 elif symbol == "XVG/BTC":
135 self.assertEqual("sell", action)
136 self.assertEqual(1000, amount)
137 self.assertEqual(D("0.00003003"), price)
138 else:
139 self.fail("I shouldn't have been called")
140
141 return {
142 "id": symbol,
143 }
144 market.create_order.side_effect = create_order
145 market.order_precision.return_value = 8
146
147 # Action 3
148 portfolio.TradeStore.run_orders()
149
150 self.assertEqual("open", all_orders[0].status)
151 self.assertEqual("open", all_orders[1].status)
152
153 market.fetch_order.return_value = { "status": "closed", "datetime": "2018-01-20 13:40:00" }
154 market.privatePostReturnOrderTrades.return_value = [
155 {
156 "tradeID": 42, "type": "buy", "fee": "0.0015",
157 "date": "2017-12-30 12:00:12", "rate": "0.1",
158 "amount": "10", "total": "1"
159 }
160 ]
161 with mock.patch.object(market.time, "sleep") as sleep:
162 # Action 4
163 helper.follow_orders(verbose=False)
164
165 sleep.assert_called_with(30)
166
167 for order in all_orders:
168 self.assertEqual("closed", order.status)
169
170 fetch_balance = {
171 "ETH": {
172 "exchange_free": D("1.0") / 3,
173 "exchange_used": D("0.0"),
174 "exchange_total": D("1.0") / 3,
175 "margin_total": 0,
176 "total": D("1.0") / 3,
177 },
178 "BTC": {
179 "exchange_free": D("0.134"),
180 "exchange_used": D("0.0"),
181 "exchange_total": D("0.134"),
182 "margin_total": 0,
183 "total": D("0.134"),
184 },
185 "ETC": {
186 "exchange_free": D("4.0"),
187 "exchange_used": D("0.0"),
188 "exchange_total": D("4.0"),
189 "margin_total": 0,
190 "total": D("4.0"),
191 },
192 "XVG": {
193 "exchange_free": D("0.0"),
194 "exchange_used": D("0.0"),
195 "exchange_total": D("0.0"),
196 "margin_total": 0,
197 "total": D("0.0"),
198 },
199 }
200 market.fetch_all_balances.return_value = fetch_balance
201
202 with mock.patch.object(market.Portfolio, "repartition", return_value=repartition):
203 # Action 5
204 helper.prepare_trades(market, only="acquire", compute_value="average")
205
206 balances = portfolio.BalanceStore.all
207 self.assertEqual(portfolio.Amount("ETH", 1 / D("3")), balances["ETH"].total)
208 self.assertEqual(portfolio.Amount("ETC", 4), balances["ETC"].total)
209 self.assertEqual(portfolio.Amount("BTC", D("0.134")), balances["BTC"].total)
210 self.assertEqual(portfolio.Amount("XVG", 0), balances["XVG"].total)
211
212
213 trades = portfolio.TradeStore.all
214 self.assertEqual(portfolio.Amount("BTC", D("0.15")), trades[0].value_from)
215 self.assertEqual(portfolio.Amount("BTC", D("0.05")), trades[0].value_to)
216 self.assertEqual("dispose", trades[0].action)
217
218 self.assertEqual(portfolio.Amount("BTC", D("0.01")), trades[1].value_from)
219 self.assertEqual(portfolio.Amount("BTC", D("0.05")), trades[1].value_to)
220 self.assertEqual("acquire", trades[1].action)
221
222 self.assertNotIn("BTC", trades)
223
224 self.assertEqual(portfolio.Amount("BTC", D("0.04")), trades[2].value_from)
225 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[2].value_to)
226 self.assertEqual("dispose", trades[2].action)
227
228 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[3].value_from)
229 self.assertEqual(portfolio.Amount("BTC", D("-0.002")), trades[3].value_to)
230 self.assertEqual("acquire", trades[3].action)
231
232 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[4].value_from)
233 self.assertEqual(portfolio.Amount("BTC", D("0.008")), trades[4].value_to)
234 self.assertEqual("acquire", trades[4].action)
235
236 self.assertEqual(portfolio.Amount("BTC", D("0.00")), trades[5].value_from)
237 self.assertEqual(portfolio.Amount("BTC", D("0.01")), trades[5].value_to)
238 self.assertEqual("acquire", trades[5].action)
239
240 # Action 6
241 portfolio.TradeStore.prepare_orders(only="acquire", compute_value=lambda x, y: x["ask"])
242
243 all_orders = portfolio.TradeStore.all_orders(state="pending")
244 self.assertEqual(4, len(all_orders))
245 self.assertEqual(portfolio.Amount("ETC", D("12.83333333")), round(all_orders[0].amount))
246 self.assertEqual(D("0.003"), all_orders[0].rate)
247 self.assertEqual("buy", all_orders[0].action)
248 self.assertEqual("long", all_orders[0].trade_type)
249
250 self.assertEqual(portfolio.Amount("BTD", D("1.61666666")), round(all_orders[1].amount))
251 self.assertEqual(D("0.0012"), all_orders[1].rate)
252 self.assertEqual("sell", all_orders[1].action)
253 self.assertEqual("short", all_orders[1].trade_type)
254
255 diff = portfolio.Amount("B2X", D("19.4")/3) - all_orders[2].amount
256 self.assertAlmostEqual(0, diff.value)
257 self.assertEqual(D("0.0012"), all_orders[2].rate)
258 self.assertEqual("buy", all_orders[2].action)
259 self.assertEqual("long", all_orders[2].trade_type)
260
261 self.assertEqual(portfolio.Amount("BTC", D("0.0097")), all_orders[3].amount)
262 self.assertEqual(D("16000"), all_orders[3].rate)
263 self.assertEqual("sell", all_orders[3].action)
264 self.assertEqual("long", all_orders[3].trade_type)
265
266 # Action 6b
267 # TODO:
268 # Move balances to margin
269
270 # Action 7
271 # TODO
272 # portfolio.TradeStore.run_orders()
273
274 with mock.patch.object(market.time, "sleep") as sleep:
275 # Action 8
276 helper.follow_orders(verbose=False)
277
278 sleep.assert_called_with(30)
279
280