X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=test.py;h=c229801246219870d99e5f8c574793dd96f1ddcc;hb=915980607f7325b0759bd508d21aa1467a590392;hp=18616c1c848620d93a19d61c72b4edcd7c773ea1;hpb=45fffd4963005a1f3957868f9ddb1aa7ec66c0e3;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FCryptoportfolio%2FTrader.git diff --git a/test.py b/test.py index 18616c1..c229801 100644 --- a/test.py +++ b/test.py @@ -101,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"): @@ -109,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"): @@ -117,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"): @@ -125,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() @@ -1444,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) @@ -3080,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):