diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-06-11 00:38:37 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-06-11 00:38:37 +0200 |
commit | 3d6f74ee1a8b061e4b274dad70125ab6388f4d83 (patch) | |
tree | cd718866b15b6ff8de3d6b95b6e156ae25c17c20 /tests | |
parent | e24df7cffc01937a211db2d29f44bccc3d740bd5 (diff) | |
download | Trader-3d6f74ee1a8b061e4b274dad70125ab6388f4d83.tar.gz Trader-3d6f74ee1a8b061e4b274dad70125ab6388f4d83.tar.zst Trader-3d6f74ee1a8b061e4b274dad70125ab6388f4d83.zip |
Fix available balance when buying
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_market.py | 32 | ||||
-rw-r--r-- | tests/test_store.py | 186 |
2 files changed, 199 insertions, 19 deletions
diff --git a/tests/test_market.py b/tests/test_market.py index c89025b..07188ac 100644 --- a/tests/test_market.py +++ b/tests/test_market.py | |||
@@ -186,14 +186,17 @@ class MarketTest(WebMockTestCase): | |||
186 | return { "average": D("0.000001") } | 186 | return { "average": D("0.000001") } |
187 | if c1 == "ETH" and c2 == "BTC": | 187 | if c1 == "ETH" and c2 == "BTC": |
188 | return { "average": D("0.1") } | 188 | return { "average": D("0.1") } |
189 | if c1 == "FOO" and c2 == "BTC": | ||
190 | return { "average": D("0.1") } | ||
189 | self.fail("Should not be called with {}, {}".format(c1, c2)) | 191 | self.fail("Should not be called with {}, {}".format(c1, c2)) |
190 | get_ticker.side_effect = _get_ticker | 192 | get_ticker.side_effect = _get_ticker |
191 | 193 | ||
192 | repartition.return_value = { | 194 | repartition.return_value = { |
193 | "DOGE": (D("0.25"), "short"), | 195 | "DOGE": (D("0.20"), "short"), |
194 | "BTC": (D("0.25"), "long"), | 196 | "BTC": (D("0.20"), "long"), |
195 | "ETH": (D("0.25"), "long"), | 197 | "ETH": (D("0.20"), "long"), |
196 | "XMR": (D("0.25"), "long"), | 198 | "XMR": (D("0.20"), "long"), |
199 | "FOO": (D("0.20"), "long"), | ||
197 | } | 200 | } |
198 | m = market.Market(self.ccxt, self.market_args()) | 201 | m = market.Market(self.ccxt, self.market_args()) |
199 | self.ccxt.fetch_all_balances.return_value = { | 202 | self.ccxt.fetch_all_balances.return_value = { |
@@ -210,12 +213,12 @@ class MarketTest(WebMockTestCase): | |||
210 | "total": D("5.0") | 213 | "total": D("5.0") |
211 | }, | 214 | }, |
212 | "BTC": { | 215 | "BTC": { |
213 | "exchange_free": D("0.075"), | 216 | "exchange_free": D("0.065"), |
214 | "exchange_used": D("0.02"), | 217 | "exchange_used": D("0.02"), |
215 | "exchange_total": D("0.095"), | 218 | "exchange_total": D("0.085"), |
216 | "margin_available": D("0.025"), | 219 | "margin_available": D("0.035"), |
217 | "margin_in_position": D("0.01"), | 220 | "margin_in_position": D("0.01"), |
218 | "margin_total": D("0.035"), | 221 | "margin_total": D("0.045"), |
219 | "total": D("0.13") | 222 | "total": D("0.13") |
220 | }, | 223 | }, |
221 | "ETH": { | 224 | "ETH": { |
@@ -224,6 +227,12 @@ class MarketTest(WebMockTestCase): | |||
224 | "exchange_total": D("1.0"), | 227 | "exchange_total": D("1.0"), |
225 | "total": D("1.0") | 228 | "total": D("1.0") |
226 | }, | 229 | }, |
230 | "FOO": { | ||
231 | "exchange_free": D("0.1"), | ||
232 | "exchange_used": D("0.0"), | ||
233 | "exchange_total": D("0.1"), | ||
234 | "total": D("0.1"), | ||
235 | }, | ||
227 | } | 236 | } |
228 | 237 | ||
229 | m.balances.fetch_balances(tag="tag") | 238 | m.balances.fetch_balances(tag="tag") |
@@ -236,12 +245,13 @@ class MarketTest(WebMockTestCase): | |||
236 | 245 | ||
237 | self.assertEqual(portfolio.Amount("BTC", "-0.025"), | 246 | self.assertEqual(portfolio.Amount("BTC", "-0.025"), |
238 | new_repartition["DOGE"] - values_in_base["DOGE"]) | 247 | new_repartition["DOGE"] - values_in_base["DOGE"]) |
239 | self.assertEqual(portfolio.Amount("BTC", "0.025"), | ||
240 | new_repartition["ETH"] - values_in_base["ETH"]) | ||
241 | self.assertEqual(0, | 248 | self.assertEqual(0, |
242 | new_repartition["ZRC"] - values_in_base["ZRC"]) | 249 | new_repartition["ETH"] - values_in_base["ETH"]) |
250 | self.assertIsNone(new_repartition.get("ZRC")) | ||
243 | self.assertEqual(portfolio.Amount("BTC", "0.025"), | 251 | self.assertEqual(portfolio.Amount("BTC", "0.025"), |
244 | new_repartition["XMR"]) | 252 | new_repartition["XMR"]) |
253 | self.assertEqual(portfolio.Amount("BTC", "0.015"), | ||
254 | new_repartition["FOO"] - values_in_base["FOO"]) | ||
245 | 255 | ||
246 | compute_trades.reset_mock() | 256 | compute_trades.reset_mock() |
247 | with self.subTest(available_balance_only=True, balance=0),\ | 257 | with self.subTest(available_balance_only=True, balance=0),\ |
diff --git a/tests/test_store.py b/tests/test_store.py index d7620a0..1a722b5 100644 --- a/tests/test_store.py +++ b/tests/test_store.py | |||
@@ -434,6 +434,176 @@ class BalanceStoreTest(WebMockTestCase): | |||
434 | self.assertListEqual(["XVG", "XMR", "USDT"], list(balance_store.currencies())) | 434 | self.assertListEqual(["XVG", "XMR", "USDT"], list(balance_store.currencies())) |
435 | 435 | ||
436 | @mock.patch.object(market.Portfolio, "repartition") | 436 | @mock.patch.object(market.Portfolio, "repartition") |
437 | def test_available_balances_for_repartition(self, repartition): | ||
438 | with self.subTest(available_balance_only=True): | ||
439 | def _get_ticker(c1, c2): | ||
440 | if c1 == "ZRC" and c2 == "BTC": | ||
441 | return { "average": D("0.0001") } | ||
442 | if c1 == "DOGE" and c2 == "BTC": | ||
443 | return { "average": D("0.000001") } | ||
444 | if c1 == "ETH" and c2 == "BTC": | ||
445 | return { "average": D("0.1") } | ||
446 | if c1 == "FOO" and c2 == "BTC": | ||
447 | return { "average": D("0.1") } | ||
448 | self.fail("Should not be called with {}, {}".format(c1, c2)) | ||
449 | self.m.get_ticker.side_effect = _get_ticker | ||
450 | |||
451 | repartition.return_value = { | ||
452 | "DOGE": (D("0.20"), "short"), | ||
453 | "BTC": (D("0.20"), "long"), | ||
454 | "ETH": (D("0.20"), "long"), | ||
455 | "XMR": (D("0.20"), "long"), | ||
456 | "FOO": (D("0.20"), "long"), | ||
457 | } | ||
458 | self.m.ccxt.fetch_all_balances.return_value = { | ||
459 | "ZRC": { | ||
460 | "exchange_free": D("2.0"), | ||
461 | "exchange_used": D("0.0"), | ||
462 | "exchange_total": D("2.0"), | ||
463 | "total": D("2.0") | ||
464 | }, | ||
465 | "DOGE": { | ||
466 | "exchange_free": D("5.0"), | ||
467 | "exchange_used": D("0.0"), | ||
468 | "exchange_total": D("5.0"), | ||
469 | "total": D("5.0") | ||
470 | }, | ||
471 | "BTC": { | ||
472 | "exchange_free": D("0.065"), | ||
473 | "exchange_used": D("0.02"), | ||
474 | "exchange_total": D("0.085"), | ||
475 | "margin_available": D("0.035"), | ||
476 | "margin_in_position": D("0.01"), | ||
477 | "margin_total": D("0.045"), | ||
478 | "total": D("0.13") | ||
479 | }, | ||
480 | "ETH": { | ||
481 | "exchange_free": D("1.0"), | ||
482 | "exchange_used": D("0.0"), | ||
483 | "exchange_total": D("1.0"), | ||
484 | "total": D("1.0") | ||
485 | }, | ||
486 | "FOO": { | ||
487 | "exchange_free": D("0.1"), | ||
488 | "exchange_used": D("0.0"), | ||
489 | "exchange_total": D("0.1"), | ||
490 | "total": D("0.1"), | ||
491 | }, | ||
492 | } | ||
493 | |||
494 | balance_store = market.BalanceStore(self.m) | ||
495 | balance_store.fetch_balances() | ||
496 | _repartition, total_base_value, amount_in_position = balance_store.available_balances_for_repartition() | ||
497 | repartition.assert_called_with(liquidity="medium") | ||
498 | self.assertEqual((D("0.20"), "short"), _repartition["DOGE"]) | ||
499 | self.assertEqual((D("0.20"), "long"), _repartition["BTC"]) | ||
500 | self.assertEqual((D("0.20"), "long"), _repartition["XMR"]) | ||
501 | self.assertEqual((D("0.20"), "long"), _repartition["FOO"]) | ||
502 | self.assertIsNone(_repartition.get("ETH")) | ||
503 | self.assertEqual(portfolio.Amount("BTC", "0.1"), total_base_value) | ||
504 | self.assertEqual(0, amount_in_position["DOGE"]) | ||
505 | self.assertEqual(0, amount_in_position["BTC"]) | ||
506 | self.assertEqual(0, amount_in_position["XMR"]) | ||
507 | self.assertEqual(portfolio.Amount("BTC", "0.1"), amount_in_position["ETH"]) | ||
508 | self.assertEqual(portfolio.Amount("BTC", "0.01"), amount_in_position["FOO"]) | ||
509 | |||
510 | with self.subTest(available_balance_only=True, balance=0): | ||
511 | def _get_ticker(c1, c2): | ||
512 | if c1 == "ETH" and c2 == "BTC": | ||
513 | return { "average": D("0.1") } | ||
514 | self.fail("Should not be called with {}, {}".format(c1, c2)) | ||
515 | self.m.get_ticker.side_effect = _get_ticker | ||
516 | |||
517 | repartition.return_value = { | ||
518 | "BTC": (D("0.5"), "long"), | ||
519 | "ETH": (D("0.5"), "long"), | ||
520 | } | ||
521 | self.m.ccxt.fetch_all_balances.return_value = { | ||
522 | "ETH": { | ||
523 | "exchange_free": D("1.0"), | ||
524 | "exchange_used": D("0.0"), | ||
525 | "exchange_total": D("1.0"), | ||
526 | "total": D("1.0") | ||
527 | }, | ||
528 | } | ||
529 | |||
530 | balance_store = market.BalanceStore(self.m) | ||
531 | balance_store.fetch_balances() | ||
532 | _repartition, total_base_value, amount_in_position = balance_store.available_balances_for_repartition(liquidity="high") | ||
533 | |||
534 | repartition.assert_called_with(liquidity="high") | ||
535 | self.assertEqual((D("0.5"), "long"), _repartition["BTC"]) | ||
536 | self.assertIsNone(_repartition.get("ETH")) | ||
537 | self.assertEqual(0, total_base_value) | ||
538 | self.assertEqual(0, amount_in_position["BTC"]) | ||
539 | self.assertEqual(0, amount_in_position["BTC"]) | ||
540 | |||
541 | repartition.reset_mock() | ||
542 | with self.subTest(available_balance_only=True, balance=0, | ||
543 | repartition="present"): | ||
544 | def _get_ticker(c1, c2): | ||
545 | if c1 == "ETH" and c2 == "BTC": | ||
546 | return { "average": D("0.1") } | ||
547 | self.fail("Should not be called with {}, {}".format(c1, c2)) | ||
548 | self.m.get_ticker.side_effect = _get_ticker | ||
549 | |||
550 | _repartition = { | ||
551 | "BTC": (D("0.5"), "long"), | ||
552 | "ETH": (D("0.5"), "long"), | ||
553 | } | ||
554 | self.m.ccxt.fetch_all_balances.return_value = { | ||
555 | "ETH": { | ||
556 | "exchange_free": D("1.0"), | ||
557 | "exchange_used": D("0.0"), | ||
558 | "exchange_total": D("1.0"), | ||
559 | "total": D("1.0") | ||
560 | }, | ||
561 | } | ||
562 | |||
563 | balance_store = market.BalanceStore(self.m) | ||
564 | balance_store.fetch_balances() | ||
565 | _repartition, total_base_value, amount_in_position = balance_store.available_balances_for_repartition(repartition=_repartition) | ||
566 | repartition.assert_not_called() | ||
567 | |||
568 | self.assertEqual((D("0.5"), "long"), _repartition["BTC"]) | ||
569 | self.assertIsNone(_repartition.get("ETH")) | ||
570 | self.assertEqual(0, total_base_value) | ||
571 | self.assertEqual(0, amount_in_position["BTC"]) | ||
572 | self.assertEqual(portfolio.Amount("BTC", "0.1"), amount_in_position["ETH"]) | ||
573 | |||
574 | repartition.reset_mock() | ||
575 | with self.subTest(available_balance_only=True, balance=0, | ||
576 | repartition="present", base_currency="ETH"): | ||
577 | def _get_ticker(c1, c2): | ||
578 | if c1 == "ETH" and c2 == "BTC": | ||
579 | return { "average": D("0.1") } | ||
580 | self.fail("Should not be called with {}, {}".format(c1, c2)) | ||
581 | self.m.get_ticker.side_effect = _get_ticker | ||
582 | |||
583 | _repartition = { | ||
584 | "BTC": (D("0.5"), "long"), | ||
585 | "ETH": (D("0.5"), "long"), | ||
586 | } | ||
587 | self.m.ccxt.fetch_all_balances.return_value = { | ||
588 | "ETH": { | ||
589 | "exchange_free": D("1.0"), | ||
590 | "exchange_used": D("0.0"), | ||
591 | "exchange_total": D("1.0"), | ||
592 | "total": D("1.0") | ||
593 | }, | ||
594 | } | ||
595 | |||
596 | balance_store = market.BalanceStore(self.m) | ||
597 | balance_store.fetch_balances() | ||
598 | _repartition, total_base_value, amount_in_position = balance_store.available_balances_for_repartition(repartition=_repartition, base_currency="ETH") | ||
599 | |||
600 | self.assertEqual((D("0.5"), "long"), _repartition["BTC"]) | ||
601 | self.assertEqual((D("0.5"), "long"), _repartition["ETH"]) | ||
602 | self.assertEqual(portfolio.Amount("ETH", 1), total_base_value) | ||
603 | self.assertEqual(0, amount_in_position["BTC"]) | ||
604 | self.assertEqual(0, amount_in_position["ETH"]) | ||
605 | |||
606 | @mock.patch.object(market.Portfolio, "repartition") | ||
437 | def test_dispatch_assets(self, repartition): | 607 | def test_dispatch_assets(self, repartition): |
438 | self.m.ccxt.fetch_all_balances.return_value = self.fetch_balance | 608 | self.m.ccxt.fetch_all_balances.return_value = self.fetch_balance |
439 | 609 | ||
@@ -1343,27 +1513,27 @@ class PortfolioTest(WebMockTestCase): | |||
1343 | with self.subTest(from_cache=False): | 1513 | with self.subTest(from_cache=False): |
1344 | market.Portfolio.liquidities = store.LockedVar({ | 1514 | market.Portfolio.liquidities = store.LockedVar({ |
1345 | "medium": { | 1515 | "medium": { |
1346 | "2018-03-01": "medium_2018-03-01", | 1516 | "2018-03-01": ["medium_2018-03-01"], |
1347 | "2018-03-08": "medium_2018-03-08", | 1517 | "2018-03-08": ["medium_2018-03-08"], |
1348 | }, | 1518 | }, |
1349 | "high": { | 1519 | "high": { |
1350 | "2018-03-01": "high_2018-03-01", | 1520 | "2018-03-01": ["high_2018-03-01"], |
1351 | "2018-03-08": "high_2018-03-08", | 1521 | "2018-03-08": ["high_2018-03-08"], |
1352 | } | 1522 | } |
1353 | }) | 1523 | }) |
1354 | market.Portfolio.last_date = store.LockedVar("2018-03-08") | 1524 | market.Portfolio.last_date = store.LockedVar("2018-03-08") |
1355 | 1525 | ||
1356 | self.assertEqual("medium_2018-03-08", market.Portfolio.repartition()) | 1526 | self.assertEqual(["medium_2018-03-08"], market.Portfolio.repartition()) |
1357 | get_cryptoportfolio.assert_called_once_with() | 1527 | get_cryptoportfolio.assert_called_once_with() |
1358 | retrieve_cryptoportfolio.assert_not_called() | 1528 | retrieve_cryptoportfolio.assert_not_called() |
1359 | self.assertEqual("medium_2018-03-08", market.Portfolio.repartition(liquidity="medium")) | 1529 | self.assertEqual(["medium_2018-03-08"], market.Portfolio.repartition(liquidity="medium")) |
1360 | self.assertEqual("high_2018-03-08", market.Portfolio.repartition(liquidity="high")) | 1530 | self.assertEqual(["high_2018-03-08"], market.Portfolio.repartition(liquidity="high")) |
1361 | 1531 | ||
1362 | retrieve_cryptoportfolio.reset_mock() | 1532 | retrieve_cryptoportfolio.reset_mock() |
1363 | get_cryptoportfolio.reset_mock() | 1533 | get_cryptoportfolio.reset_mock() |
1364 | 1534 | ||
1365 | with self.subTest(from_cache=True): | 1535 | with self.subTest(from_cache=True): |
1366 | self.assertEqual("medium_2018-03-08", market.Portfolio.repartition(from_cache=True)) | 1536 | self.assertEqual(["medium_2018-03-08"], market.Portfolio.repartition(from_cache=True)) |
1367 | get_cryptoportfolio.assert_called_once_with() | 1537 | get_cryptoportfolio.assert_called_once_with() |
1368 | retrieve_cryptoportfolio.assert_called_once_with() | 1538 | retrieve_cryptoportfolio.assert_called_once_with() |
1369 | 1539 | ||