]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/commitdiff
Fix vanishing orders
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Mon, 2 Apr 2018 17:18:49 +0000 (19:18 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Mon, 2 Apr 2018 17:18:49 +0000 (19:18 +0200)
Fixes https://git.immae.eu/mantisbt/view.php?id=60

portfolio.py
test.py

index 9dae23eeb09a58755376da51e12cfe81dd67cc6d..9e98c43ab3e3b656eed3db87208d5a626370a228 100644 (file)
@@ -381,6 +381,14 @@ class Trade:
         self.orders.append(order)
         return order
 
+    def reopen_same_order(self, order):
+        new_order = Order(order.action, order.amount, order.rate,
+                order.base_currency, order.trade_type, self.market,
+                self, close_if_possible=order.close_if_possible)
+        self.orders.append(new_order)
+        new_order.run()
+        return new_order
+
     def as_json(self):
         return {
                 "action": self.action,
@@ -542,6 +550,15 @@ class Order:
             self.fetch()
         return self.status
 
+    def fix_disappeared_order(self):
+        if self.status.startswith("closed") and \
+                len(self.mouvements) == 1 and \
+                self.mouvements[0].total_in_base == 0:
+            self.status = "error_disappeared"
+            new_order = self.trade.reopen_same_order(self)
+            self.market.report.log_error("fetch",
+                    message="Order {} disappeared, recreating it as {}".format(self, new_order))
+
     def mark_finished_order(self):
         if self.status.startswith("closed") and self.market.debug:
             self.market.report.log_debug_action("Mark {} as finished".format(self))
@@ -565,6 +582,8 @@ class Order:
 
         self.fetch_mouvements()
 
+        self.fix_disappeared_order()
+
         self.mark_finished_order()
         # FIXME: consider open order with dust remaining as closed
 
diff --git a/test.py b/test.py
index 9ea9df47b371290740f697e74ea7a4d3c54eb14a..7b17f9ebc54cd3b68c3a777157a61a5ed60ccf83 100644 (file)
--- a/test.py
+++ b/test.py
@@ -2406,6 +2406,27 @@ class TradeTest(WebMockTestCase):
         order1.filled_amount.assert_called_with(in_base_currency=True)
         order2.filled_amount.assert_called_with(in_base_currency=True)
 
+    def test_reopen_same_order(self):
+        value_from = portfolio.Amount("BTC", "0.5")
+        value_from.linked_to = portfolio.Amount("ETH", "10.0")
+        value_to = portfolio.Amount("BTC", "1.0")
+        trade = portfolio.Trade(value_from, value_to, "ETH", self.m)
+        order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
+                D("0.1"), "BTC", "long", self.m, "trade")
+        with mock.patch("portfolio.Order.run") as run:
+            new_order = trade.reopen_same_order(order)
+            self.assertEqual("buy", new_order.action)
+            self.assertEqual(portfolio.Amount("ETH", 10), new_order.amount)
+            self.assertEqual(D("0.1"), new_order.rate)
+            self.assertEqual("BTC", new_order.base_currency)
+            self.assertEqual("long", new_order.trade_type)
+            self.assertEqual(self.m, new_order.market)
+            self.assertEqual(False, new_order.close_if_possible)
+            self.assertEqual(trade, new_order.trade)
+            run.assert_called_once()
+            self.assertEqual(1, len(trade.orders))
+            self.assertEqual(new_order, trade.orders[0])
+
     @mock.patch.object(portfolio.Computation, "compute_value")
     @mock.patch.object(portfolio.Trade, "filled_amount")
     @mock.patch.object(portfolio, "Order")
@@ -3038,8 +3059,9 @@ class OrderTest(WebMockTestCase):
         self.m.report.log_debug_action.assert_called_once()
 
     @mock.patch.object(portfolio.Order, "fetch_mouvements")
+    @mock.patch.object(portfolio.Order, "fix_disappeared_order")
     @mock.patch.object(portfolio.Order, "mark_finished_order")
-    def test_fetch(self, mark_finished_order, fetch_mouvements):
+    def test_fetch(self, mark_finished_order, fix_disappeared_order, fetch_mouvements):
         order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
                 D("0.1"), "BTC", "long", self.m, "trade")
         order.id = 45
