Repository: freqtrade/freqtrade

Issue:
sync / resync Wallet (refresh)
Hello !
I am missing a feature like sync/resync wallet.

I've done a deposit to binance. It wasn't recognised by freqtrade.
Start/stop hasn't worked for this.
Changing the deposit from ETH to BTC and stop/start hasn't worked either.

Only shutdown an start new has taken the new amount into calculation.



Discussion:
Updating wallets is done every time the bot takes action (opens / closes a trade).

Doing this more often (like every iteration) would probably result in bans from the exchange, since the balance call is rather expensive (from an api limiting perspective).

This is also not exposed intentionally towards the user - so you cannot accidentally block your bot from the exchange (which can lead to losses due to sell-orders not being placed) by pressing that button too often, therefore i'm not sure if this SHOULD be exposed to the user at all.

`/reload_conf` would have worked for your case - since that will recreate the whole bot class.
However i think it's a rather limited case (waiting for the next buy / sell would be sufficient), since the balance is irrelevant to bot operations as long as it's not buying / selling.

I'll however also make sure that we're updating the balance before buying - as i'm not sure without checking.


There are two reasons that the balance can change.
First, like above, I've put some extra cash to the exchange to reach the minimum buy amount.
Second, Binance allows staking, there could be a (daily) reward which changes the amount of a coin.

In both cases I want to see the changed amount.

So there are two possibilities, first, let only freqtrade calculate and work with the known balance or second update the balances and use that amount.

Maybe you can add this feature to /balance (Telegram) with a time stop. The balances will be downloaded once a minute, hitting more often will result in nothing, maybe an info in the programm output. 
The first part (making sure balance is updated before buying) has been implemented in #2734. 

I'll have a look at a refresh balance when `/balance` is called every hour or so (more often won't make sense - `/balance` is not made to replace checking balances on the exchange.

Resolving patch:
diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py
--- a/freqtrade/rpc/rpc.py
+++ b/freqtrade/rpc/rpc.py
@@ -306,6 +306,8 @@ def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> Dict:
         except (TemporaryError, DependencyException):
             raise RPCException('Error getting current tickers.')
 
+        self._freqtrade.wallets.update(require_update=False)
+
         for coin, balance in self._freqtrade.wallets.get_all_balances().items():
             if not balance.total:
                 continue
diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py
--- a/freqtrade/wallets.py
+++ b/freqtrade/wallets.py
@@ -2,7 +2,10 @@
 """ Wallet """
 
 import logging
-from typing import Dict, NamedTuple, Any
+from typing import Any, Dict, NamedTuple
+
+import arrow
+
 from freqtrade.exchange import Exchange
 from freqtrade.persistence import Trade
 
@@ -24,7 +27,7 @@ def __init__(self, config: dict, exchange: Exchange) -> None:
         self._exchange = exchange
         self._wallets: Dict[str, Wallet] = {}
         self.start_cap = config['dry_run_wallet']
-
+        self._last_wallet_refresh = 0
         self.update()
 
     def get_free(self, currency) -> float:
@@ -95,12 +98,21 @@ def _update_live(self) -> None:
                 balances[currency].get('total', None)
             )
 
-    def update(self) -> None:
-        if self._config['dry_run']:
-            self._update_dry()
-        else:
-            self._update_live()
-        logger.info('Wallets synced.')
+    def update(self, require_update: bool = True) -> None:
+        """
+        Updates wallets from the configured version.
+        By default, updates from the exchange.
+        Update-skipping should only be used for user-invoked /balance calls, since
+        for trading operations, the latest balance is needed.
+        :param require_update: Allow skipping an update if balances were recently refreshed
+        """
+        if (require_update or (self._last_wallet_refresh + 3600 < arrow.utcnow().timestamp)):
+            if self._config['dry_run']:
+                self._update_dry()
+            else:
+                self._update_live()
+            logger.info('Wallets synced.')
+            self._last_wallet_refresh = arrow.utcnow().timestamp
 
     def get_all_balances(self) -> Dict[str, Any]:
         return self._wallets


Test patch:
diff --git a/tests/test_wallets.py b/tests/test_wallets.py
--- a/tests/test_wallets.py
+++ b/tests/test_wallets.py
@@ -32,7 +32,7 @@ def test_sync_wallet_at_boot(mocker, default_conf):
     assert freqtrade.wallets._wallets['GAS'].used == 0.0
     assert freqtrade.wallets._wallets['GAS'].total == 0.260739
     assert freqtrade.wallets.get_free('BNT') == 1.0
-
+    assert freqtrade.wallets._last_wallet_refresh > 0
     mocker.patch.multiple(
         'freqtrade.exchange.Exchange',
         get_balances=MagicMock(return_value={
@@ -61,6 +61,11 @@ def test_sync_wallet_at_boot(mocker, default_conf):
     assert freqtrade.wallets.get_free('GAS') == 0.270739
     assert freqtrade.wallets.get_used('GAS') == 0.1
     assert freqtrade.wallets.get_total('GAS') == 0.260439
+    update_mock = mocker.patch('freqtrade.wallets.Wallets._update_live')
+    freqtrade.wallets.update(False)
+    assert update_mock.call_count == 0
+    freqtrade.wallets.update()
+    assert update_mock.call_count == 1
 
 
 def test_sync_wallet_missing_data(mocker, default_conf):