Repository: freqtrade/freqtrade

Issue:
Telegram: hide/compact the list of currencies with a low balance (below dust level)
Hi,

This is my first contribution!

When using the /balance command with the Telegram bot, having a lot of low-amount currencies will result in a insanely long list:

![Insade amount of dust currencies](https://user-images.githubusercontent.com/3023499/123959483-842cd680-d9ae-11eb-9980-6cfef537d836.png)

It happens quickly on Binance depending on your config, I don't know if it's the same for other exchanges.

Wouldn't it be simpler to regroup all these currencies in a line like this:
"72 Other currencies:
 Est. USDT: 133.967"

Or we could make an option to choose if we want to keep the list as it is for now, or if we want to compact this.

What do you think?

It looks like a minor modification, if you're interested by this one but it's not on the priority list I could learn how to contribute and make a PR.

Thank you!


Discussion:
to be honest, it'll only happen if you don't have BNB in your account (or have BNB fees disabled). 
Personal suggestion: convert all "dust" to BNB and use that to pay fees - it'll avoid this situation as well as allow you to pay lower fees.


I understand that this can however be a pain-point if you won't or can't use BNB for whatever reason - so for sure, if you feel for it, i'd be happy to receive a Pull Request which will improve this behaviour.

I remember a Binance account that was left with dust that were worth a few hundred dollars one or two years later. So I'm guessing it could be worth not converting dust coins, because one of them could shoot up...
Thank you for your advice anyway! I will look at it when I find time to do it.

Resolving patch:
diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py
--- a/freqtrade/rpc/telegram.py
+++ b/freqtrade/rpc/telegram.py
@@ -24,7 +24,7 @@
 from freqtrade.constants import DUST_PER_COIN
 from freqtrade.enums import RPCMessageType
 from freqtrade.exceptions import OperationalException
-from freqtrade.misc import chunks, round_coin_value
+from freqtrade.misc import chunks, plural, round_coin_value
 from freqtrade.rpc import RPC, RPCException, RPCHandler
 
 
@@ -598,6 +598,9 @@ def _balance(self, update: Update, context: CallbackContext) -> None:
                     "Starting capital: "
                     f"`{self._config['dry_run_wallet']}` {self._config['stake_currency']}.\n"
                 )
+            total_dust_balance = 0
+            total_dust_currencies = 0
+            curr_output = ''
             for curr in result['currencies']:
                 if curr['est_stake'] > balance_dust_level:
                     curr_output = (
@@ -607,9 +610,9 @@ def _balance(self, update: Update, context: CallbackContext) -> None:
                         f"\t`Pending: {curr['used']:.8f}`\n"
                         f"\t`Est. {curr['stake']}: "
                         f"{round_coin_value(curr['est_stake'], curr['stake'], False)}`\n")
-                else:
-                    curr_output = (f"*{curr['currency']}:* not showing <{balance_dust_level} "
-                                   f"{curr['stake']} amount \n")
+                elif curr['est_stake'] <= balance_dust_level:
+                    total_dust_balance += curr['est_stake']
+                    total_dust_currencies += 1
 
                 # Handle overflowing message length
                 if len(output + curr_output) >= MAX_TELEGRAM_MESSAGE_LENGTH:
@@ -618,6 +621,14 @@ def _balance(self, update: Update, context: CallbackContext) -> None:
                 else:
                     output += curr_output
 
+            if total_dust_balance > 0:
+                output += (
+                    f"*{total_dust_currencies} Other "
+                    f"{plural(total_dust_currencies, 'Currency', 'Currencies')} "
+                    f"(< {balance_dust_level} {result['stake']}):*\n"
+                    f"\t`Est. {result['stake']}: "
+                    f"{round_coin_value(total_dust_balance, result['stake'], False)}`\n")
+
             output += ("\n*Estimated Value*:\n"
                        f"\t`{result['stake']}: {result['total']: .8f}`\n"
                        f"\t`{result['symbol']}: "


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1761,7 +1761,7 @@ def rpc_balance():
             'total': 0.1,
             'free': 0.01,
             'used': 0.0
-            },
+        },
         'EUR': {
             'total': 10.0,
             'free': 10.0,
diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py
--- a/tests/rpc/test_rpc_telegram.py
+++ b/tests/rpc/test_rpc_telegram.py
@@ -519,12 +519,15 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick
     assert msg_mock.call_count == 1
     assert '*BTC:*' in result
     assert '*ETH:*' not in result
-    assert '*USDT:*' in result
-    assert '*EUR:*' in result
+    assert '*USDT:*' not in result
+    assert '*EUR:*' not in result
+    assert '*LTC:*' in result
+    assert '*XRP:*' not in result
     assert 'Balance:' in result
     assert 'Est. BTC:' in result
     assert 'BTC: 12.00000000' in result
-    assert '*XRP:* not showing <0.0001 BTC amount' in result
+    assert "*3 Other Currencies (< 0.0001 BTC):*" in result
+    assert 'BTC: 0.00000309' in result
 
 
 def test_balance_handle_empty_response(default_conf, update, mocker) -> None: