diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-05-05 14:41:30 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-05-05 14:41:30 +0200 |
commit | b4e5bbfbae6228879435b7cf1618a1e386d4ef1b (patch) | |
tree | 90cce895ea70aa3127fe764ac4da7e1d510b1589 | |
parent | 855a1f7036403c1fc10b9ede13b0dd18ec83929d (diff) | |
parent | bb127bc87c2b2880469bfab230415c85e589421a (diff) | |
download | Trader-b4e5bbfbae6228879435b7cf1618a1e386d4ef1b.tar.gz Trader-b4e5bbfbae6228879435b7cf1618a1e386d4ef1b.tar.zst Trader-b4e5bbfbae6228879435b7cf1618a1e386d4ef1b.zip |
Merge branch 'dev'v1.7
-rw-r--r-- | market.py | 54 | ||||
-rw-r--r-- | store.py | 10 | ||||
-rw-r--r-- | tests/test_market.py | 32 | ||||
-rw-r--r-- | tests/test_store.py | 10 |
4 files changed, 77 insertions, 29 deletions
@@ -254,8 +254,7 @@ class Processor: | |||
254 | { | 254 | { |
255 | "name": "print_balances", | 255 | "name": "print_balances", |
256 | "number": 1, | 256 | "number": 1, |
257 | "fetch_balances": ["begin"], | 257 | "fetch_balances_begin": { "log_tickers": True, "add_portfolio": True }, |
258 | "fetch_balances_args": { "add_portfolio": True }, | ||
259 | "print_tickers": { "base_currency": "BTC" }, | 258 | "print_tickers": { "base_currency": "BTC" }, |
260 | } | 259 | } |
261 | ], | 260 | ], |
@@ -272,25 +271,37 @@ class Processor: | |||
272 | "number": 2, | 271 | "number": 2, |
273 | "before": False, | 272 | "before": False, |
274 | "after": True, | 273 | "after": True, |
275 | "fetch_balances": ["begin"], | 274 | "fetch_balances_begin": {}, |
276 | "prepare_trades": { "compute_value": "average" }, | 275 | "prepare_trades": { "compute_value": "average" }, |
277 | "prepare_orders": { "compute_value": "average" }, | 276 | "prepare_orders": { "compute_value": "average" }, |
278 | }, | 277 | }, |
279 | ], | 278 | ], |
280 | "sell_needed": [ | 279 | "sell_needed": [ |
281 | { | 280 | { |
282 | "name": "wait", | 281 | "name": "print_balances", |
283 | "number": 0, | 282 | "number": 0, |
283 | "before": True, | ||
284 | "after": False, | ||
285 | "fetch_balances_begin": { | ||
286 | "checkpoint": "end", | ||
287 | "log_tickers": True, | ||
288 | "add_portfolio": True | ||
289 | }, | ||
290 | }, | ||
291 | { | ||
292 | "name": "wait", | ||
293 | "number": 1, | ||
284 | "before": False, | 294 | "before": False, |
285 | "after": True, | 295 | "after": True, |
286 | "wait_for_recent": {}, | 296 | "wait_for_recent": {}, |
287 | }, | 297 | }, |
288 | { | 298 | { |
289 | "name": "sell", | 299 | "name": "sell", |
290 | "number": 1, | 300 | "number": 2, |
291 | "before": False, | 301 | "before": False, |
292 | "after": True, | 302 | "after": True, |
293 | "fetch_balances": ["begin", "end"], | 303 | "fetch_balances_begin": {}, |
304 | "fetch_balances_end": {}, | ||
294 | "prepare_trades": {}, | 305 | "prepare_trades": {}, |
295 | "prepare_orders": { "only": "dispose", "compute_value": "average" }, | 306 | "prepare_orders": { "only": "dispose", "compute_value": "average" }, |
296 | "run_orders": {}, | 307 | "run_orders": {}, |
@@ -299,10 +310,14 @@ class Processor: | |||
299 | }, | 310 | }, |
300 | { | 311 | { |
301 | "name": "buy", | 312 | "name": "buy", |
302 | "number": 2, | 313 | "number": 3, |
303 | "before": False, | 314 | "before": False, |
304 | "after": True, | 315 | "after": True, |
305 | "fetch_balances": ["begin", "end"], | 316 | "fetch_balances_begin": {}, |
317 | "fetch_balances_end": { | ||
318 | "checkpoint": "begin", | ||
319 | "log_tickers": True | ||
320 | }, | ||
306 | "prepare_trades": { "only": "acquire", "available_balance_only": True }, | 321 | "prepare_trades": { "only": "acquire", "available_balance_only": True }, |
307 | "prepare_orders": { "only": "acquire", "compute_value": "average" }, | 322 | "prepare_orders": { "only": "acquire", "compute_value": "average" }, |
308 | "move_balances": {}, | 323 | "move_balances": {}, |
@@ -317,7 +332,12 @@ class Processor: | |||
317 | "number": 1, | 332 | "number": 1, |
318 | "before": True, | 333 | "before": True, |
319 | "after": False, | 334 | "after": False, |
320 | "fetch_balances": ["begin", "end"], | 335 | "fetch_balances_begin": { |
336 | "checkpoint": "end", | ||
337 | "log_tickers": True, | ||
338 | "add_portfolio": True | ||
339 | }, | ||
340 | "fetch_balances_end": {}, | ||
321 | "prepare_trades": { "repartition": { "base_currency": (1, "long") } }, | 341 | "prepare_trades": { "repartition": { "base_currency": (1, "long") } }, |
322 | "prepare_orders": { "compute_value": "average" }, | 342 | "prepare_orders": { "compute_value": "average" }, |
323 | "run_orders": {}, | 343 | "run_orders": {}, |
@@ -336,7 +356,11 @@ class Processor: | |||
336 | "number": 3, | 356 | "number": 3, |
337 | "before": False, | 357 | "before": False, |
338 | "after": True, | 358 | "after": True, |
339 | "fetch_balances": ["begin", "end"], | 359 | "fetch_balances_begin": {}, |
360 | "fetch_balances_end": { | ||
361 | "checkpoint": "begin", | ||
362 | "log_tickers": True | ||
363 | }, | ||
340 | "prepare_trades": { "available_balance_only": True }, | 364 | "prepare_trades": { "available_balance_only": True }, |
341 | "prepare_orders": { "compute_value": "average" }, | 365 | "prepare_orders": { "compute_value": "average" }, |
342 | "move_balances": {}, | 366 | "move_balances": {}, |
@@ -388,18 +412,18 @@ class Processor: | |||
388 | process_name = "process_{}__{}_{}".format(scenario_name, step["number"], step["name"]) | 412 | process_name = "process_{}__{}_{}".format(scenario_name, step["number"], step["name"]) |
389 | self.market.report.log_stage("{}_begin".format(process_name)) | 413 | self.market.report.log_stage("{}_begin".format(process_name)) |
390 | 414 | ||
391 | fetch_args = step.get("fetch_balances_args", {}) | 415 | if "fetch_balances_begin" in step: |
392 | if "begin" in step.get("fetch_balances", []): | ||
393 | self.market.balances.fetch_balances(tag="{}_begin".format(process_name), | 416 | self.market.balances.fetch_balances(tag="{}_begin".format(process_name), |
394 | log_tickers=True, **fetch_args) | 417 | **step["fetch_balances_begin"]) |
395 | 418 | ||
396 | for action in self.ordered_actions: | 419 | for action in self.ordered_actions: |
397 | if action in step: | 420 | if action in step: |
398 | self.run_action(action, step[action], kwargs) | 421 | self.run_action(action, step[action], kwargs) |
399 | 422 | ||
400 | if "end" in step.get("fetch_balances", []): | 423 | if "fetch_balances_end" in step: |
401 | self.market.balances.fetch_balances(tag="{}_end".format(process_name), | 424 | self.market.balances.fetch_balances(tag="{}_end".format(process_name), |
402 | log_tickers=True, **fetch_args) | 425 | **step["fetch_balances_end"]) |
426 | |||
403 | self.market.report.log_stage("{}_end".format(process_name)) | 427 | self.market.report.log_stage("{}_end".format(process_name)) |
404 | 428 | ||
405 | def method_arguments(self, action): | 429 | def method_arguments(self, action): |
@@ -99,7 +99,7 @@ class ReportStore: | |||
99 | "args": args, | 99 | "args": args, |
100 | }) | 100 | }) |
101 | 101 | ||
102 | def log_balances(self, tag=None, tickers=None, | 102 | def log_balances(self, tag=None, checkpoint=None, tickers=None, |
103 | ticker_currency=None, compute_value=None, type=None): | 103 | ticker_currency=None, compute_value=None, type=None): |
104 | self.print_log("[Balance]") | 104 | self.print_log("[Balance]") |
105 | for currency, balance in self.market.balances.all.items(): | 105 | for currency, balance in self.market.balances.all.items(): |
@@ -108,6 +108,7 @@ class ReportStore: | |||
108 | log = { | 108 | log = { |
109 | "type": "balance", | 109 | "type": "balance", |
110 | "tag": tag, | 110 | "tag": tag, |
111 | "checkpoint": checkpoint, | ||
111 | "balances": self.market.balances.as_json() | 112 | "balances": self.market.balances.as_json() |
112 | } | 113 | } |
113 | 114 | ||
@@ -303,7 +304,8 @@ class BalanceStore: | |||
303 | compute_value, type) | 304 | compute_value, type) |
304 | return amounts | 305 | return amounts |
305 | 306 | ||
306 | def fetch_balances(self, tag=None, add_portfolio=False, log_tickers=False, | 307 | def fetch_balances(self, tag=None, add_portfolio=False, |
308 | checkpoint=None, log_tickers=False, | ||
307 | ticker_currency="BTC", ticker_compute_value="average", ticker_type="total"): | 309 | ticker_currency="BTC", ticker_compute_value="average", ticker_type="total"): |
308 | all_balances = self.market.ccxt.fetch_all_balances() | 310 | all_balances = self.market.ccxt.fetch_all_balances() |
309 | for currency, balance in all_balances.items(): | 311 | for currency, balance in all_balances.items(): |
@@ -315,11 +317,11 @@ class BalanceStore: | |||
315 | self.all.setdefault(currency, portfolio.Balance(currency, {})) | 317 | self.all.setdefault(currency, portfolio.Balance(currency, {})) |
316 | if log_tickers: | 318 | if log_tickers: |
317 | tickers = self.in_currency(ticker_currency, compute_value=ticker_compute_value, type=ticker_type) | 319 | tickers = self.in_currency(ticker_currency, compute_value=ticker_compute_value, type=ticker_type) |
318 | self.market.report.log_balances(tag=tag, | 320 | self.market.report.log_balances(tag=tag, checkpoint=checkpoint, |
319 | tickers=tickers, ticker_currency=ticker_currency, | 321 | tickers=tickers, ticker_currency=ticker_currency, |
320 | compute_value=ticker_compute_value, type=ticker_type) | 322 | compute_value=ticker_compute_value, type=ticker_type) |
321 | else: | 323 | else: |
322 | self.market.report.log_balances(tag=tag) | 324 | self.market.report.log_balances(tag=tag, checkpoint=checkpoint) |
323 | 325 | ||
324 | def dispatch_assets(self, amount, liquidity="medium", repartition=None): | 326 | def dispatch_assets(self, amount, liquidity="medium", repartition=None): |
325 | if repartition is None: | 327 | if repartition is None: |
diff --git a/tests/test_market.py b/tests/test_market.py index 46fad53..37c009b 100644 --- a/tests/test_market.py +++ b/tests/test_market.py | |||
@@ -174,7 +174,7 @@ class MarketTest(WebMockTestCase): | |||
174 | base_currency='BTC', compute_value='average', | 174 | base_currency='BTC', compute_value='average', |
175 | available_balance_only=False, liquidity='medium', | 175 | available_balance_only=False, liquidity='medium', |
176 | only=None, repartition=None) | 176 | only=None, repartition=None) |
177 | m.report.log_balances.assert_called_once_with(tag="tag") | 177 | m.report.log_balances.assert_called_once_with(tag="tag", checkpoint=None) |
178 | 178 | ||
179 | compute_trades.reset_mock() | 179 | compute_trades.reset_mock() |
180 | with self.subTest(available_balance_only=True),\ | 180 | with self.subTest(available_balance_only=True),\ |
@@ -964,7 +964,7 @@ class ProcessorTest(WebMockTestCase): | |||
964 | process_step.reset_mock() | 964 | process_step.reset_mock() |
965 | 965 | ||
966 | processor.process("sell_needed", steps=["before", "after"]) | 966 | processor.process("sell_needed", steps=["before", "after"]) |
967 | self.assertEqual(3, process_step.call_count) | 967 | self.assertEqual(4, process_step.call_count) |
968 | 968 | ||
969 | def test_method_arguments(self): | 969 | def test_method_arguments(self): |
970 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) | 970 | ccxt = mock.Mock(spec=market.ccxt.poloniexE) |
@@ -1002,17 +1002,17 @@ class ProcessorTest(WebMockTestCase): | |||
1002 | processor = market.Processor(self.m) | 1002 | processor = market.Processor(self.m) |
1003 | 1003 | ||
1004 | with mock.patch.object(processor, "run_action") as run_action: | 1004 | with mock.patch.object(processor, "run_action") as run_action: |
1005 | step = processor.scenarios["sell_needed"][1] | 1005 | step = processor.scenarios["sell_needed"][2] |
1006 | 1006 | ||
1007 | processor.process_step("foo", step, {"foo":"bar"}) | 1007 | processor.process_step("foo", step, {"foo":"bar"}) |
1008 | 1008 | ||
1009 | self.m.report.log_stage.assert_has_calls([ | 1009 | self.m.report.log_stage.assert_has_calls([ |
1010 | mock.call("process_foo__1_sell_begin"), | 1010 | mock.call("process_foo__2_sell_begin"), |
1011 | mock.call("process_foo__1_sell_end"), | 1011 | mock.call("process_foo__2_sell_end"), |
1012 | ]) | 1012 | ]) |
1013 | self.m.balances.fetch_balances.assert_has_calls([ | 1013 | self.m.balances.fetch_balances.assert_has_calls([ |
1014 | mock.call(tag="process_foo__1_sell_begin", log_tickers=True), | 1014 | mock.call(tag="process_foo__2_sell_begin"), |
1015 | mock.call(tag="process_foo__1_sell_end", log_tickers=True), | 1015 | mock.call(tag="process_foo__2_sell_end"), |
1016 | ]) | 1016 | ]) |
1017 | 1017 | ||
1018 | self.assertEqual(5, run_action.call_count) | 1018 | self.assertEqual(5, run_action.call_count) |
@@ -1030,6 +1030,24 @@ class ProcessorTest(WebMockTestCase): | |||
1030 | step = processor.scenarios["sell_needed"][0] | 1030 | step = processor.scenarios["sell_needed"][0] |
1031 | 1031 | ||
1032 | processor.process_step("foo", step, {"foo":"bar"}) | 1032 | processor.process_step("foo", step, {"foo":"bar"}) |
1033 | |||
1034 | self.m.report.log_stage.assert_has_calls([ | ||
1035 | mock.call("process_foo__0_print_balances_begin"), | ||
1036 | mock.call("process_foo__0_print_balances_end"), | ||
1037 | ]) | ||
1038 | self.m.balances.fetch_balances.assert_has_calls([ | ||
1039 | mock.call(add_portfolio=True, checkpoint='end', | ||
1040 | log_tickers=True, | ||
1041 | tag='process_foo__0_print_balances_begin') | ||
1042 | ]) | ||
1043 | |||
1044 | self.assertEqual(0, run_action.call_count) | ||
1045 | |||
1046 | self.m.reset_mock() | ||
1047 | with mock.patch.object(processor, "run_action") as run_action: | ||
1048 | step = processor.scenarios["sell_needed"][1] | ||
1049 | |||
1050 | processor.process_step("foo", step, {"foo":"bar"}) | ||
1033 | self.m.balances.fetch_balances.assert_not_called() | 1051 | self.m.balances.fetch_balances.assert_not_called() |
1034 | 1052 | ||
1035 | self.m.reset_mock() | 1053 | self.m.reset_mock() |
diff --git a/tests/test_store.py b/tests/test_store.py index ee7e063..58e76e0 100644 --- a/tests/test_store.py +++ b/tests/test_store.py | |||
@@ -380,7 +380,7 @@ class BalanceStoreTest(WebMockTestCase): | |||
380 | balance_store.fetch_balances(tag="foo") | 380 | balance_store.fetch_balances(tag="foo") |
381 | self.assertEqual(0, balance_store.all["ETC"].total) | 381 | self.assertEqual(0, balance_store.all["ETC"].total) |
382 | self.assertListEqual(["USDT", "XVG", "XMR", "ETC"], list(balance_store.currencies())) | 382 | self.assertListEqual(["USDT", "XVG", "XMR", "ETC"], list(balance_store.currencies())) |
383 | self.m.report.log_balances.assert_called_with(tag="foo") | 383 | self.m.report.log_balances.assert_called_with(tag="foo", checkpoint=None) |
384 | 384 | ||
385 | with self.subTest(log_tickers=True),\ | 385 | with self.subTest(log_tickers=True),\ |
386 | mock.patch.object(balance_store, "in_currency") as in_currency: | 386 | mock.patch.object(balance_store, "in_currency") as in_currency: |
@@ -388,7 +388,7 @@ class BalanceStoreTest(WebMockTestCase): | |||
388 | balance_store.fetch_balances(log_tickers=True, ticker_currency="FOO", | 388 | balance_store.fetch_balances(log_tickers=True, ticker_currency="FOO", |
389 | ticker_compute_value="compute", ticker_type="type") | 389 | ticker_compute_value="compute", ticker_type="type") |
390 | self.m.report.log_balances.assert_called_with(compute_value='compute', | 390 | self.m.report.log_balances.assert_called_with(compute_value='compute', |
391 | tag=None, ticker_currency='FOO', tickers='tickers', | 391 | tag=None, checkpoint=None, ticker_currency='FOO', tickers='tickers', |
392 | type='type') | 392 | type='type') |
393 | 393 | ||
394 | balance_store = market.BalanceStore(self.m) | 394 | balance_store = market.BalanceStore(self.m) |
@@ -425,7 +425,7 @@ class BalanceStoreTest(WebMockTestCase): | |||
425 | self.assertEqual(D("2.6"), amounts["BTC"].value) | 425 | self.assertEqual(D("2.6"), amounts["BTC"].value) |
426 | self.assertEqual(D("7.5"), amounts["XEM"].value) | 426 | self.assertEqual(D("7.5"), amounts["XEM"].value) |
427 | self.assertEqual(D("-1.0"), amounts["DASH"].value) | 427 | self.assertEqual(D("-1.0"), amounts["DASH"].value) |
428 | self.m.report.log_balances.assert_called_with(tag=None) | 428 | self.m.report.log_balances.assert_called_with(tag=None, checkpoint=None) |
429 | self.m.report.log_dispatch.assert_called_once_with(portfolio.Amount("BTC", | 429 | self.m.report.log_dispatch.assert_called_once_with(portfolio.Amount("BTC", |
430 | "11.1"), amounts, "medium", repartition_hash) | 430 | "11.1"), amounts, "medium", repartition_hash) |
431 | 431 | ||
@@ -617,12 +617,14 @@ class ReportStoreTest(WebMockTestCase): | |||
617 | ]) | 617 | ]) |
618 | add_log.assert_called_once_with({ | 618 | add_log.assert_called_once_with({ |
619 | 'type': 'balance', | 619 | 'type': 'balance', |
620 | 'checkpoint': None, | ||
620 | 'balances': 'json', | 621 | 'balances': 'json', |
621 | 'tag': 'tag' | 622 | 'tag': 'tag' |
622 | }) | 623 | }) |
623 | add_redis_status.assert_called_once_with({ | 624 | add_redis_status.assert_called_once_with({ |
624 | 'type': 'balance', | 625 | 'type': 'balance', |
625 | 'balances': 'json', | 626 | 'balances': 'json', |
627 | 'checkpoint': None, | ||
626 | 'tag': 'tag' | 628 | 'tag': 'tag' |
627 | }) | 629 | }) |
628 | add_log.reset_mock() | 630 | add_log.reset_mock() |
@@ -639,6 +641,7 @@ class ReportStoreTest(WebMockTestCase): | |||
639 | type="total") | 641 | type="total") |
640 | add_log.assert_called_once_with({ | 642 | add_log.assert_called_once_with({ |
641 | 'type': 'balance', | 643 | 'type': 'balance', |
644 | 'checkpoint': None, | ||
642 | 'balances': 'json', | 645 | 'balances': 'json', |
643 | 'tag': 'tag', | 646 | 'tag': 'tag', |
644 | 'tickers': { | 647 | 'tickers': { |
@@ -658,6 +661,7 @@ class ReportStoreTest(WebMockTestCase): | |||
658 | }) | 661 | }) |
659 | add_redis_status.assert_called_once_with({ | 662 | add_redis_status.assert_called_once_with({ |
660 | 'type': 'balance', | 663 | 'type': 'balance', |
664 | 'checkpoint': None, | ||
661 | 'balances': 'json', | 665 | 'balances': 'json', |
662 | 'tag': 'tag', | 666 | 'tag': 'tag', |
663 | 'tickers': { | 667 | 'tickers': { |