diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-02-12 00:13:24 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-02-12 00:13:24 +0100 |
commit | df9e4e7f30a3505675bf61f7da19af4453647772 (patch) | |
tree | fb799d4dec96993e7892c4385df34f03349cc0b9 | |
parent | 5a72ded790f8b5e7c9b38a3cc91c12fbfb6cb97a (diff) | |
download | Trader-df9e4e7f30a3505675bf61f7da19af4453647772.tar.gz Trader-df9e4e7f30a3505675bf61f7da19af4453647772.tar.zst Trader-df9e4e7f30a3505675bf61f7da19af4453647772.zip |
Fix some errors in api responses
Handle some exceptions
-rw-r--r-- | portfolio.py | 28 | ||||
-rw-r--r-- | test.py | 40 |
2 files changed, 54 insertions, 14 deletions
diff --git a/portfolio.py b/portfolio.py index e98689e..17a17ba 100644 --- a/portfolio.py +++ b/portfolio.py | |||
@@ -3,6 +3,7 @@ from datetime import datetime | |||
3 | from decimal import Decimal as D, ROUND_DOWN | 3 | from decimal import Decimal as D, ROUND_DOWN |
4 | # Put your poloniex api key in market.py | 4 | # Put your poloniex api key in market.py |
5 | from json import JSONDecodeError | 5 | from json import JSONDecodeError |
6 | from ccxt import ExchangeError, ExchangeNotAvailable | ||
6 | import requests | 7 | import requests |
7 | import helper as h | 8 | import helper as h |
8 | from store import * | 9 | from store import * |
@@ -463,6 +464,11 @@ class Order: | |||
463 | else: | 464 | else: |
464 | try: | 465 | try: |
465 | self.results.append(self.market.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account)) | 466 | self.results.append(self.market.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account)) |
467 | except ExchangeNotAvailable: | ||
468 | # Impossible to honor the order (dust amount) | ||
469 | self.status = "closed" | ||
470 | self.mark_finished_order() | ||
471 | return | ||
466 | except Exception as e: | 472 | except Exception as e: |
467 | self.status = "error" | 473 | self.status = "error" |
468 | print("error when running market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( | 474 | print("error when running market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( |
@@ -526,7 +532,10 @@ class Order: | |||
526 | return filled_amount | 532 | return filled_amount |
527 | 533 | ||
528 | def fetch_mouvements(self): | 534 | def fetch_mouvements(self): |
529 | mouvements = self.market.privatePostReturnOrderTrades({"orderNumber": self.id}) | 535 | try: |
536 | mouvements = self.market.privatePostReturnOrderTrades({"orderNumber": self.id}) | ||
537 | except ExchangeError: | ||
538 | mouvements = [] | ||
530 | self.mouvements = [] | 539 | self.mouvements = [] |
531 | 540 | ||
532 | for mouvement_hash in mouvements: | 541 | for mouvement_hash in mouvements: |
@@ -544,14 +553,17 @@ class Mouvement: | |||
544 | def __init__(self, currency, base_currency, hash_): | 553 | def __init__(self, currency, base_currency, hash_): |
545 | self.currency = currency | 554 | self.currency = currency |
546 | self.base_currency = base_currency | 555 | self.base_currency = base_currency |
547 | self.id = hash_["id"] | 556 | self.id = hash_.get("tradeID") |
548 | self.action = hash_["type"] | 557 | self.action = hash_.get("type") |
549 | self.fee_rate = D(hash_["fee"]) | 558 | self.fee_rate = D(hash_.get("fee", -1)) |
550 | self.date = datetime.strptime(hash_["date"], '%Y-%m-%d %H:%M:%S') | 559 | try: |
551 | self.rate = D(hash_["rate"]) | 560 | self.date = datetime.strptime(hash_.get("date", ""), '%Y-%m-%d %H:%M:%S') |
552 | self.total = Amount(currency, hash_["amount"]) | 561 | except ValueError: |
562 | self.date = None | ||
563 | self.rate = D(hash_.get("rate", 0)) | ||
564 | self.total = Amount(currency, hash_.get("amount", 0)) | ||
553 | # rate * total = total_in_base | 565 | # rate * total = total_in_base |
554 | self.total_in_base = Amount(base_currency, hash_["total"]) | 566 | self.total_in_base = Amount(base_currency, hash_.get("total", 0)) |
555 | 567 | ||
556 | if __name__ == '__main__': # pragma: no cover | 568 | if __name__ == '__main__': # pragma: no cover |
557 | from market import market | 569 | from market import market |
@@ -1549,12 +1549,12 @@ class OrderTest(WebMockTestCase): | |||
1549 | order = portfolio.Order("buy", portfolio.Amount("ETH", 10), | 1549 | order = portfolio.Order("buy", portfolio.Amount("ETH", 10), |
1550 | D("0.1"), "BTC", "long", "market", "trade") | 1550 | D("0.1"), "BTC", "long", "market", "trade") |
1551 | order.mouvements.append(portfolio.Mouvement("ETH", "BTC", { | 1551 | order.mouvements.append(portfolio.Mouvement("ETH", "BTC", { |
1552 | "id": 42, "type": "buy", "fee": "0.0015", | 1552 | "tradeID": 42, "type": "buy", "fee": "0.0015", |
1553 | "date": "2017-12-30 12:00:12", "rate": "0.1", | 1553 | "date": "2017-12-30 12:00:12", "rate": "0.1", |
1554 | "amount": "3", "total": "0.3" | 1554 | "amount": "3", "total": "0.3" |
1555 | })) | 1555 | })) |
1556 | order.mouvements.append(portfolio.Mouvement("ETH", "BTC", { | 1556 | order.mouvements.append(portfolio.Mouvement("ETH", "BTC", { |
1557 | "id": 43, "type": "buy", "fee": "0.0015", | 1557 | "tradeID": 43, "type": "buy", "fee": "0.0015", |
1558 | "date": "2017-12-30 13:00:12", "rate": "0.2", | 1558 | "date": "2017-12-30 13:00:12", "rate": "0.2", |
1559 | "amount": "2", "total": "0.4" | 1559 | "amount": "2", "total": "0.4" |
1560 | })) | 1560 | })) |
@@ -1569,12 +1569,12 @@ class OrderTest(WebMockTestCase): | |||
1569 | market = mock.Mock() | 1569 | market = mock.Mock() |
1570 | market.privatePostReturnOrderTrades.return_value = [ | 1570 | market.privatePostReturnOrderTrades.return_value = [ |
1571 | { | 1571 | { |
1572 | "id": 42, "type": "buy", "fee": "0.0015", | 1572 | "tradeID": 42, "type": "buy", "fee": "0.0015", |
1573 | "date": "2017-12-30 12:00:12", "rate": "0.1", | 1573 | "date": "2017-12-30 12:00:12", "rate": "0.1", |
1574 | "amount": "3", "total": "0.3" | 1574 | "amount": "3", "total": "0.3" |
1575 | }, | 1575 | }, |
1576 | { | 1576 | { |
1577 | "id": 43, "type": "buy", "fee": "0.0015", | 1577 | "tradeID": 43, "type": "buy", "fee": "0.0015", |
1578 | "date": "2017-12-30 13:00:12", "rate": "0.2", | 1578 | "date": "2017-12-30 13:00:12", "rate": "0.2", |
1579 | "amount": "2", "total": "0.4" | 1579 | "amount": "2", "total": "0.4" |
1580 | } | 1580 | } |
@@ -1591,6 +1591,12 @@ class OrderTest(WebMockTestCase): | |||
1591 | self.assertEqual(42, order.mouvements[0].id) | 1591 | self.assertEqual(42, order.mouvements[0].id) |
1592 | self.assertEqual(43, order.mouvements[1].id) | 1592 | self.assertEqual(43, order.mouvements[1].id) |
1593 | 1593 | ||
1594 | market.privatePostReturnOrderTrades.side_effect = portfolio.ExchangeError | ||
1595 | order = portfolio.Order("buy", portfolio.Amount("ETH", 10), | ||
1596 | D("0.1"), "BTC", "long", market, "trade") | ||
1597 | order.fetch_mouvements() | ||
1598 | self.assertEqual(0, len(order.mouvements)) | ||
1599 | |||
1594 | def test_mark_finished_order(self): | 1600 | def test_mark_finished_order(self): |
1595 | market = mock.Mock() | 1601 | market = mock.Mock() |
1596 | order = portfolio.Order("buy", portfolio.Amount("ETH", 10), | 1602 | order = portfolio.Order("buy", portfolio.Amount("ETH", 10), |
@@ -1770,11 +1776,24 @@ class OrderTest(WebMockTestCase): | |||
1770 | self.assertRegex(stdout_mock.getvalue(), "error when running market.create_order") | 1776 | self.assertRegex(stdout_mock.getvalue(), "error when running market.create_order") |
1771 | self.assertRegex(stdout_mock.getvalue(), "Exception: bouh") | 1777 | self.assertRegex(stdout_mock.getvalue(), "Exception: bouh") |
1772 | 1778 | ||
1779 | market.create_order.reset_mock() | ||
1780 | with self.subTest(dust_amount_exception=True),\ | ||
1781 | mock.patch.object(portfolio.Order, "mark_finished_order") as mark_finished_order: | ||
1782 | order = portfolio.Order("buy", portfolio.Amount("ETH", 0.001), | ||
1783 | D("0.1"), "BTC", "long", market, "trade") | ||
1784 | market.create_order.side_effect = portfolio.ExchangeNotAvailable | ||
1785 | order.run() | ||
1786 | market.create_order.assert_called_once() | ||
1787 | self.assertEqual(0, len(order.results)) | ||
1788 | self.assertEqual("closed", order.status) | ||
1789 | mark_finished_order.assert_called_once() | ||
1790 | |||
1791 | |||
1773 | @unittest.skipUnless("unit" in limits, "Unit skipped") | 1792 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
1774 | class MouvementTest(WebMockTestCase): | 1793 | class MouvementTest(WebMockTestCase): |
1775 | def test_values(self): | 1794 | def test_values(self): |
1776 | mouvement = portfolio.Mouvement("ETH", "BTC", { | 1795 | mouvement = portfolio.Mouvement("ETH", "BTC", { |
1777 | "id": 42, "type": "buy", "fee": "0.0015", | 1796 | "tradeID": 42, "type": "buy", "fee": "0.0015", |
1778 | "date": "2017-12-30 12:00:12", "rate": "0.1", | 1797 | "date": "2017-12-30 12:00:12", "rate": "0.1", |
1779 | "amount": "10", "total": "1" | 1798 | "amount": "10", "total": "1" |
1780 | }) | 1799 | }) |
@@ -1788,6 +1807,15 @@ class MouvementTest(WebMockTestCase): | |||
1788 | self.assertEqual(portfolio.Amount("ETH", "10"), mouvement.total) | 1807 | self.assertEqual(portfolio.Amount("ETH", "10"), mouvement.total) |
1789 | self.assertEqual(portfolio.Amount("BTC", "1"), mouvement.total_in_base) | 1808 | self.assertEqual(portfolio.Amount("BTC", "1"), mouvement.total_in_base) |
1790 | 1809 | ||
1810 | mouvement = portfolio.Mouvement("ETH", "BTC", { "foo": "bar" }) | ||
1811 | self.assertIsNone(mouvement.date) | ||
1812 | self.assertIsNone(mouvement.id) | ||
1813 | self.assertIsNone(mouvement.action) | ||
1814 | self.assertEqual(-1, mouvement.fee_rate) | ||
1815 | self.assertEqual(0, mouvement.rate) | ||
1816 | self.assertEqual(portfolio.Amount("ETH", 0), mouvement.total) | ||
1817 | self.assertEqual(portfolio.Amount("BTC", 0), mouvement.total_in_base) | ||
1818 | |||
1791 | @unittest.skipUnless("acceptance" in limits, "Acceptance skipped") | 1819 | @unittest.skipUnless("acceptance" in limits, "Acceptance skipped") |
1792 | class AcceptanceTest(WebMockTestCase): | 1820 | class AcceptanceTest(WebMockTestCase): |
1793 | @unittest.expectedFailure | 1821 | @unittest.expectedFailure |
@@ -1939,7 +1967,7 @@ class AcceptanceTest(WebMockTestCase): | |||
1939 | market.fetch_order.return_value = { "status": "closed", "datetime": "2018-01-20 13:40:00" } | 1967 | market.fetch_order.return_value = { "status": "closed", "datetime": "2018-01-20 13:40:00" } |
1940 | market.privatePostReturnOrderTrades.return_value = [ | 1968 | market.privatePostReturnOrderTrades.return_value = [ |
1941 | { | 1969 | { |
1942 | "id": 42, "type": "buy", "fee": "0.0015", | 1970 | "tradeID": 42, "type": "buy", "fee": "0.0015", |
1943 | "date": "2017-12-30 12:00:12", "rate": "0.1", | 1971 | "date": "2017-12-30 12:00:12", "rate": "0.1", |
1944 | "amount": "10", "total": "1" | 1972 | "amount": "10", "total": "1" |
1945 | } | 1973 | } |