]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - test.py
Handle invalid nonces
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / test.py
diff --git a/test.py b/test.py
index 40c64a95d769c2d9e8dc3b6cbbe182309002317e..c229801246219870d99e5f8c574793dd96f1ddcc 100644 (file)
--- a/test.py
+++ b/test.py
@@ -70,6 +70,18 @@ class poloniexETest(unittest.TestCase):
         self.wm.stop()
         super(poloniexETest, self).tearDown()
 
+    def test__init(self):
+        with mock.patch("market.ccxt.poloniexE.session") as session:
+            session.request.return_value = "response"
+            ccxt = market.ccxt.poloniexE()
+            ccxt._market = mock.Mock
+            ccxt._market.report = mock.Mock()
+
+            ccxt.session.request("GET", "URL", data="data",
+                    headers="headers")
+            ccxt._market.report.log_http_request.assert_called_with('GET', 'URL', 'data',
+                    'headers', 'response')
+
     def test_nanoseconds(self):
         with mock.patch.object(market.ccxt.time, "time") as time:
             time.return_value = 123456.7890123456
@@ -89,7 +101,7 @@ class poloniexETest(unittest.TestCase):
                     retry_call.assert_called_with(request,
                             delay=1, tries=10, fargs=["foo"],
                             fkwargs={'api': 'public', 'method': 'GET', 'params': {}, 'headers': None, 'body': None},
-                            exceptions=(market.ccxt.RequestTimeout,))
+                            exceptions=(market.ccxt.RequestTimeout, market.ccxt.InvalidNonce))
                     request.assert_not_called()
 
                 with self.subTest(desc="private GET"):
@@ -97,7 +109,7 @@ class poloniexETest(unittest.TestCase):
                     retry_call.assert_called_with(request,
                             delay=1, tries=10, fargs=["foo"],
                             fkwargs={'api': 'private', 'method': 'GET', 'params': {}, 'headers': None, 'body': None},
-                            exceptions=(market.ccxt.RequestTimeout,))
+                            exceptions=(market.ccxt.RequestTimeout, market.ccxt.InvalidNonce))
                     request.assert_not_called()
 
                 with self.subTest(desc="private POST regexp"):
@@ -105,7 +117,7 @@ class poloniexETest(unittest.TestCase):
                     retry_call.assert_called_with(request,
                             delay=1, tries=10, fargs=["returnFoo"],
                             fkwargs={'api': 'private', 'method': 'POST', 'params': {}, 'headers': None, 'body': None},
-                            exceptions=(market.ccxt.RequestTimeout,))
+                            exceptions=(market.ccxt.RequestTimeout, market.ccxt.InvalidNonce))
                     request.assert_not_called()
 
                 with self.subTest(desc="private POST non-regexp"):
@@ -113,7 +125,7 @@ class poloniexETest(unittest.TestCase):
                     retry_call.assert_called_with(request,
                             delay=1, tries=10, fargs=["getMarginPosition"],
                             fkwargs={'api': 'private', 'method': 'POST', 'params': {}, 'headers': None, 'body': None},
-                            exceptions=(market.ccxt.RequestTimeout,))
+                            exceptions=(market.ccxt.RequestTimeout, market.ccxt.InvalidNonce))
                     request.assert_not_called()
             retry_call.reset_mock()
             request.reset_mock()
@@ -1177,17 +1189,11 @@ class MarketTest(WebMockTestCase):
     def test_from_config(self, ccxt):
         with mock.patch("market.ReportStore"):
             ccxt.poloniexE.return_value = self.ccxt
-            self.ccxt.session.request.return_value = "response"
 
             m = market.Market.from_config({"key": "key", "secred": "secret"}, self.market_args())
 
             self.assertEqual(self.ccxt, m.ccxt)
 
