diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-05-01 17:24:40 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-05-01 17:24:40 +0200 |
commit | 2b1ee8f4d54fa1672510141a71a5817120ac031c (patch) | |
tree | 762d3a59d666bf6e1d4d1ea5901c31ab06f7e88e | |
parent | 37b64a97021220df0bee5fd927184b92b10e8d76 (diff) | |
download | Trader-2b1ee8f4d54fa1672510141a71a5817120ac031c.tar.gz Trader-2b1ee8f4d54fa1672510141a71a5817120ac031c.tar.zst Trader-2b1ee8f4d54fa1672510141a71a5817120ac031c.zip |
Store tickers in balance log
-rw-r--r-- | market.py | 4 | ||||
-rw-r--r-- | store.py | 31 | ||||
-rw-r--r-- | tests/test_market.py | 4 | ||||
-rw-r--r-- | tests/test_store.py | 133 |
4 files changed, 116 insertions, 56 deletions
@@ -391,14 +391,14 @@ class Processor: | |||
391 | process_name = "process_{}__{}_{}".format(scenario_name, step["number"], step["name"]) | 391 | process_name = "process_{}__{}_{}".format(scenario_name, step["number"], step["name"]) |
392 | self.market.report.log_stage("{}_begin".format(process_name)) | 392 | self.market.report.log_stage("{}_begin".format(process_name)) |
393 | if "begin" in step.get("fetch_balances", []): | 393 | if "begin" in step.get("fetch_balances", []): |
394 | self.market.balances.fetch_balances(tag="{}_begin".format(process_name)) | 394 | self.market.balances.fetch_balances(tag="{}_begin".format(process_name), log_tickers=True) |
395 | 395 | ||
396 | for action in self.ordered_actions: | 396 | for action in self.ordered_actions: |
397 | if action in step: | 397 | if action in step: |
398 | self.run_action(action, step[action], kwargs) | 398 | self.run_action(action, step[action], kwargs) |
399 | 399 | ||
400 | if "end" in step.get("fetch_balances", []): | 400 | if "end" in step.get("fetch_balances", []): |
401 | self.market.balances.fetch_balances(tag="{}_end".format(process_name)) | 401 | self.market.balances.fetch_balances(tag="{}_end".format(process_name), log_tickers=True) |
402 | self.market.report.log_stage("{}_end".format(process_name)) | 402 | self.market.report.log_stage("{}_end".format(process_name)) |
403 | 403 | ||
404 | def method_arguments(self, action): | 404 | def method_arguments(self, action): |
@@ -98,7 +98,8 @@ class ReportStore: | |||
98 | "args": args, | 98 | "args": args, |
99 | }) | 99 | }) |
100 | 100 | ||
101 | def log_balances(self, tag=None): | 101 | def log_balances(self, tag=None, tickers=None, |
102 | ticker_currency=None, compute_value=None, type=None): | ||
102 | self.print_log("[Balance]") | 103 | self.print_log("[Balance]") |
103 | for currency, balance in self.market.balances.all.items(): | 104 | for currency, balance in self.market.balances.all.items(): |
104 | self.print_log("\t{}".format(balance)) | 105 | self.print_log("\t{}".format(balance)) |
@@ -109,11 +110,22 @@ class ReportStore: | |||
109 | "balances": self.market.balances.as_json() | 110 | "balances": self.market.balances.as_json() |
110 | } | 111 | } |
111 | 112 | ||
113 | if tickers is not None: | ||
114 | log["tickers"] = self._ticker_hash(tickers, ticker_currency, | ||
115 | compute_value, type) | ||
116 | |||
112 | self.add_log(log.copy()) | 117 | self.add_log(log.copy()) |
113 | self.add_redis_status(log) | 118 | self.add_redis_status(log) |
114 | 119 | ||
115 | def log_tickers(self, amounts, other_currency, | 120 | def log_tickers(self, amounts, other_currency, |
116 | compute_value, type): | 121 | compute_value, type): |
122 | log = self._ticker_hash(amounts, other_currency, compute_value, | ||
123 | type) | ||
124 | log["type"] = "tickers" | ||
125 | |||
126 | self.add_log(log) | ||
127 | |||
128 | def _ticker_hash(self, amounts, other_currency, compute_value, type): | ||
117 | values = {} | 129 | values = {} |
118 | rates = {} | 130 | rates = {} |
119 | if callable(compute_value): | 131 | if callable(compute_value): |
@@ -122,8 +134,7 @@ class ReportStore: | |||
122 | for currency, amount in amounts.items(): | 134 | for currency, amount in amounts.items(): |
123 | values[currency] = amount.as_json()["value"] | 135 | values[currency] = amount.as_json()["value"] |
124 | rates[currency] = amount.rate | 136 | rates[currency] = amount.rate |
125 | log = { | 137 | return { |
126 | "type": "tickers", | ||
127 | "compute_value": compute_value, | 138 | "compute_value": compute_value, |
128 | "balance_type": type, | 139 | "balance_type": type, |
129 | "currency": other_currency, | 140 | "currency": other_currency, |
@@ -132,9 +143,6 @@ class ReportStore: | |||
132 | "total": sum(amounts.values()).as_json()["value"] | 143 | "total": sum(amounts.values()).as_json()["value"] |
133 | } | 144 | } |
134 | 145 | ||
135 | self.add_log(log.copy()) | ||
136 | self.add_redis_status(log) | ||
137 | |||
138 | def log_dispatch(self, amount, amounts, liquidity, repartition): | 146 | def log_dispatch(self, amount, amounts, liquidity, repartition): |
139 | self.add_log({ | 147 | self.add_log({ |
140 | "type": "dispatch", | 148 | "type": "dispatch", |
@@ -294,13 +302,20 @@ class BalanceStore: | |||
294 | compute_value, type) | 302 | compute_value, type) |
295 | return amounts | 303 | return amounts |
296 | 304 | ||
297 | def fetch_balances(self, tag=None): | 305 | def fetch_balances(self, tag=None, log_tickers=False, |
306 | ticker_currency="BTC", ticker_compute_value="average", ticker_type="total"): | ||
298 | all_balances = self.market.ccxt.fetch_all_balances() | 307 | all_balances = self.market.ccxt.fetch_all_balances() |
299 | for currency, balance in all_balances.items(): | 308 | for currency, balance in all_balances.items(): |
300 | if balance["exchange_total"] != 0 or balance["margin_total"] != 0 or \ | 309 | if balance["exchange_total"] != 0 or balance["margin_total"] != 0 or \ |
301 | currency in self.all: | 310 | currency in self.all: |
302 | self.all[currency] = portfolio.Balance(currency, balance) | 311 | self.all[currency] = portfolio.Balance(currency, balance) |
303 | self.market.report.log_balances(tag=tag) | 312 | if log_tickers: |
313 | tickers = self.in_currency(ticker_currency, compute_value=ticker_compute_value, type=ticker_type) | ||
314 | self.market.report.log_balances(tag=tag, | ||
315 | tickers=tickers, ticker_currency=ticker_currency, | ||
316 | compute_value=ticker_compute_value, type=ticker_type) | ||
317 | else: | ||
318 | self.market.report.log_balances(tag=tag) | ||
304 | 319 | ||
305 | def dispatch_assets(self, amount, liquidity="medium", repartition=None): | 320 | def dispatch_assets(self, amount, liquidity="medium", repartition=None): |
306 | if repartition is None: | 321 | if repartition is None: |
diff --git a/tests/test_market.py b/tests/test_market.py index 53630b7..6a3322c 100644 --- a/tests/test_market.py +++ b/tests/test_market.py | |||
@@ -993,8 +993,8 @@ class ProcessorTest(WebMockTestCase): | |||
993 | mock.call("process_foo__1_sell_end"), | 993 | mock.call("process_foo__1_sell_end"), |
994 | ]) | 994 | ]) |
995 | self.m.balances.fetch_balances.assert_has_calls([ | 995 | self.m.balances.fetch_balances.assert_has_calls([ |
996 | mock.call(tag="process_foo__1_sell_begin"), | 996 | mock.call(tag="process_foo__1_sell_begin", log_tickers=True), |
997 | mock.call(tag="process_foo__1_sell_end"), | 997 | mock.call(tag="process_foo__1_sell_end", log_tickers=True), |
998 | ]) | 998 | ]) |
999 | 999 | ||
1000 | self.assertEqual(5, run_action.call_count) | 1000 | self.assertEqual(5, run_action.call_count) |
diff --git a/tests/test_store.py b/tests/test_store.py index df113b7..12999d3 100644 --- a/tests/test_store.py +++ b/tests/test_store.py | |||
@@ -369,17 +369,27 @@ class BalanceStoreTest(WebMockTestCase): | |||
369 | 369 | ||
370 | balance_store = market.BalanceStore(self.m) | 370 | balance_store = market.BalanceStore(self.m) |
371 | 371 | ||
372 | balance_store.fetch_balances() | 372 | with self.subTest(log_tickers=False): |
373 | self.assertNotIn("ETC", balance_store.currencies()) | 373 | balance_store.fetch_balances() |
374 | self.assertListEqual(["USDT", "XVG", "XMR"], list(balance_store.currencies())) | 374 | self.assertNotIn("ETC", balance_store.currencies()) |
375 | 375 | self.assertListEqual(["USDT", "XVG", "XMR"], list(balance_store.currencies())) | |
376 | balance_store.all["ETC"] = portfolio.Balance("ETC", { | 376 | |
377 | "exchange_total": "1", "exchange_free": "0", | 377 | balance_store.all["ETC"] = portfolio.Balance("ETC", { |
378 | "exchange_used": "1" }) | 378 | "exchange_total": "1", "exchange_free": "0", |
379 | balance_store.fetch_balances(tag="foo") | 379 | "exchange_used": "1" }) |
380 | self.assertEqual(0, balance_store.all["ETC"].total) | 380 | balance_store.fetch_balances(tag="foo") |
381 | self.assertListEqual(["USDT", "XVG", "XMR", "ETC"], list(balance_store.currencies())) | 381 | self.assertEqual(0, balance_store.all["ETC"].total) |
382 | self.m.report.log_balances.assert_called_with(tag="foo") | 382 | self.assertListEqual(["USDT", "XVG", "XMR", "ETC"], list(balance_store.currencies())) |
383 | self.m.report.log_balances.assert_called_with(tag="foo") | ||
384 | |||
385 | with self.subTest(log_tickers=True),\ | ||
386 | mock.patch.object(balance_store, "in_currency") as in_currency: | ||
387 | in_currency.return_value = "tickers" | ||
388 | balance_store.fetch_balances(log_tickers=True, ticker_currency="FOO", | ||
389 | ticker_compute_value="compute", ticker_type="type") | ||
390 | self.m.report.log_balances.assert_called_with(compute_value='compute', | ||
391 | tag=None, ticker_currency='FOO', tickers='tickers', | ||
392 | type='type') | ||
383 | 393 | ||
384 | @mock.patch.object(market.Portfolio, "repartition") | 394 | @mock.patch.object(market.Portfolio, "repartition") |
385 | def test_dispatch_assets(self, repartition): | 395 | def test_dispatch_assets(self, repartition): |
@@ -586,27 +596,77 @@ class ReportStoreTest(WebMockTestCase): | |||
586 | self.m.balances.as_json.return_value = "json" | 596 | self.m.balances.as_json.return_value = "json" |
587 | self.m.balances.all = { "FOO": "bar", "BAR": "baz" } | 597 | self.m.balances.all = { "FOO": "bar", "BAR": "baz" } |
588 | 598 | ||
589 | report_store.log_balances(tag="tag") | 599 | with self.subTest(tickers=None): |
590 | print_log.assert_has_calls([ | 600 | report_store.log_balances(tag="tag") |
591 | mock.call("[Balance]"), | 601 | print_log.assert_has_calls([ |
592 | mock.call("\tbar"), | 602 | mock.call("[Balance]"), |
593 | mock.call("\tbaz"), | 603 | mock.call("\tbar"), |
594 | ]) | 604 | mock.call("\tbaz"), |
595 | add_log.assert_called_once_with({ | 605 | ]) |
596 | 'type': 'balance', | 606 | add_log.assert_called_once_with({ |
597 | 'balances': 'json', | 607 | 'type': 'balance', |
598 | 'tag': 'tag' | 608 | 'balances': 'json', |
599 | }) | 609 | 'tag': 'tag' |
600 | add_redis_status.assert_called_once_with({ | 610 | }) |
601 | 'type': 'balance', | 611 | add_redis_status.assert_called_once_with({ |
602 | 'balances': 'json', | 612 | 'type': 'balance', |
603 | 'tag': 'tag' | 613 | 'balances': 'json', |
604 | }) | 614 | 'tag': 'tag' |
615 | }) | ||
616 | add_log.reset_mock() | ||
617 | add_redis_status.reset_mock() | ||
618 | with self.subTest(tickers="present"): | ||
619 | amounts = { | ||
620 | "BTC": portfolio.Amount("BTC", 10), | ||
621 | "ETH": portfolio.Amount("BTC", D("0.3")) | ||
622 | } | ||
623 | amounts["ETH"].rate = D("0.1") | ||
624 | |||
625 | report_store.log_balances(tag="tag", tickers=amounts, | ||
626 | ticker_currency="BTC", compute_value="default", | ||
627 | type="total") | ||
628 | add_log.assert_called_once_with({ | ||
629 | 'type': 'balance', | ||
630 | 'balances': 'json', | ||
631 | 'tag': 'tag', | ||
632 | 'tickers': { | ||
633 | 'compute_value': 'default', | ||
634 | 'balance_type': 'total', | ||
635 | 'currency': 'BTC', | ||
636 | 'balances': { | ||
637 | 'BTC': D('10'), | ||
638 | 'ETH': D('0.3') | ||
639 | }, | ||
640 | 'rates': { | ||
641 | 'BTC': None, | ||
642 | 'ETH': D('0.1') | ||
643 | }, | ||
644 | 'total': D('10.3') | ||
645 | }, | ||
646 | }) | ||
647 | add_redis_status.assert_called_once_with({ | ||
648 | 'type': 'balance', | ||
649 | 'balances': 'json', | ||
650 | 'tag': 'tag', | ||
651 | 'tickers': { | ||
652 | 'compute_value': 'default', | ||
653 | 'balance_type': 'total', | ||
654 | 'currency': 'BTC', | ||
655 | 'balances': { | ||
656 | 'BTC': D('10'), | ||
657 | 'ETH': D('0.3') | ||
658 | }, | ||
659 | 'rates': { | ||
660 | 'BTC': None, | ||
661 | 'ETH': D('0.1') | ||
662 | }, | ||
663 | 'total': D('10.3') | ||
664 | }, | ||
665 | }) | ||
605 | 666 | ||
606 | @mock.patch.object(market.ReportStore, "print_log") | 667 | @mock.patch.object(market.ReportStore, "print_log") |
607 | @mock.patch.object(market.ReportStore, "add_log") | 668 | @mock.patch.object(market.ReportStore, "add_log") |
608 | @mock.patch.object(market.ReportStore, "add_redis_status") | 669 | def test_log_tickers(self, add_log, print_log): |
609 | def test_log_tickers(self, add_redis_status, add_log, print_log): | ||
610 | report_store = market.ReportStore(self.m) | 670 | report_store = market.ReportStore(self.m) |
611 | amounts = { | 671 | amounts = { |
612 | "BTC": portfolio.Amount("BTC", 10), | 672 | "BTC": portfolio.Amount("BTC", 10), |
@@ -631,21 +691,6 @@ class ReportStoreTest(WebMockTestCase): | |||
631 | }, | 691 | }, |
632 | 'total': D('10.3') | 692 | 'total': D('10.3') |
633 | }) | 693 | }) |
634 | add_redis_status.assert_called_once_with({ | ||
635 | 'type': 'tickers', | ||
636 | 'compute_value': 'default', | ||
637 | 'balance_type': 'total', | ||
638 | 'currency': 'BTC', | ||
639 | 'balances': { | ||
640 | 'BTC': D('10'), | ||
641 | 'ETH': D('0.3') | ||
642 | }, | ||
643 | 'rates': { | ||
644 | 'BTC': None, | ||
645 | 'ETH': D('0.1') | ||
646 | }, | ||
647 | 'total': D('10.3') | ||
648 | }) | ||
649 | 694 | ||
650 | add_log.reset_mock() | 695 | add_log.reset_mock() |
651 | compute_value = lambda x: x["bid"] | 696 | compute_value = lambda x: x["bid"] |