From dd78c62c3d60f28e139bbb78e89a96008828d552 Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Sat, 28 Oct 2017 08:44:49 +0300 Subject: [PATCH 1/3] added new command to return balance across all currencies --- freqtrade/exchange/__init__.py | 2 ++ freqtrade/exchange/bittrex.py | 6 ++++++ freqtrade/rpc/telegram.py | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 77a2d4b84..f255647b7 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -84,6 +84,8 @@ def get_balance(currency: str) -> float: return EXCHANGE.get_balance(currency) +def get_balances(): + return EXCHANGE.get_balances() def get_ticker(pair: str) -> dict: return EXCHANGE.get_ticker(pair) diff --git a/freqtrade/exchange/bittrex.py b/freqtrade/exchange/bittrex.py index cb85aaf87..0b70e7a3b 100644 --- a/freqtrade/exchange/bittrex.py +++ b/freqtrade/exchange/bittrex.py @@ -54,6 +54,12 @@ class Bittrex(Exchange): raise RuntimeError('{}: {}'.format(self.name.upper(), data['message'])) return float(data['result']['Balance'] or 0.0) + def get_balances(self): + data = _API.get_balances() + if not data['success']: + raise RuntimeError('{}: {}'.format(self.name.upper(), data['message'])) + return data['result'] + def get_ticker(self, pair: str) -> dict: data = _API.get_ticker(pair.replace('_', '-')) if not data['success']: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 84c86f816..9ea81c0b7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -41,6 +41,7 @@ def init(config: dict) -> None: handles = [ CommandHandler('status', _status), CommandHandler('profit', _profit), + CommandHandler('balance', _balance), CommandHandler('start', _start), CommandHandler('stop', _stop), CommandHandler('forcesell', _forcesell), @@ -201,6 +202,26 @@ def _profit(bot: Bot, update: Update) -> None: ) send_msg(markdown_msg, bot=bot) +@authorized_only +def _balance(bot: Bot, update: Update) -> None: + """ + Hander for /balance + Returns current account balance per crypto + """ + filter = {'Currency', 'CryptoAddress'} + output = "" + + balances = exchange.get_balances() + + for c in balances: + # output[c['Currency']] = {k: c[k] for k in c.keys() & {*set(c) - set(filter)}} + output += """*Currency*: {Currency} +*Available*: {Available} +*Balance*: {Balance} +*Pending*: {Pending} + +""".format(**c) + send_msg(output) @authorized_only def _start(bot: Bot, update: Update) -> None: From 4f6c3f94e09eaf9065973acf9992c2123f87c830 Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Sun, 29 Oct 2017 10:10:00 +0200 Subject: [PATCH 2/3] added tests to /balance, minor cleanup --- freqtrade/rpc/telegram.py | 8 ++++---- freqtrade/tests/test_telegram.py | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 9ea81c0b7..dcdefaee6 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -208,19 +208,18 @@ def _balance(bot: Bot, update: Update) -> None: Hander for /balance Returns current account balance per crypto """ - filter = {'Currency', 'CryptoAddress'} output = "" balances = exchange.get_balances() - for c in balances: - # output[c['Currency']] = {k: c[k] for k in c.keys() & {*set(c) - set(filter)}} + for currency in balances: output += """*Currency*: {Currency} *Available*: {Available} *Balance*: {Balance} *Pending*: {Pending} -""".format(**c) +""".format(**currency) + send_msg(output) @authorized_only @@ -347,6 +346,7 @@ def _help(bot: Bot, update: Update) -> None: */profit:* `Lists cumulative profit from all finished trades` */forcesell :* `Instantly sells the given trade, regardless of profit` */performance:* `Show performance of each finished trade grouped by pair` +*/balance:* `Show account balance per currency` */help:* `This help message` """ send_msg(message, bot=bot) diff --git a/freqtrade/tests/test_telegram.py b/freqtrade/tests/test_telegram.py index fb9a618a0..c6c5902c5 100644 --- a/freqtrade/tests/test_telegram.py +++ b/freqtrade/tests/test_telegram.py @@ -9,7 +9,7 @@ from telegram import Bot, Update, Message, Chat from freqtrade.main import init, create_trade from freqtrade.misc import update_state, State, get_state, CONF_SCHEMA from freqtrade.persistence import Trade -from freqtrade.rpc.telegram import _status, _profit, _forcesell, _performance, _start, _stop +from freqtrade.rpc.telegram import _status, _profit, _forcesell, _performance, _start, _stop, _balance @pytest.fixture @@ -197,3 +197,21 @@ def test_stop_handle(conf, update, mocker): assert get_state() == State.STOPPED assert msg_mock.call_count == 1 assert 'Stopping trader' in msg_mock.call_args_list[0][0][0] + +def test_balance_handle(conf, update, mocker): + mock_balance = [{ + 'Currency': 'BTC', + 'Balance': 10.0, + 'Available': 12.0, + 'Pending': 0.0, + 'CryptoAddress': 'XXXX'}] + mocker.patch.dict('freqtrade.main._CONF', conf) + msg_mock = MagicMock() + mocker.patch.multiple('freqtrade.main.telegram', _CONF=conf, init=MagicMock(), send_msg=msg_mock) + mocker.patch.multiple('freqtrade.main.exchange', + get_balances=MagicMock(return_value=mock_balance)) + + _balance(bot=MagicBot(), update=update) + assert msg_mock.call_count == 1 + assert '*Currency*: BTC' in msg_mock.call_args_list[0][0][0] + assert 'Balance' in msg_mock.call_args_list[0][0][0] From f4fe09ffbfe33bc92f5adff8684255dc0debc4b8 Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Sun, 29 Oct 2017 17:57:57 +0200 Subject: [PATCH 3/3] added get_balances as a abstract method to the interface baseclass --- freqtrade/exchange/interface.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/freqtrade/exchange/interface.py b/freqtrade/exchange/interface.py index 114ac9a6f..7c6f30be2 100644 --- a/freqtrade/exchange/interface.py +++ b/freqtrade/exchange/interface.py @@ -49,6 +49,21 @@ class Exchange(ABC): :return: float """ + @abstractmethod + def get_balances(self) -> List[dict]: + """ + Gets account balances across currencies + :return: List of dicts, format: [ + { + 'Currency': str, + 'Balance': float, + 'Available': float, + 'Pending': float, + } + ... + ] + """ + @abstractmethod def get_ticker(self, pair: str) -> dict: """