]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blobdiff - test.py
Add processors
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / test.py
diff --git a/test.py b/test.py
index 141c9e062d9cd6ea9a7ecfdb98bcdf3bdef93862..740921268cf35f01ee3a046752099cd8d3045ec1 100644 (file)
--- a/test.py
+++ b/test.py
@@ -45,6 +45,87 @@ class WebMockTestCase(unittest.TestCase):
         self.wm.stop()
         super(WebMockTestCase, self).tearDown()
 
+@unittest.skipUnless("unit" in limits, "Unit skipped")
+class poloniexETest(unittest.TestCase):
+    def setUp(self):
+        super(poloniexETest, self).setUp()
+        self.wm = requests_mock.Mocker()
+        self.wm.start()
+
+        self.s = market.ccxt.poloniexE()
+
+    def tearDown(self):
+        self.wm.stop()
+        super(poloniexETest, self).tearDown()
+
+    def test_nanoseconds(self):
+        with mock.patch.object(market.ccxt.time, "time") as time:
+            time.return_value = 123456.7890123456
+            self.assertEqual(123456789012345, self.s.nanoseconds())
+
+    def test_nonce(self):
+        with mock.patch.object(market.ccxt.time, "time") as time:
+            time.return_value = 123456.7890123456
+            self.assertEqual(123456789012345, self.s.nonce())
+
+    def test_order_precision(self):
+        self.assertEqual(8, self.s.order_precision("FOO"))
+
+    def test_transfer_balance(self):
+        with self.subTest(success=True),\
+                mock.patch.object(self.s, "privatePostTransferBalance") as t:
+            t.return_value = { "success": 1 }
+            result = self.s.transfer_balance("FOO", 12, "exchange", "margin")
+            t.assert_called_once_with({
+                "currency": "FOO",
+                "amount": 12,
+                "fromAccount": "exchange",
+                "toAccount": "margin",
+                "confirmed": 1
+                })
+            self.assertTrue(result)
+
+        with self.subTest(success=False),\
+                mock.patch.object(self.s, "privatePostTransferBalance") as t:
+            t.return_value = { "success": 0 }
+            self.assertFalse(self.s.transfer_balance("FOO", 12, "exchange", "margin"))
+
+    def test_close_margin_position(self):
+        with mock.patch.object(self.s, "privatePostCloseMarginPosition") as c:
+            self.s.close_margin_position("FOO", "BAR")
+            c.assert_called_with({"currencyPair": "BAR_FOO"})
+
+    def test_tradable_balances(self):
+        with mock.patch.object(self.s, "privatePostReturnTradableBalances") as r:
+            r.return_value = {
+                    "FOO": { "exchange": "12.1234", "margin": "0.0123" },
+                    "BAR": { "exchange": "1", "margin": "0" },
+                    }
+            balances = self.s.tradable_balances()
+            self.assertEqual(["FOO", "BAR"], list(balances.keys()))
+            self.assertEqual(["exchange", "margin"], list(balances["FOO"].keys()))
+            self.assertEqual(D("12.1234"), balances["FOO"]["exchange"])
+            self.assertEqual(["exchange", "margin"], list(balances["BAR"].keys()))
+
+    def test_margin_summary(self):
+        with mock.patch.object(self.s, "privatePostReturnMarginAccountSummary") as r:
+            r.return_value = {
+                    "currentMargin": "1.49680968",
+                    "lendingFees": "0.0000001",
+                    "pl": "0.00008254",
+                    "totalBorrowedValue": "0.00673602",
+                    "totalValue": "0.01000000",
+                    "netValue": "0.01008254",
+                    }
+            expected = {
+                    'current_margin': D('1.49680968'),
+                    'gains': D('0.00008254'),
+                    'lending_fees': D('0.0000001'),
+                    'total': D('0.01000000'),
+                    'total_borrowed': D('0.00673602')
+                    }
+            self.assertEqual(expected, self.s.margin_summary())
+
 @unittest.skipUnless("unit" in limits, "Unit skipped")
 class PortfolioTest(WebMockTestCase):
     def fill_data(self):
@@ -612,6 +693,7 @@ class MarketTest(WebMockTestCase):
             self.assertTrue(ticker["inverted"])
             self.assertIn("original", ticker)
             self.assertEqual(10, ticker["original"]["bid"])
+            self.assertEqual(25, ticker["original"]["average"])
 
             ticker = m.get_ticker("XVG", "XMR")
             self.assertIsNone(ticker)
@@ -640,6 +722,7 @@ class MarketTest(WebMockTestCase):
             self.assertTrue(ticker["inverted"])
             self.assertIn("original", ticker)
             self.assertEqual(10, ticker["original"]["bid"])
+            self.assertEqual(25, ticker["original"]["average"])
 
             ticker = m.get_ticker("XVG", "XMR")
             self.assertIsNone(ticker)
@@ -698,99 +781,11 @@ class MarketTest(WebMockTestCase):
             self.assertEqual(D("0.01"), call[0][0]["XVG"].value)
             self.assertEqual(D("0.2525"), call[0][1]["BTC"].value)
             self.assertEqual(D("0.7575"), call[0][1]["XEM"].value)
-            m.report.log_stage.assert_called_once_with("prepare_trades")
-            m.report.log_balances.assert_called_once_with(tag="tag")
-
-    @mock.patch.object(portfolio.Portfolio, "repartition")
-    @mock.patch.object(market.Market, "get_ticker")
-    @mock.patch.object(market.TradeStore, "compute_trades")
-    def test_update_trades(self, compute_trades, get_ticker, repartition):
-        repartition.return_value = {
-                "XEM": (D("0.75"), "long"),
-                "BTC": (D("0.25"), "long"),
-                }
-        def _get_ticker(c1, c2):
-            if c1 == "USDT" and c2 == "BTC":
-                return { "average": D("0.0001") }
-            if c1 == "XVG" and c2 == "BTC":
-                return { "average": D("0.000001") }
-            if c1 == "XEM" and c2 == "BTC":
-                return { "average": D("0.001") }
-            self.fail("Should be called with {}, {}".format(c1, c2))
-        get_ticker.side_effect = _get_ticker
-
-        with mock.patch("market.ReportStore"):
-            m = market.Market(self.ccxt)
-            self.ccxt.fetch_all_balances.return_value = {
-                    "USDT": {
-                        "exchange_free": D("10000.0"),
-                        "exchange_used": D("0.0"),
-                        "exchange_total": D("10000.0"),
-                        "total": D("10000.0")
-                        },
-                    "XVG": {
-                        "exchange_free": D("10000.0"),
-                        "exchange_used": D("0.0"),
-                        "exchange_total": D("10000.0"),
-                        "total": D("10000.0")
-                        },
-                    }
-
-            m.balances.fetch_balances(tag="tag")
-
-            m.update_trades()
-            compute_trades.assert_called()
-
-            call = compute_trades.call_args
-            self.assertEqual(1, call[0][0]["USDT"].value)
-            self.assertEqual(D("0.01"), call[0][0]["XVG"].value)
-            self.assertEqual(D("0.2525"), call[0][1]["BTC"].value)
-            self.assertEqual(D("0.7575"), call[0][1]["XEM"].value)
-            m.report.log_stage.assert_called_once_with("update_trades")
+            m.report.log_stage.assert_called_once_with("prepare_trades",
+                    base_currency='BTC', compute_value='average',
+                    liquidity='medium', only=None, repartition=None)
             m.report.log_balances.assert_called_once_with(tag="tag")
 
-    @mock.patch.object(portfolio.Portfolio, "repartition")
-    @mock.patch.object(market.Market, "get_ticker")
-    @mock.patch.object(market.TradeStore, "compute_trades")
-    def test_prepare_trades_to_sell_all(self, compute_trades, get_ticker, repartition):
-        def _get_ticker(c1, c2):
-            if c1 == "USDT" and c2 == "BTC":
-                return { "average": D("0.0001") }
-            if c1 == "XVG" and c2 == "BTC":
-                return { "average": D("0.000001") }
-            self.fail("Should be called with {}, {}".format(c1, c2))
-        get_ticker.side_effect = _get_ticker
-
-        with mock.patch("market.ReportStore"):
-            m = market.Market(self.ccxt)
-            self.ccxt.fetch_all_balances.return_value = {
-                    "USDT": {
-                        "exchange_free": D("10000.0"),
-                        "exchange_used": D("0.0"),
-                        "exchange_total": D("10000.0"),
-                        "total": D("10000.0")
-                        },
-                    "XVG": {
-                        "exchange_free": D("10000.0"),
-                        "exchange_used": D("0.0"),
-                        "exchange_total": D("10000.0"),
-                        "total": D("10000.0")
-                        },
-                    }
-
-            m.balances.fetch_balances(tag="tag")
-
-            m.prepare_trades_to_sell_all()
-
-            repartition.assert_not_called()
-            compute_trades.assert_called()
-
-            call = compute_trades.call_args
-            self.assertEqual(1, call[0][0]["USDT"].value)
-            self.assertEqual(D("0.01"), call[0][0]["XVG"].value)
-            self.assertEqual(D("1.01"), call[0][1]["BTC"].value)
-            m.report.log_stage.assert_called_once_with("prepare_trades_to_sell_all")
-            m.report.log_balances.assert_called_once_with(tag="tag")
 
     @mock.patch.object(portfolio.time, "sleep")
     @mock.patch.object(market.TradeStore, "all_orders")