@@ -3050,6 +3072,7 @@ class OrderTest(WebMockTestCase):
             self.m.report.log_debug_action.reset_mock()
             self.m.ccxt.fetch_order.assert_not_called()
             mark_finished_order.assert_not_called()
+            fix_disappeared_order.assert_not_called()
             fetch_mouvements.assert_not_called()
 
         with self.subTest(debug=False):
@@ -3067,6 +3090,7 @@ class OrderTest(WebMockTestCase):
             self.assertEqual(1, len(order.results))
             self.m.report.log_debug_action.assert_not_called()
             mark_finished_order.assert_called_once()
+            fix_disappeared_order.assert_called_once()
 
             mark_finished_order.reset_mock()
             with self.subTest(missing_order=True):
@@ -3077,6 +3101,98 @@ class OrderTest(WebMockTestCase):
                 self.assertEqual("closed_unknown", order.status)
                 mark_finished_order.assert_called_once()
 
+    def test_fix_disappeared_order(self):
+        with self.subTest("Open order"):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.id = 45
+            order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
+                "tradeID":21336541,
+                "currencyPair":"BTC_XRP",
+                "type":"sell",
+                "rate":"0.00007013",
+                "amount":"0.00000222",
+                "total":"0.00000000",
+                "fee":"0.00150000",
+                "date":"2018-04-02 00:09:13"
+                }))
+            with mock.patch.object(order, "trade") as trade:
+                order.fix_disappeared_order()
+                trade.reopen_same_order.assert_not_called()
+
+        with self.subTest("Non-zero amount"):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.id = 45
+            order.status = "closed"
+            order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
+                "tradeID":21336541,
+                "currencyPair":"BTC_XRP",
+                "type":"sell",
+                "rate":"0.00007013",
+                "amount":"0.00000222",
+                "total":"0.00000010",
+                "fee":"0.00150000",
+                "date":"2018-04-02 00:09:13"
+                }))
+            with mock.patch.object(order, "trade") as trade:
+                order.fix_disappeared_order()
+                self.assertEqual("closed", order.status)
+                trade.reopen_same_order.assert_not_called()
+
+        with self.subTest("Other mouvements"):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.id = 45
+            order.status = "closed"
+            order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
+                "tradeID":21336541,
+                "currencyPair":"BTC_XRP",
+                "type":"sell",
+                "rate":"0.00007013",
+                "amount":"0.00000222",
+                "total":"0.00000001",
+                "fee":"0.00150000",
+                "date":"2018-04-02 00:09:13"
+                }))
+            order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
+                "tradeID":21336541,
+                "currencyPair":"BTC_XRP",
+                "type":"sell",
+                "rate":"0.00007013",
+                "amount":"0.00000222",
+                "total":"0.00000000",
+                "fee":"0.00150000",
+                "date":"2018-04-02 00:09:13"
+                }))
+            with mock.patch.object(order, "trade") as trade:
+                order.fix_disappeared_order()
+                self.assertEqual("closed", order.status)
+                trade.reopen_same_order.assert_not_called()
+
+        with self.subTest("Order disappeared"):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.id = 45
+            order.status = "closed"
+            order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
+                "tradeID":21336541,
+                "currencyPair":"BTC_XRP",
+                "type":"sell",
+                "rate":"0.00007013",
+                "amount":"0.00000222",
+                "total":"0.00000000",
+                "fee":"0.00150000",
+                "date":"2018-04-02 00:09:13"
+                }))
+            with mock.patch.object(order, "trade") as trade:
+                trade.reopen_same_order.return_value = "New order"
+                order.fix_disappeared_order()
+                self.assertEqual("error_disappeared", order.status)
+                trade.reopen_same_order.assert_called_once_with(order)
+                self.m.report.log_error.assert_called_once_with('fetch',
+                        message='Order Order(buy long 10.00000000 ETH at 0.1 BTC [error_disappeared]) disappeared, recreating it as New order')
+
     @mock.patch.object(portfolio.Order, "fetch")
     def test_get_status(self, fetch):
         with self.subTest(debug=True):