From ef8fa5e5454a17c49fe14f6a2c1cffa9cd985bdb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Sat, 4 Aug 2018 20:12:33 +0200 Subject: [PATCH] Add liquidity option for cryptoportfolio users --- main.py | 29 ++++++++++++++------ market.py | 4 ++- tests/test_main.py | 65 ++++++++++++++++++++++++++++++++------------ tests/test_market.py | 5 ++-- 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/main.py b/main.py index ab523be..a7ad8f7 100644 --- 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: diff --git a/market.py b/market.py index 41c4c9c..82df34f 100644 --- 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"] diff --git a/tests/test_main.py b/tests/test_main.py index 0b4745f..3735a3b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -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) diff --git a/tests/test_market.py b/tests/test_market.py index c029686..aeb9f8e 100644 --- a/tests/test_market.py +++ b/tests/test_market.py @@ -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() -- 2.41.0