Repository: freqtrade/freqtrade

Issue:
Telegram message limit
  * Python Version: 3.6.5
  * CCXT version: 1.18.435
  * Branch: Develop
  * Last Commit ID: 4a6c8f3cb27d33c24d4baefa33ebc177c5e742e4
  
Don't get any output for telegram  /balance command 
in console get 
WARNING - Telegram NetworkError: Message is too long! Trying one more time.
WARNING - TelegramError: Message is too long! Giving up on that message.




Discussion:
The limit for Telegram messages is, if I remember it properly, 4096 symbols. This can be reached in case of less than 40 currencies in the user account on exchange with balance large enough to be printed in the message (small balances are ignored in the output).

Maybe the bot should send a separate message for each currency. Or other kind of pagination of the balance data should be implemented.
I think if we know the limit (i did not), we can simply split it when we reach the limit - so we would send 2 messages, not 50 (in case of 50 currencies...)

I'll try to have a look 
https://core.telegram.org/method/messages.sendMessage
(may require VPN to access in some countries)
states: "Current maximum length is 4096 UTF8 characters"


Resolving patch:
diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py
--- a/freqtrade/rpc/telegram.py
+++ b/freqtrade/rpc/telegram.py
@@ -20,6 +20,9 @@
 logger.debug('Included module rpc.telegram ...')
 
 
+MAX_TELEGRAM_MESSAGE_LENGTH = 4096
+
+
 def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]:
     """
     Decorator to check if the message comes from the correct chat_id
@@ -327,13 +330,20 @@ def _balance(self, bot: Bot, update: Update) -> None:
             output = ''
             for currency in result['currencies']:
                 if currency['est_btc'] > 0.0001:
-                    output += "*{currency}:*\n" \
+                    curr_output = "*{currency}:*\n" \
                             "\t`Available: {available: .8f}`\n" \
                             "\t`Balance: {balance: .8f}`\n" \
                             "\t`Pending: {pending: .8f}`\n" \
                             "\t`Est. BTC: {est_btc: .8f}`\n".format(**currency)
                 else:
-                    output += "*{currency}:* not showing <1$ amount \n".format(**currency)
+                    curr_output = "*{currency}:* not showing <1$ amount \n".format(**currency)
+
+                # Handle overflowing messsage length
+                if len(output + curr_output) >= MAX_TELEGRAM_MESSAGE_LENGTH:
+                    self._send_msg(output, bot=bot)
+                    output = curr_output
+                else:
+                    output += curr_output
 
             output += "\n*Estimated Value*:\n" \
                       "\t`BTC: {total: .8f}`\n" \


Test patch:
diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py
--- a/freqtrade/tests/rpc/test_rpc_telegram.py
+++ b/freqtrade/tests/rpc/test_rpc_telegram.py
@@ -4,7 +4,8 @@
 
 import re
 from datetime import datetime
-from random import randint
+from random import choice, randint
+from string import ascii_uppercase
 from unittest.mock import MagicMock, PropertyMock
 
 import arrow
@@ -20,7 +21,8 @@
 from freqtrade.rpc.telegram import Telegram, authorized_only
 from freqtrade.state import State
 from freqtrade.strategy.interface import SellType
-from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has, patch_exchange)
+from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has,
+                                      patch_exchange)
 from freqtrade.tests.test_freqtradebot import patch_get_signal
 
 
@@ -587,6 +589,45 @@ def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
     assert 'all balances are zero' in result
 
 
+def test_balance_handle_too_large_response(default_conf, update, mocker) -> None:
+    balances = []
+    for i in range(100):
+        curr = choice(ascii_uppercase) + choice(ascii_uppercase) + choice(ascii_uppercase)
+        balances.append({
+            'currency': curr,
+            'available': 1.0,
+            'pending': 0.5,
+            'balance': i,
+            'est_btc': 1
+        })
+    mocker.patch('freqtrade.rpc.rpc.RPC._rpc_balance', return_value={
+        'currencies': balances,
+        'total': 100.0,
+        'symbol': 100.0,
+        'value': 1000.0,
+    })
+
+    msg_mock = MagicMock()
+    mocker.patch.multiple(
+        'freqtrade.rpc.telegram.Telegram',
+        _init=MagicMock(),
+        _send_msg=msg_mock
+    )
+
+    freqtradebot = get_patched_freqtradebot(mocker, default_conf)
+    patch_get_signal(freqtradebot, (True, False))
+
+    telegram = Telegram(freqtradebot)
+
+    telegram._balance(bot=MagicMock(), update=update)
+    assert msg_mock.call_count > 1
+    # Test if wrap happens around 4000 -
+    # and each single currency-output is around 120 characters long so we need
+    # an offset to avoid random test failures
+    assert len(msg_mock.call_args_list[0][0][0]) < 4096
+    assert len(msg_mock.call_args_list[0][0][0]) > (4096 - 120)
+
+
 def test_start_handle(default_conf, update, mocker) -> None:
     msg_mock = MagicMock()
     mocker.patch.multiple(