]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/commitdiff
Add liquidity option for cryptoportfolio users
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 4 Aug 2018 18:12:33 +0000 (20:12 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 4 Aug 2018 18:12:33 +0000 (20:12 +0200)
main.py
market.py
tests/test_main.py
tests/test_market.py

diff --git a/main.py b/main.py
index ab523bec068fa4c00e08de16a1bf54ea7ef378ae..a7ad8f73db8e3983171b9727a9e0e898915c7b5b 100644 (file)
--- a/main.py
+++ b/main.py
@@ -64,19 +64,30 @@ def get_user_market(config_path, user_id, debug=False):
         args.append("--debug")
     args = parse_args(args)
     parse_config(args)
-    market_id, market_config, user_id = list(fetch_markets(str(user_id)))[0]
-    return market.Market.from_config(market_config, args, user_id=user_id)
+    market_id, market_config, user_id, options = list(fetch_markets(str(user_id)))[0]
+    return market.Market.from_config(market_config, args, user_id=user_id, options=options)
 
 def fetch_markets(user):
     cursor = dbs.psql.cursor()
 
     if user is None:
-        cursor.execute("SELECT id,config,user_id FROM market_configs WHERE status='enabled'")
+        cursor.execute("SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled'")
     else:
-        cursor.execute("SELECT id,config,user_id FROM market_configs WHERE status='enabled' AND user_id = %s", [user])
+        cursor.execute("SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled' AND user_id = %s", [user])
 
     for row in cursor:
-        yield row
+        options = {
+                "liquidity": parse_liquidity(row[3])
+                }
+        yield row[0:3] + (options,)
+
+def parse_liquidity(value):
+    if value == "high-liquidity":
+        return "high"
+    elif value == "medium-liquidity":
+        return "medium"
+    else:
+        return None
 
 def parse_config(args):
     if args.db_host is not None:
@@ -152,11 +163,11 @@ def parse_args(argv):
         parsed.action = ["sell_all"]
     return parsed
 
-def process(market_config, market_id, user_id, args):
+def process(market_config, market_id, user_id, args, options):
     try:
         market.Market\
                 .from_config(market_config, args, market_id=market_id,
-                        user_id=user_id)\
+                        user_id=user_id, options=options)\
                 .process(args.action, before=args.before, after=args.after)
     except Exception as e:
         print("{}: {}".format(e.__class__.__name__, e))
@@ -180,8 +191,8 @@ def main(argv):
     else:
         process_ = process
 
-    for market_id, market_config, user_id in fetch_markets(args.user):
-        process_(market_config, market_id, user_id, args)
+    for market_id, market_config, user_id, options in fetch_markets(args.user):
+        process_(market_config, market_id, user_id, args, options)
 
     if args.parallel:
         for thread in threads:
index 41c4c9c5652d6c24629aca26d21e58797a7eb6e5..82df34f4766ba7648cce4a5e4f364dde948c53b1 100644 (file)
--- a/market.py
+++ b/market.py
@@ -15,6 +15,7 @@ class Market:
     report = None
     trades = None
     balances = None
+    options = None
 
     def __init__(self, ccxt_instance, args, **kwargs):
         self.args = args
@@ -26,6 +27,7 @@ class Market:
         self.balances = BalanceStore(self)
         self.processor = Processor(self)
 
+        self.options = kwargs.get("options", {})
         for key in ["user_id", "market_id"]:
             setattr(self, key, kwargs.get(key, None))
 
@@ -466,7 +468,7 @@ class Processor:
 
     def parse_args(self, action, default_args, kwargs):
         method, allowed_arguments = self.method_arguments(action)
-        args = {k: v for k, v in {**default_args, **kwargs}.items() if k in allowed_arguments }
+        args = {k: v for k, v in {**default_args, **kwargs, **self.market.options}.items() if k in allowed_arguments }
 
         if "repartition" in args and "base_currency" in args["repartition"]:
             r = args["repartition"]
index 0b4745f659d5a11e6b66faee79aa20f603f26e8a..3735a3be58bbe81a7cd948829b77eee27e0249be 100644 (file)
@@ -103,23 +103,29 @@ class MainTest(WebMockTestCase):
                 mock.patch("main.parse_config") as main_parse_config:
             with self.subTest(debug=False):
                 main_parse_args.return_value = self.market_args()
-                main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)]
+                main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3, { "foo": "bar" })]
                 m = main.get_user_market("config_path.ini", 1)
 
                 self.assertIsInstance(m, market.Market)
                 self.assertFalse(m.debug)
+                self.assertEqual("bar", m.options["foo"])
                 main_parse_args.assert_called_once_with(["--config", "config_path.ini"])
 
             main_parse_args.reset_mock()
             with self.subTest(debug=True):
                 main_parse_args.return_value = self.market_args(debug=True)
-                main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3)]
+                main_fetch_markets.return_value = [(1, {"key": "market_config"}, 3, { "foo": "bar" })]
                 m = main.get_user_market("config_path.ini", 1, debug=True)
 
                 self.assertIsInstance(m, market.Market)
                 self.assertTrue(m.debug)
                 main_parse_args.assert_called_once_with(["--config", "config_path.ini", "--debug"])
 
+    def test_parse_liquidity(self):
+        self.assertEqual("high", main.parse_liquidity("high-liquidity"))
+        self.assertEqual("medium", main.parse_liquidity("medium-liquidity"))
+        self.assertIsNone(main.parse_liquidity("foo"))
+
     def test_process(self):
         with mock.patch("market.Market") as market_mock,\
                 mock.patch('sys.stdout', new_callable=StringIO) as stdout_mock:
@@ -133,16 +139,16 @@ class MainTest(WebMockTestCase):
             args_mock.after = "after"
             self.assertEqual("", stdout_mock.getvalue())
 
-            main.process("config", 3, 1, args_mock)
+            main.process("config", 3, 1, args_mock, "options")
 
             market_mock.from_config.assert_has_calls([
-                mock.call("config", args_mock, market_id=3, user_id=1),
+                mock.call("config", args_mock, market_id=3, user_id=1, options="options"),
                 mock.call().process("action", before="before", after="after"),
                 ])
 
             with self.subTest(exception=True):
                 market_mock.from_config.side_effect = Exception("boo")
-                main.process(3, "config", 1, args_mock)
+                main.process(3, "config", 1, args_mock, "options")
                 self.assertEqual("Exception: boo\n", stdout_mock.getvalue())
 
     def test_main(self):
@@ -157,7 +163,10 @@ class MainTest(WebMockTestCase):
                 args_mock.user = "user"
                 parse_args.return_value = args_mock
 
-                fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
+                fetch_markets.return_value = [
+                        [3, "config1", 1, "options"],
+                        [1, "config2", 2, "options"]
+                ]
 
                 main.main(["Foo", "Bar"])
 
@@ -167,9 +176,10 @@ class MainTest(WebMockTestCase):
 
                 self.assertEqual(2, process.call_count)
                 process.assert_has_calls([
-                    mock.call("config1", 3, 1, args_mock),
-                    mock.call("config2", 1, 2, args_mock),
+                    mock.call("config1", 3, 1, args_mock, "options"),
+                    mock.call("config2", 1, 2, args_mock, "options"),
                     ])
+
         with self.subTest(parallel=True):
             with mock.patch("main.parse_args") as parse_args,\
                     mock.patch("main.parse_config") as parse_config,\
@@ -183,7 +193,10 @@ class MainTest(WebMockTestCase):
                 args_mock.user = "user"
                 parse_args.return_value = args_mock
 
-                fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
+                fetch_markets.return_value = [
+                        [3, "config1", 1, "options"],
+                        [1, "config2", 2, "options"]
+                ]
 
                 main.main(["Foo", "Bar"])
 
@@ -196,10 +209,11 @@ class MainTest(WebMockTestCase):
                 self.assertEqual(2, process.call_count)
                 process.assert_has_calls([
                     mock.call.__bool__(),
-                    mock.call("config1", 3, 1, args_mock),
+                    mock.call("config1", 3, 1, args_mock, "options"),
                     mock.call.__bool__(),
-                    mock.call("config2", 1, 2, args_mock),
+                    mock.call("config2", 1, 2, args_mock, "options"),
                     ])
+
         with self.subTest(quiet=True):
             with mock.patch("main.parse_args") as parse_args,\
                     mock.patch("main.parse_config") as parse_config,\
@@ -213,7 +227,10 @@ class MainTest(WebMockTestCase):
                 args_mock.user = "user"
                 parse_args.return_value = args_mock
 
-                fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
+                fetch_markets.return_value = [
+                        [3, "config1", 1, "options"],
+                        [1, "config2", 2, "options"]
+                ]
 
                 main.main(["Foo", "Bar"])
 
@@ -232,7 +249,10 @@ class MainTest(WebMockTestCase):
                 args_mock.user = "user"
                 parse_args.return_value = args_mock
 
-                fetch_markets.return_value = [[3, "config1", 1], [1, "config2", 2]]
+                fetch_markets.return_value = [
+                        [3, "config1", 1, "options"],
+                        [1, "config2", 2, "options"]
+                ]
 
                 main.main(["Foo", "Bar"])
 
@@ -318,23 +338,32 @@ class MainTest(WebMockTestCase):
     @mock.patch.object(main.dbs, "psql")
     def test_fetch_markets(self, psql):
         cursor_mock = mock.MagicMock()
-        cursor_mock.__iter__.return_value = ["row_1", "row_2"]
+        cursor_mock.__iter__.return_value = [
+                (1, "cfg", 1, "high-liquidity"),
+                (2, "cfg2", 3, "medium-liquidity")
+                ]
 
         psql.cursor.return_value = cursor_mock
 
         with self.subTest(user=None):
             rows = list(main.fetch_markets(None))
 
-            cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE status='enabled'")
+            cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled'")
 
-            self.assertEqual(["row_1", "row_2"], rows)
+            self.assertEqual([
+                (1, 'cfg', 1, {'liquidity': 'high'}),
+                (2, 'cfg2', 3, {'liquidity': 'medium'})
+                ], rows)
 
         cursor_mock.execute.reset_mock()
         with self.subTest(user=1):
             rows = list(main.fetch_markets(1))
 
-            cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id FROM market_configs WHERE status='enabled' AND user_id = %s", [1])
+            cursor_mock.execute.assert_called_once_with("SELECT id,config,user_id,portfolio_profile FROM market_configs_augmented WHERE status='enabled' AND user_id = %s", [1])
 
-            self.assertEqual(["row_1", "row_2"], rows)
+            self.assertEqual([
+                (1, 'cfg', 1, {'liquidity': 'high'}),
+                (2, 'cfg2', 3, {'liquidity': 'medium'})
+                ], rows)
 
 
index c02968672aa46cdadb64379ac40d87e970c1e7ea..aeb9f8e252369d19641e25ef1b0a79f34f733ed7 100644 (file)
@@ -1126,12 +1126,13 @@ class ProcessorTest(WebMockTestCase):
             method_mock = mock.Mock()
             method_arguments.return_value = [
                     method_mock,
-                    ["foo2", "foo"]
+                    ["foo2", "foo", "foo3"]
                     ]
+            self.m.options = { "foo3": "coucou"}
             method, args = processor.parse_args("action", {"foo": "bar", "foo2": "bar"}, {"foo": "bar2", "bla": "bla"})
 
             self.assertEqual(method_mock, method)
-            self.assertEqual({"foo": "bar2", "foo2": "bar"}, args)
+            self.assertEqual({"foo": "bar2", "foo2": "bar", "foo3": "coucou"}, args)
 
         with mock.patch.object(processor, "method_arguments") as method_arguments:
             method_mock = mock.Mock()