@@ -2273,12 +2268,24 @@ class ReportStoreTest(WebMockTestCase):
     @mock.patch.object(market.ReportStore, "add_log")
     def test_log_stage(self, add_log, print_log):
         report_store = market.ReportStore(self.m)
-        report_store.log_stage("foo")
+        c = lambda x: x
+        report_store.log_stage("foo", bar="baz", c=c, d=portfolio.Amount("BTC", 1))
         print_log.assert_has_calls([
             mock.call("-----------"),
-            mock.call("[Stage] foo"),
+            mock.call("[Stage] foo bar=baz, c=c = lambda x: x, d={'currency': 'BTC', 'value': Decimal('1')}"),
             ])
-        add_log.assert_called_once_with({'type': 'stage', 'stage': 'foo'})
+        add_log.assert_called_once_with({
+            'type': 'stage',
+            'stage': 'foo',
+            'args': {
+                'bar': 'baz',
+                'c': 'c = lambda x: x',
+                'd': {
+                    'currency': 'BTC',
+                    'value': D('1')
+                    }
+                }
+            })
 
     @mock.patch.object(market.ReportStore, "print_log")
     @mock.patch.object(market.ReportStore, "add_log")
@@ -2791,71 +2798,55 @@ class HelperTest(WebMockTestCase):
 
             self.assertRegex(stdout_mock.getvalue(), "impossible to store report file: FileNotFoundError;")
 
-    @mock.patch("helper.process_sell_all__1_all_sell")
-    @mock.patch("helper.process_sell_all__2_all_buy")
-    @mock.patch("portfolio.Portfolio.wait_for_recent")
-    def test_main_process_market(self, wait, buy, sell):
+    @mock.patch("helper.Processor.process")
+    def test_main_process_market(self, process):
         with self.subTest(before=False, after=False):
-            helper.main_process_market("user", None)
-            
-            wait.assert_not_called()
-            buy.assert_not_called()
-            sell.assert_not_called()
+            m = mock.Mock()
+            helper.main_process_market(m, None)
+
+            process.assert_not_called()
 
-        buy.reset_mock()
-        wait.reset_mock()
-        sell.reset_mock()
+        process.reset_mock()
         with self.subTest(before=True, after=False):
-            helper.main_process_market("user", None, before=True)
-            
-            wait.assert_not_called()
-            buy.assert_not_called()
-            sell.assert_called_once_with("user")
+            helper.main_process_market(m, None, before=True)
+
+            process.assert_called_once_with("sell_all", steps="before")
 
-        buy.reset_mock()
-        wait.reset_mock()
-        sell.reset_mock()
+        process.reset_mock()
         with self.subTest(before=False, after=True):
-            helper.main_process_market("user", None, after=True)
+            helper.main_process_market(m, None, after=True)
             
-            wait.assert_called_once_with("user")
-            buy.assert_called_once_with("user")
-            sell.assert_not_called()
+            process.assert_called_once_with("sell_all", steps="after")
 
-        buy.reset_mock()
-        wait.reset_mock()
-        sell.reset_mock()
+        process.reset_mock()
         with self.subTest(before=True, after=True):
-            helper.main_process_market("user", None, before=True, after=True)
-            
-            wait.assert_called_once_with("user")
-            buy.assert_called_once_with("user")
-            sell.assert_called_once_with("user")
+            helper.main_process_market(m, None, before=True, after=True)
 
-        buy.reset_mock()
-        wait.reset_mock()
-        sell.reset_mock()
+            process.assert_has_calls([
+                mock.call("sell_all", steps="before"),
+                mock.call("sell_all", steps="after"),
+                ])
+
+        process.reset_mock()
         with self.subTest(action="print_balances"),\
                 mock.patch("helper.print_balances") as print_balances:
-            helper.main_process_market("user", "print_balances")
+            helper.main_process_market("user", ["print_balances"])
 
-            buy.assert_not_called()
-            wait.assert_not_called()
-            sell.assert_not_called()
+            process.assert_not_called()
             print_balances.assert_called_once_with("user")
 
         with self.subTest(action="print_orders"),\
-                mock.patch("helper.print_orders") as print_orders:
-            helper.main_process_market("user", "print_orders")
+                mock.patch("helper.print_orders") as print_orders,\
+                mock.patch("helper.print_balances") as print_balances:
+            helper.main_process_market("user", ["print_orders", "print_balances"])
 
-            buy.assert_not_called()
-            wait.assert_not_called()
-            sell.assert_not_called()
+            process.assert_not_called()
             print_orders.assert_called_once_with("user")
+            print_balances.assert_called_once_with("user")
 
         with self.subTest(action="unknown"),\
                 self.assertRaises(NotImplementedError):
-            helper.main_process_market("user", "unknown")
+            helper.main_process_market("user", ["unknown"])
 
     @mock.patch.object(helper, "psycopg2")
     def test_fetch_markets(self, psycopg2):
@@ -3004,7 +2995,7 @@ class HelperTest(WebMockTestCase):
             mock.call(tag="process_sell_needed__2_buy_begin"),
             mock.call(tag="process_sell_needed__2_buy_end"),
             ])
-        self.m.update_trades.assert_called_with(base_currency="BTC",
+        self.m.prepare_trades.assert_called_with(base_currency="BTC",
                 liquidity="medium", only="acquire")
         self.m.trades.prepare_orders.assert_called_with(compute_value="average",
                 only="acquire")
@@ -3023,7 +3014,8 @@ class HelperTest(WebMockTestCase):
             mock.call(tag="process_sell_all__1_all_sell_begin"),
             mock.call(tag="process_sell_all__1_all_sell_end"),
             ])
-        self.m.prepare_trades_to_sell_all.assert_called_with(base_currency="BTC")
+        self.m.prepare_trades.assert_called_with(base_currency="BTC",
+                liquidity="medium", repartition={'BTC': (1, 'long')})
         self.m.trades.prepare_orders.assert_called_with(compute_value="average")
         self.m.trades.run_orders.assert_called()
         self.m.follow_orders.assert_called()
@@ -3032,12 +3024,22 @@ class HelperTest(WebMockTestCase):
             mock.call("process_sell_all__1_all_sell_end")
             ])
 
-    def test_process_sell_all__2_all_buy(self):
-        helper.process_sell_all__2_all_buy(self.m)
+    @mock.patch("portfolio.Portfolio.wait_for_recent")
+    def test_process_sell_all__2_wait(self, wait):
+        helper.process_sell_all__2_wait(self.m)
+
+        wait.assert_called_once_with(self.m)
+        self.m.report.log_stage.assert_has_calls([
+            mock.call("process_sell_all__2_wait_begin"),
+            mock.call("process_sell_all__2_wait_end")
+            ])
+
+    def test_process_sell_all__3_all_buy(self):
+        helper.process_sell_all__3_all_buy(self.m)
 
         self.m.balances.fetch_balances.assert_has_calls([
-            mock.call(tag="process_sell_all__2_all_buy_begin"),
-            mock.call(tag="process_sell_all__2_all_buy_end"),
+            mock.call(tag="process_sell_all__3_all_buy_begin"),
+            mock.call(tag="process_sell_all__3_all_buy_end"),
             ])
         self.m.prepare_trades.assert_called_with(base_currency="BTC",
                 liquidity="medium")
@@ -3046,8 +3048,8 @@ class HelperTest(WebMockTestCase):
         self.m.trades.run_orders.assert_called()
         self.m.follow_orders.assert_called()
         self.m.report.log_stage.assert_has_calls([
-            mock.call("process_sell_all__2_all_buy_begin"),
-            mock.call("process_sell_all__2_all_buy_end")
+            mock.call("process_sell_all__3_all_buy_begin"),
+            mock.call("process_sell_all__3_all_buy_end")
             ])
 
 @unittest.skipUnless("acceptance" in limits, "Acceptance skipped")
@@ -3251,7 +3253,7 @@ class AcceptanceTest(WebMockTestCase):
 
         with mock.patch.object(portfolio.Portfolio, "repartition", return_value=repartition):
             # Action 5
-            helper.update_trades(market, only="acquire", compute_value="average")
+            helper.prepare_trades(market, only="acquire", compute_value="average")
 
         balances = portfolio.BalanceStore.all
         self.assertEqual(portfolio.Amount("ETH", 1 / D("3")), balances["ETH"].total)