-            self.ccxt.session.request("GET", "URL", data="data",
-                    headers="headers")
-            m.report.log_http_request.assert_called_with('GET', 'URL', 'data',
-                    'headers', 'response')
-
         m = market.Market.from_config({"key": "key", "secred": "secret"}, self.market_args(debug=True))
         self.assertEqual(True, m.debug)
 
@@ -1438,6 +1444,141 @@ class MarketTest(WebMockTestCase):
                     self.ccxt.transfer_balance.assert_any_call("USDT", 100, "exchange", "margin")
                     self.ccxt.transfer_balance.assert_any_call("ETC", 5, "margin", "exchange")
 
+        m.report.reset_mock()
+        fetch_balances.reset_mock()
+        with self.subTest(retry=True):
+            with mock.patch("market.ReportStore"):
+                m = market.Market(self.ccxt, self.market_args())
+
+                value_from = portfolio.Amount("BTC", "0.0")
+                value_from.linked_to = portfolio.Amount("ETH", "0.0")
+                value_to = portfolio.Amount("BTC", "-3.0")
+                trade = portfolio.Trade(value_from, value_to, "ETH", m)
+
+                m.trades.all = [trade]
+                balance = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" })
+                m.balances.all = {"BTC": balance}
+
+                m.ccxt.transfer_balance.side_effect = [
+                        market.ccxt.RequestTimeout,
+                        market.ccxt.InvalidNonce,
+                        True
+                        ]
+                m.move_balances()
+                self.ccxt.transfer_balance.assert_has_calls([
+                    mock.call("BTC", 3, "exchange", "margin"),
+                    mock.call("BTC", 3, "exchange", "margin"),
+                    mock.call("BTC", 3, "exchange", "margin")
+                    ])
+                self.assertEqual(3, fetch_balances.call_count)
+                m.report.log_error.assert_called_with(mock.ANY, message="Retrying", exception=mock.ANY)
+                self.assertEqual(3, m.report.log_move_balances.call_count)
+
+        self.ccxt.transfer_balance.reset_mock()
+        m.report.reset_mock()
+        fetch_balances.reset_mock()
+        with self.subTest(retry=True, too_much=True):
+            with mock.patch("market.ReportStore"):
+                m = market.Market(self.ccxt, self.market_args())
+
+                value_from = portfolio.Amount("BTC", "0.0")
+                value_from.linked_to = portfolio.Amount("ETH", "0.0")
+                value_to = portfolio.Amount("BTC", "-3.0")
+                trade = portfolio.Trade(value_from, value_to, "ETH", m)
+
+                m.trades.all = [trade]
+                balance = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" })
+                m.balances.all = {"BTC": balance}
+
+                m.ccxt.transfer_balance.side_effect = [
+                        market.ccxt.RequestTimeout,
+                        market.ccxt.RequestTimeout,
+                        market.ccxt.RequestTimeout,
+                        market.ccxt.RequestTimeout,
+                        market.ccxt.RequestTimeout,
+                        ]
+                with self.assertRaises(market.ccxt.RequestTimeout):
+                    m.move_balances()
+
+        self.ccxt.transfer_balance.reset_mock()
+        m.report.reset_mock()
+        fetch_balances.reset_mock()
+        with self.subTest(retry=True, partial_result=True):
+            with mock.patch("market.ReportStore"):
+                m = market.Market(self.ccxt, self.market_args())
+
+                value_from = portfolio.Amount("BTC", "1.0")
+                value_from.linked_to = portfolio.Amount("ETH", "10.0")
+                value_to = portfolio.Amount("BTC", "10.0")
+                trade1 = portfolio.Trade(value_from, value_to, "ETH", m)
+
+                value_from = portfolio.Amount("BTC", "0.0")
+                value_from.linked_to = portfolio.Amount("ETH", "0.0")
+                value_to = portfolio.Amount("BTC", "-3.0")
+                trade2 = portfolio.Trade(value_from, value_to, "ETH", m)
+
+                value_from = portfolio.Amount("USDT", "0.0")
+                value_from.linked_to = portfolio.Amount("XVG", "0.0")
+                value_to = portfolio.Amount("USDT", "-50.0")
+                trade3 = portfolio.Trade(value_from, value_to, "XVG", m)
+
+                m.trades.all = [trade1, trade2, trade3]
+                balance1 = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" })
+                balance2 = portfolio.Balance("USDT", { "margin_in_position": "100", "margin_available": "50" })
+                balance3 = portfolio.Balance("ETC", { "margin_in_position": "10", "margin_available": "15" })
+                m.balances.all = {"BTC": balance1, "USDT": balance2, "ETC": balance3}
+
+                call_counts = { "BTC": 0, "USDT": 0, "ETC": 0 }
+                def _transfer_balance(currency, amount, from_, to_):
+                    call_counts[currency] += 1
+                    if currency == "BTC":
+                        m.balances.all["BTC"] = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "3" })
+                    if currency == "USDT":
+                        if call_counts["USDT"] == 1:
+                            raise market.ccxt.RequestTimeout
+                        else:
+                            m.balances.all["USDT"] = portfolio.Balance("USDT", { "margin_in_position": "100", "margin_available": "150" })
+                    if currency == "ETC":
+                            m.balances.all["ETC"] = portfolio.Balance("ETC", { "margin_in_position": "10", "margin_available": "10" })
+
+
+                m.ccxt.transfer_balance.side_effect = _transfer_balance
+
+                m.move_balances()
+                self.ccxt.transfer_balance.assert_has_calls([
+                    mock.call("BTC", 3, "exchange", "margin"),
+                    mock.call('USDT', 100, 'exchange', 'margin'),
+                    mock.call('USDT', 100, 'exchange', 'margin'),
+                    mock.call("ETC", 5, "margin", "exchange")
+                    ])
+                self.assertEqual(2, fetch_balances.call_count)
+                m.report.log_error.assert_called_with(mock.ANY, message="Retrying", exception=mock.ANY)
+                self.assertEqual(2, m.report.log_move_balances.call_count)
+                m.report.log_move_balances.asser_has_calls([
+                    mock.call(
+                        {
+                            'BTC': portfolio.Amount("BTC", "3"),
+                            'USDT': portfolio.Amount("USDT", "150"),
+                            'ETC': portfolio.Amount("ETC", "10"),
+                            },
+                        {
+                            'BTC': portfolio.Amount("BTC", "3"),
+                            'USDT': portfolio.Amount("USDT", "100"),
+                            }),
+                    mock.call(
+                        {
+                            'BTC': portfolio.Amount("BTC", "3"),
+                            'USDT': portfolio.Amount("USDT", "150"),
+                            'ETC': portfolio.Amount("ETC", "10"),
+                            },
+                        {
+                            'BTC': portfolio.Amount("BTC", "0"),
+                            'USDT': portfolio.Amount("USDT", "100"),
+                            'ETC': portfolio.Amount("ETC", "-5"),
+                            }),
+                    ])
+
+
     def test_store_file_report(self):
         file_open = mock.mock_open()
         m = market.Market(self.ccxt, self.market_args(), report_path="present", user_id=1)
@@ -3074,6 +3215,549 @@ class OrderTest(WebMockTestCase):
             self.assertEqual(5, self.m.report.log_error.call_count)
             self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00096060 ETH at 0.1 BTC [pending])", exception=mock.ANY)
 
+        self.m.reset_mock()
+        with self.subTest(invalid_nonce=True):
+            with self.subTest(retry_success=True):
+                order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                        D("0.1"), "BTC", "long", self.m, "trade")
+                self.m.ccxt.create_order.side_effect = [
+                        portfolio.InvalidNonce,
+                        portfolio.InvalidNonce,
+                        { "id": 123 },
+                        ]
+                order.run()
+                self.m.ccxt.create_order.assert_has_calls([
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                ])
+                self.assertEqual(3, self.m.ccxt.create_order.call_count)
+                self.assertEqual(3, order.tries)
+                self.m.report.log_error.assert_called()
+                self.assertEqual(2, self.m.report.log_error.call_count)
+                self.m.report.log_error.assert_called_with(mock.ANY, message="Retrying after invalid nonce", exception=mock.ANY)
+                self.assertEqual(123, order.id)
+
+            self.m.reset_mock()
+            with self.subTest(retry_success=False):
+                order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                        D("0.1"), "BTC", "long", self.m, "trade")
+                self.m.ccxt.create_order.side_effect = [
+                        portfolio.InvalidNonce,
+                        portfolio.InvalidNonce,
+                        portfolio.InvalidNonce,
+                        portfolio.InvalidNonce,
+                        portfolio.InvalidNonce,
+                        ]
+                order.run()
+                self.assertEqual(5, self.m.ccxt.create_order.call_count)
+                self.assertEqual(5, order.tries)
+                self.m.report.log_error.assert_called()
+                self.assertEqual(5, self.m.report.log_error.call_count)
+                self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00100000 ETH at 0.1 BTC [pending]) after invalid nonce", exception=mock.ANY)
+                self.assertEqual("error", order.status)
+
+        self.m.reset_mock()
+        with self.subTest(request_timeout=True):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            with self.subTest(retrieved=False), \
+                    mock.patch.object(order, "retrieve_order") as retrieve:
+                self.m.ccxt.create_order.side_effect = [
+                        portfolio.RequestTimeout,
+                        portfolio.RequestTimeout,
+                        { "id": 123 },
+                        ]
+                retrieve.return_value = False
+                order.run()
+                self.m.ccxt.create_order.assert_has_calls([
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                ])
+                self.assertEqual(3, self.m.ccxt.create_order.call_count)
+                self.assertEqual(3, order.tries)
+                self.m.report.log_error.assert_called()
+                self.assertEqual(2, self.m.report.log_error.call_count)
+                self.m.report.log_error.assert_called_with(mock.ANY, message="Retrying after timeout", exception=mock.ANY)
+                self.assertEqual(123, order.id)
+
+            self.m.reset_mock()
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            with self.subTest(retrieved=True), \
+                    mock.patch.object(order, "retrieve_order") as retrieve:
+                self.m.ccxt.create_order.side_effect = [
+                        portfolio.RequestTimeout,
+                        ]
+                def _retrieve():
+                    order.results.append({"id": 123})
+                    return True
+                retrieve.side_effect = _retrieve
+                order.run()
+                self.m.ccxt.create_order.assert_has_calls([
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                ])
+                self.assertEqual(1, self.m.ccxt.create_order.call_count)
+                self.assertEqual(1, order.tries)
+                self.m.report.log_error.assert_called()
+                self.assertEqual(1, self.m.report.log_error.call_count)
+                self.m.report.log_error.assert_called_with(mock.ANY, message="Timeout, found the order")
+                self.assertEqual(123, order.id)
+
+            self.m.reset_mock()
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            with self.subTest(retrieved=False), \
+                    mock.patch.object(order, "retrieve_order") as retrieve:
+                self.m.ccxt.create_order.side_effect = [
+                        portfolio.RequestTimeout,
+                        portfolio.RequestTimeout,
+                        portfolio.RequestTimeout,
+                        portfolio.RequestTimeout,
+                        portfolio.RequestTimeout,
+                        ]
+                retrieve.return_value = False
+                order.run()
+                self.m.ccxt.create_order.assert_has_calls([
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                    mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')),
+                ])
+                self.assertEqual(5, self.m.ccxt.create_order.call_count)
+                self.assertEqual(5, order.tries)
+                self.m.report.log_error.assert_called()
+                self.assertEqual(5, self.m.report.log_error.call_count)
+                self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00100000 ETH at 0.1 BTC [pending]) after timeouts", exception=mock.ANY)
+                self.assertEqual("error", order.status)
+
+    def test_retrieve_order(self):
+        with self.subTest(similar_open_order=True):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55)
+
+            self.m.ccxt.order_precision.return_value = 8
+            self.m.ccxt.fetch_orders.return_value = [
+                    { # Wrong amount
+                        'amount': 0.002, 'cost': 0.1,
+                        'datetime': '2018-03-25T15:15:51.000Z',
+                        'fee': None, 'filled': 0.0,
+                        'id': '1',
+                        'info': {
+                            'amount': '0.002',
+                            'date': '2018-03-25 15:15:51',
+                            'margin': 0, 'orderNumber': '1',
+                            'price': '0.1', 'rate': '0.1',
+                            'side': 'buy', 'startingAmount': '0.002',
+                            'status': 'open', 'total': '0.0002',
+                            'type': 'limit'
+                            },
+                        'price': 0.1, 'remaining': 0.002, 'side': 'buy',
+                        'status': 'open', 'symbol': 'ETH/BTC',
+                        'timestamp': 1521990951000, 'trades': None,
+                        'type': 'limit'
+                        },
+                    { # Margin
+                        'amount': 0.001, 'cost': 0.1,
+                        'datetime': '2018-03-25T15:15:51.000Z',
+                        'fee': None, 'filled': 0.0,
+                        'id': '2',
+                        'info': {
+                            'amount': '0.001',
+                            'date': '2018-03-25 15:15:51',
+                            'margin': 1, 'orderNumber': '2',
+                            'price': '0.1', 'rate': '0.1',
+                            'side': 'buy', 'startingAmount': '0.001',
+                            'status': 'open', 'total': '0.0001',
+                            'type': 'limit'
+                            },
+                        'price': 0.1, 'remaining': 0.001, 'side': 'buy',
+                        'status': 'open', 'symbol': 'ETH/BTC',
+                        'timestamp': 1521990951000, 'trades': None,
+                        'type': 'limit'
+                        },
+                    { # selling
+                        'amount': 0.001, 'cost': 0.1,
+                        'datetime': '2018-03-25T15:15:51.000Z',
+                        'fee': None, 'filled': 0.0,
+                        'id': '3',
+                        'info': {
+                            'amount': '0.001',
+                            'date': '2018-03-25 15:15:51',
+                            'margin': 0, 'orderNumber': '3',
+                            'price': '0.1', 'rate': '0.1',
+                            'side': 'sell', 'startingAmount': '0.001',
+                            'status': 'open', 'total': '0.0001',
+                            'type': 'limit'
+                            },
+                        'price': 0.1, 'remaining': 0.001, 'side': 'sell',
+                        'status': 'open', 'symbol': 'ETH/BTC',
+                        'timestamp': 1521990951000, 'trades': None,
+                        'type': 'limit'
+                        },
+                    { # Wrong rate
+                        'amount': 0.001, 'cost': 0.15,
+                        'datetime': '2018-03-25T15:15:51.000Z',
+                        'fee': None, 'filled': 0.0,
+                        'id': '4',
+                        'info': {
+                            'amount': '0.001',
+                            'date': '2018-03-25 15:15:51',
+                            'margin': 0, 'orderNumber': '4',
+                            'price': '0.15', 'rate': '0.15',
+                            'side': 'buy', 'startingAmount': '0.001',
+                            'status': 'open', 'total': '0.0001',
+                            'type': 'limit'
+                            },
+                        'price': 0.15, 'remaining': 0.001, 'side': 'buy',
+                        'status': 'open', 'symbol': 'ETH/BTC',
+                        'timestamp': 1521990951000, 'trades': None,
+                        'type': 'limit'
+                        },
+                    { # All good
+                        'amount': 0.001, 'cost': 0.1,
+                        'datetime': '2018-03-25T15:15:51.000Z',
+                        'fee': None, 'filled': 0.0,
+                        'id': '5',
+                        'info': {
+                            'amount': '0.001',
+                            'date': '2018-03-25 15:15:51',
+                            'margin': 0, 'orderNumber': '1',
+                            'price': '0.1', 'rate': '0.1',
+                            'side': 'buy', 'startingAmount': '0.001',
+                            'status': 'open', 'total': '0.0001',
+                            'type': 'limit'
+                            },
+                        'price': 0.1, 'remaining': 0.001, 'side': 'buy',
+                        'status': 'open', 'symbol': 'ETH/BTC',
+                        'timestamp': 1521990951000, 'trades': None,
+                        'type': 'limit'
+                        }
+                    ]
+            result = order.retrieve_order()
+            self.assertTrue(result)
+            self.assertEqual('5', order.results[0]["id"])
+            self.m.ccxt.fetch_my_trades.assert_not_called()
+            self.m.ccxt.fetch_orders.assert_called_once_with(symbol="ETH/BTC", since=1521983750)
+
+        self.m.reset_mock()
+        with self.subTest(similar_open_order=False, past_trades=True):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55)
+
+            self.m.ccxt.order_precision.return_value = 8
+            self.m.ccxt.fetch_orders.return_value = []
+            self.m.ccxt.fetch_my_trades.return_value = [
+                    { # Wrong timestamp 1
+                        'amount': 0.0006,
+                        'cost': 0.00006,
+                        'datetime': '2018-03-25T15:15:14.000Z',
+                        'id': '1-1',
+                        'info': {
+                            'amount': '0.0006',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:15:14',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '1',
+                            'rate': '0.1',
+                            'total': '0.00006',
+                            'tradeID': '1-1',
+                            'type': 'buy'
+                            },
+                        'order': '1',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983714,
+                        'type': 'limit'
+                        },
+                    { # Wrong timestamp 2
+                        'amount': 0.0004,
+                        'cost': 0.00004,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '1-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '1',
+                            'rate': '0.1',
+                            'total': '0.00004',
+                            'tradeID': '1-2',
+                            'type': 'buy'
+                            },
+                        'order': '1',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    { # Wrong side 1
+                        'amount': 0.0006,
+                        'cost': 0.00006,
+                        'datetime': '2018-03-25T15:15:54.000Z',
+                        'id': '2-1',
+                        'info': {
+                            'amount': '0.0006',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:15:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '2',
+                            'rate': '0.1',
+                            'total': '0.00006',
+                            'tradeID': '2-1',
+                            'type': 'sell'
+                            },
+                        'order': '2',
+                        'price': 0.1,
+                        'side': 'sell',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983754,
+                        'type': 'limit'
+                        },
+                    { # Wrong side 2
+                        'amount': 0.0004,
+                        'cost': 0.00004,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '2-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '2',
+                            'rate': '0.1',
+                            'total': '0.00004',
+                            'tradeID': '2-2',
+                            'type': 'buy'
+                            },
+                        'order': '2',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    { # Margin trade 1
+                        'amount': 0.0006,
+                        'cost': 0.00006,
+                        'datetime': '2018-03-25T15:15:54.000Z',
+                        'id': '3-1',
+                        'info': {
+                            'amount': '0.0006',
+                            'category': 'marginTrade',
+                            'date': '2018-03-25 15:15:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '3',
+                            'rate': '0.1',
+                            'total': '0.00006',
+                            'tradeID': '3-1',
+                            'type': 'buy'
+                            },
+                        'order': '3',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983754,
+                        'type': 'limit'
+                        },
+                    { # Margin trade 2
+                        'amount': 0.0004,
+                        'cost': 0.00004,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '3-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'marginTrade',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '3',
+                            'rate': '0.1',
+                            'total': '0.00004',
+                            'tradeID': '3-2',
+                            'type': 'buy'
+                            },
+                        'order': '3',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    { # Wrong amount 1
+                        'amount': 0.0005,
+                        'cost': 0.00005,
+                        'datetime': '2018-03-25T15:15:54.000Z',
+                        'id': '4-1',
+                        'info': {
+                            'amount': '0.0005',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:15:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '4',
+                            'rate': '0.1',
+                            'total': '0.00005',
+                            'tradeID': '4-1',
+                            'type': 'buy'
+                            },
+                        'order': '4',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983754,
+                        'type': 'limit'
+                        },
+                    { # Wrong amount 2
+                        'amount': 0.0004,
+                        'cost': 0.00004,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '4-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '4',
+                            'rate': '0.1',
+                            'total': '0.00004',
+                            'tradeID': '4-2',
+                            'type': 'buy'
+                            },
+                        'order': '4',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    { # Wrong price 1
+                        'amount': 0.0006,
+                        'cost': 0.000066,
+                        'datetime': '2018-03-25T15:15:54.000Z',
+                        'id': '5-1',
+                        'info': {
+                            'amount': '0.0006',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:15:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '5',
+                            'rate': '0.11',
+                            'total': '0.000066',
+                            'tradeID': '5-1',
+                            'type': 'buy'
+                            },
+                        'order': '5',
+                        'price': 0.11,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983754,
+                        'type': 'limit'
+                        },
+                    { # Wrong price 2
+                        'amount': 0.0004,
+                        'cost': 0.00004,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '5-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '5',
+                            'rate': '0.1',
+                            'total': '0.00004',
+                            'tradeID': '5-2',
+                            'type': 'buy'
+                            },
+                        'order': '5',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    { # All good 1
+                        'amount': 0.0006,
+                        'cost': 0.00006,
+                        'datetime': '2018-03-25T15:15:54.000Z',
+                        'id': '7-1',
+                        'info': {
+                            'amount': '0.0006',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:15:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 1,
+                            'orderNumber': '7',
+                            'rate': '0.1',
+                            'total': '0.00006',
+                            'tradeID': '7-1',
+                            'type': 'buy'
+                            },
+                        'order': '7',
+                        'price': 0.1,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983754,
+                        'type': 'limit'
+                        },
+                    { # All good 2
+                        'amount': 0.0004,
+                        'cost': 0.000036,
+                        'datetime': '2018-03-25T15:16:54.000Z',
+                        'id': '7-2',
+                        'info': {
+                            'amount': '0.0004',
+                            'category': 'exchange',
+                            'date': '2018-03-25 15:16:54',
+                            'fee': '0.00150000',
+                            'globalTradeID': 2,
+                            'orderNumber': '7',
+                            'rate': '0.09',
+                            'total': '0.000036',
+                            'tradeID': '7-2',
+                            'type': 'buy'
+                            },
+                        'order': '7',
+                        'price': 0.09,
+                        'side': 'buy',
+                        'symbol': 'ETH/BTC',
+                        'timestamp': 1521983814,
+                        'type': 'limit'
+                        },
+                    ]
+
+            result = order.retrieve_order()
+            self.assertTrue(result)
+            self.assertEqual('7', order.results[0]["id"])
+            self.m.ccxt.fetch_orders.assert_called_once_with(symbol="ETH/BTC", since=1521983750)
+
+        self.m.reset_mock()
+        with self.subTest(similar_open_order=False, past_trades=False):
+            order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"),
+                    D("0.1"), "BTC", "long", self.m, "trade")
+            order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55)
+
+            self.m.ccxt.order_precision.return_value = 8
+            self.m.ccxt.fetch_orders.return_value = []
+            self.m.ccxt.fetch_my_trades.return_value = []
+            result = order.retrieve_order()
+            self.assertFalse(result)
 
 @unittest.skipUnless("unit" in limits, "Unit skipped")
 class MouvementTest(WebMockTestCase):