Repository: freqtrade/freqtrade

Issue:
Simulated balance in dry mode not being calculated correctly
## Describe your environment
  * Operating system: ____Ubuntu 20-04
  * Python Version: _____ 3.8.10
  * CCXT version: _____ 3.1.13
  * Freqtrade Version: ____ 2023.6.dev-8f02050fd (native)
  
## Describe the problem:
The simulated balance shown during a trade that has partial sells does not appear to be calculated correctly. It should match the projected profit in the frequi dashboard profit chart (both represent the amout of USDT you'd have if you were to sell up immediately, they should match). 

In the example below the simulated USDT amount is $1626.28, I started with $2500 and the profit in the chart shows it started that trade $154.629 up, i.e. $2654.629. The `stake_amount` is $1028.349, the difference is `2654.629 - 1028.349 = 1626.28`.  However, `stake_amount` is that which is used for calculatng the average price, it's not the difference between how much was used to buy, and how much was returned from sells, which is what the simulated balance should be showing. 

Just to confirm with reference to the diagrams below, `stake_amount` is $1028.349, the `amount` is 2239.5564, the `open_rate` (which is the average price and doesn't change with sells) is 0.45918. `1028.349 / 2239.5564 =  0.45918`.

I think the dry balance currently reported in dry mode when there are partial sells would not match what a live balance would show for the same trade.

![simulated_balance](https://github.com/freqtrade/freqtrade/assets/28675875/209ad3dc-61f6-4f58-9cbb-3f50a23bf0de)
![projected_profit](https://github.com/freqtrade/freqtrade/assets/28675875/273fc0a0-5ba9-4dde-91df-ba943c07d816)

Simulated balance in dry mode not being calculated correctly
## Describe your environment
  * Operating system: ____Ubuntu 20-04
  * Python Version: _____ 3.8.10
  * CCXT version: _____ 3.1.13
  * Freqtrade Version: ____ 2023.6.dev-8f02050fd (native)
  
## Describe the problem:
The simulated balance shown during a trade that has partial sells does not appear to be calculated correctly. It should match the projected profit in the frequi dashboard profit chart (both represent the amout of USDT you'd have if you were to sell up immediately, they should match). 

In the example below the simulated USDT amount is $1626.28, I started with $2500 and the profit in the chart shows it started that trade $154.629 up, i.e. $2654.629. The `stake_amount` is $1028.349, the difference is `2654.629 - 1028.349 = 1626.28`.  However, `stake_amount` is that which is used for calculatng the average price, it's not the difference between how much was used to buy, and how much was returned from sells, which is what the simulated balance should be showing. 

Just to confirm with reference to the diagrams below, `stake_amount` is $1028.349, the `amount` is 2239.5564, the `open_rate` (which is the average price and doesn't change with sells) is 0.45918. `1028.349 / 2239.5564 =  0.45918`.

I think the dry balance currently reported in dry mode when there are partial sells would not match what a live balance would show for the same trade.

![simulated_balance](https://github.com/freqtrade/freqtrade/assets/28675875/209ad3dc-61f6-4f58-9cbb-3f50a23bf0de)
![projected_profit](https://github.com/freqtrade/freqtrade/assets/28675875/273fc0a0-5ba9-4dde-91df-ba943c07d816)



Discussion:
To be frank, this will need a bit more than a description and a screenshot to have it being looked at.

You can't assume that the bot started "x" up from a chart. Treat it as what it is - a chart. Once you accound for parallelism etc., You cant take any assumption about the prior state from this plot, sorry.


As is, it's non actionable without significant time invest to even try and get to a similar state (which isn't described how, either).

I'm happy to look at it if i can either get that database file (so i can look at the actual data), or even better, if you're able to compile a simple unittest thats showing what you think is wrong.

Maybe (most likely) also the output of 
`freqtrade show-trades --db-url sqlite:///<trades.sqlite> --print-json --trade-id <tradeid>` for the open will suffice, but i can't say for sure.
OK, I'll get the trade information for you. But I know the balance reverts to the projected value on closing the trade, I reported that on Discord so I'm confident it started with that balance, and the figures match exactly which is a pretty strong clue that it did (this is not the first time this has happened BTW):
https://discord.com/channels/700048804539400213/779658156467814421/1124081752504291338

Here's the trade log:
[trade_18_json.txt](https://github.com/freqtrade/freqtrade/files/11996092/trade_18_json.txt)

To be honest for this you don't really need recreate the state, a simple examination of the code to see whether `stake_amount` is being subtracted from the last simulated balance should suffice because if it is there's a logical problem, it should be the last simulated balance minus the sum of the stakes used for buys plus the sum of the stakes returned from sells.
I think the problem is in `_update_dry(self)`, specifically the bit that sums up the total amount in trades:
`tot_in_trades = sum(trade.stake_amount for trade in open_trades)`
I forgot to add the actual database as you requested, sorry.
[PerkGrid_test14_dry.zip](https://github.com/freqtrade/freqtrade/files/12013779/PerkGrid_test14_dry.zip)

I have hacked my version of `_update_dry(self)` in `wallets.py` to do this. It's a hack, nowhere near freqtrade standards, but it does seem to make the simulated balance much closer to the projected profit. Not quite the same (possibly due to fees need to be applied when selling up, the balance just shows how much the remaining base is worth without those fees).

As it stands at the moment the simulated balance for USDT with partial sells only increments by the base times the average price, i.e. as if no partial profit was made at all, so doesn't reflect the amount actually returned by the sell. With this hack the amount returned to the wallet is the cost of the sell after fees:

```
        # tot_in_trades = sum(trade.stake_amount for trade in open_trades)
                
        total_sells_cost = 0.0
        total_buys_cost = 0.0
        for trade in open_trades:
            for order in trade.orders:
                if order.side == 'sell':
                    total_sells_cost += (order.cost * (1 - trade.fee_close))
                if order.side == 'buy':    
                    total_buys_cost += (order.cost * (1 + trade.fee_open))
        tot_in_trades = total_buys_cost - total_sells_cost    
```
i didn't have time yet to have a look if this is actually a problem, or a miss-interpretation of some UI outputs (which i do not consider as complete information).

It's clearly a logical problem to subtract `stake_amount` from the simulated balance, and that's in the code right now.
> It's clearly a logical problem to use subtract `stake_amount` from the simulated balance, and that's in the code right now.

This is your report - yes.
At present, i can neither confirm nor deny that that's correct. 
Stating it as if it were a fact is incorrect and missleading, as it's your opinion / observation based on some assumptions, not something confirmed by anyone other than yourself.
I'm sorry if you can't see that logical problem, it's not my opinion, it's a logical problem. `stake_amount` is calculated in `recalc_trade_from_orders()` that has this line:
`price = avg_price if is_exit else tmp_price`

Which means `stake_amount` decrements by the base amount sold multiplied by the average price for sells, *not* the price it sold at, meaning if you were to sell above the average price the simulated balance wouldn't reflect that profit and would be too low compared to what the exchange would have in live. If you were to sell below the average price the simulated balance would appear to be higher, again not what an exchange would have.

Just to add to this, I'm referencing the code now, the UI screenshots just gave a hint (actually a very strong hint since the calculations matched exactly) what might be going on in the code. The `stake_amount` is subtracted from the current closed balance in `_update_dry(self)` using the following lines:

`tot_in_trades = sum(trade.stake_amount for trade in open_trades)`
and
`current_stake = self.start_cap + tot_profit - tot_in_trades`


As an aside, the reason there's such a large discrepency in those screenshots between the simulated wallet (showing a significant profit) and the projected profit (showing a significant loss) is because I'm running a grid bot that often sells below the average price, and in that trade the price dropped below the bottom of the grid, and I had to sell some at signifcantly below the average price to liberate some stake so it could continue to trade in a shifted down grid. As I said above, selling below the average price when subtracting `stake_amount` means the simulated balance is too high.

My analysis suggested quite strongly that `stake_amount` was very likely being subtracted from the current closed balance, but at no point did I say it actually was until I had looked at the code. Statements beginning with `it appears that` and `I think that` are not definitive. So your assertion that `Stating it as if it were a fact is incorrect and missleading, as it's your opinion / observation based on some assumptions` was completely unfounded and unjustified, I had previously referenced the code where it was happening, logically you cannot mix the partial profit way of calculating profit with the sum of the costs way, and a simulated wallet uses the latter while `stake_amount` is part of the former.

Screenshots like that are not information free, they can hint at possible or even probable problems in the code, they cannot be just dismissed as not having any relevance. That was the only information I used to track this down, and it took me 30 seconds to find it in the code. I understand you don't want people to just post screenshots and say 'hey, there's a problem here please fix it', but in my case I provided some detailed analysis of what frequi was appearing to say which if was true would strongly suggest a likely logical error in the code, and where it was.
> was completely unfounded and unjustified, 

Was referencing the below - which i find quite definitive to me.

> I'm sorry if you can't see that logical problem, it's not my opinion, it's a logical problem.

seems like you didn't read (or understand) what i said above.
I didn't **look** at this problem for more than "what's the info i will probably need". 
No line of code has been read for this problem until now.

As such - it's an **unverified Issue report**. Everyone reporting an issue will think they're right - and is as such their opinion. it's neither personal, nor limited to this particular issue.

That report might be true / correct - or might not - but it's not a **confirmed logical problem**, but a **suspected problem** (logical or not).
I never said you're wrong - i said i can neither confirm nor deny it's true - and that's still the case.

> Screenshots like that are not information free,

Sometimes - but in the above case, it assumes quite precise knowing of your situation. Extracting such a situation to a signle trade (like i'll do below) makes it much easier to actually understand the problem.
> As an aside, the reason there's such a large discrepency in those screenshots between the simulated wallet (showing a significant profit) and the projected profit (showing a significant loss) is because I'm running a grid bot that often sells below the average price, and in that trade the price dropped below the bottom of the grid, and I had to sell some at signifcantly below the average price to liberate some stake so it could continue to trade in a shifted down grid. As I said above, selling below the average price when subtracting stake_amount means the simulated balance is too high.

the actual profit or strategy running doesn't really matter :) 
every strategy will have it's downturns  at some point.

>  I'm referencing the code now, the UI screenshots just gave a hint

Referencing at the code and "this will fix it" doesn't really describe what the **problem is** though.
I'm still not sure what the actual problem is you're hinting at, and are "sure it's a logical problem".
Your initial description (everything else is basically "this code is wrong, this needs fixing") doesn't account for realized profit at all, and therefore these numbers can't match (that number is neither shown, nor accounted for)

As mentioned above, i'm not saying it is or isn't there - but i need to **understand** the problem first, and then find time to look at the problem.

---


If I look at the balance report code - it's using the sum of all open stakes (yes, based on their average entry prices) - adding the total profit already persisted (closed trades) - and subtracting the current "in trade" stakes.

The thing that's wrong here (to me) is not the usage of stake_amount (i struggle to see why you think that's wrong) - but the account for realized profit on open trades.

On your provided trade, that's ~-230$ - which is neither information that's been provided in the description - but it's what's Actually missing in your balance.
if i add in that logic - then your trade now look as follows (starting balance 2000$ - but reserving a small percentage)

![image](https://github.com/freqtrade/freqtrade/assets/5024695/77da666f-cf23-4587-89b5-31b708ac1d63)

![image](https://github.com/freqtrade/freqtrade/assets/5024695/6c4cd6b6-4bd7-4ec4-8cb0-2ae8574a5b2d)

Detail screenshot - as it contains the total profit
![image](https://github.com/freqtrade/freqtrade/assets/5024695/d3654d42-370b-4ece-b687-724dbbcc818b)


---

Making a very simple example (from the docs), but with stake amount added.

Starting capital = 5000$
Buy 100@8$ (800$)
Buy 100@9$ -> Avg price: 8.5$, stake_amount is 200 * 8.5 = 1700.0 (that's the same as 800$ + 900$) - we now have 3300$ left in the account.
Sell 100@10$ -> Avg price: 8.5$, realized profit 150$,stake-amount 100 * 8.5 = 850$ (USDT balance is now 5000 + 150 - 850 = 4300$)
buy 150@11$ -> Avg price: 10$, realized profit 150$, stake_amount = 250 * 10 = 2500$ (USDT balance is now 5000 + 150 - 2500 = 2650)

This seems like the correct value to me - and needs a much smaller (but quite different) adjustment to the code than yours, and is a lot safer, as `order.cost` will be filled unreliably when used in the context of futures.
Funnily enough - that's also exactly the result of `5000 - (100 * 8 + 100 * 9 - 100 * 10 + 150 * 11)` - which is using the logic you posted above (ignoring fees ...) - but might suffer from severe inconsistencies when using futures (even though these are only present on live - it's still pretty dangerous to actually use them in dry-run.





OK, if you add in realized profit to this what you're doing is logically identical to using the sell cost, since the realized profit is the difference between the the real price and the average price times the base sold, and you've already added the average price part. A more convoluted way than using costs directly I think, but logically the same. Using `stake_amount` by itself _is_ a logical problem though, my point still stands, that doesn't represent the difference between the costs of buying and the costs of selling which is what a simulated wallet should be showing. That's because a wallet is effectively summing up the difference between the buy costs that leave the wallet and the sell costs that return (importantly the base sold times the price it sold at), but `stake_amount` only decreases by the base sold multiplied by the average price for sells, not the sold at price, and if it didn't do that the average price would change with sells which we know shouldn't and doesn't happen.

Looking at that example you gave with just sum of costs it is equivalent to your version with realized profit added in:
```
Buy 100@8$ (800$) : USDT balance now 5000$ - 800$ = 4200$
Buy 100@9$ (900$) : USDT balance now 5000$ - 800$ - 900$ = 3300$
Sell 100@10$ ($1000) : USDT balance now 5000$ - 800$ - 900$ + $1000 = $4300
Buy 150@11 (1650$): USDT balance now 5000$ - 800$ - 900$ + 1000$ - 1650$ = 2650$
```
To be frank, this will need a bit more than a description and a screenshot to have it being looked at.

You can't assume that the bot started "x" up from a chart. Treat it as what it is - a chart. Once you accound for parallelism etc., You cant take any assumption about the prior state from this plot, sorry.


As is, it's non actionable without significant time invest to even try and get to a similar state (which isn't described how, either).

I'm happy to look at it if i can either get that database file (so i can look at the actual data), or even better, if you're able to compile a simple unittest thats showing what you think is wrong.

Maybe (most likely) also the output of 
`freqtrade show-trades --db-url sqlite:///<trades.sqlite> --print-json --trade-id <tradeid>` for the open will suffice, but i can't say for sure.
OK, I'll get the trade information for you. But I know the balance reverts to the projected value on closing the trade, I reported that on Discord so I'm confident it started with that balance, and the figures match exactly which is a pretty strong clue that it did (this is not the first time this has happened BTW):
https://discord.com/channels/700048804539400213/779658156467814421/1124081752504291338

Here's the trade log:
[trade_18_json.txt](https://github.com/freqtrade/freqtrade/files/11996092/trade_18_json.txt)

To be honest for this you don't really need recreate the state, a simple examination of the code to see whether `stake_amount` is being subtracted from the last simulated balance should suffice because if it is there's a logical problem, it should be the last simulated balance minus the sum of the stakes used for buys plus the sum of the stakes returned from sells.
I think the problem is in `_update_dry(self)`, specifically the bit that sums up the total amount in trades:
`tot_in_trades = sum(trade.stake_amount for trade in open_trades)`
I forgot to add the actual database as you requested, sorry.
[PerkGrid_test14_dry.zip](https://github.com/freqtrade/freqtrade/files/12013779/PerkGrid_test14_dry.zip)

I have hacked my version of `_update_dry(self)` in `wallets.py` to do this. It's a hack, nowhere near freqtrade standards, but it does seem to make the simulated balance much closer to the projected profit. Not quite the same (possibly due to fees need to be applied when selling up, the balance just shows how much the remaining base is worth without those fees).

As it stands at the moment the simulated balance for USDT with partial sells only increments by the base times the average price, i.e. as if no partial profit was made at all, so doesn't reflect the amount actually returned by the sell. With this hack the amount returned to the wallet is the cost of the sell after fees:

```
        # tot_in_trades = sum(trade.stake_amount for trade in open_trades)
                
        total_sells_cost = 0.0
        total_buys_cost = 0.0
        for trade in open_trades:
            for order in trade.orders:
                if order.side == 'sell':
                    total_sells_cost += (order.cost * (1 - trade.fee_close))
                if order.side == 'buy':    
                    total_buys_cost += (order.cost * (1 + trade.fee_open))
        tot_in_trades = total_buys_cost - total_sells_cost    
```
i didn't have time yet to have a look if this is actually a problem, or a miss-interpretation of some UI outputs (which i do not consider as complete information).

It's clearly a logical problem to subtract `stake_amount` from the simulated balance, and that's in the code right now.
> It's clearly a logical problem to use subtract `stake_amount` from the simulated balance, and that's in the code right now.

This is your report - yes.
At present, i can neither confirm nor deny that that's correct. 
Stating it as if it were a fact is incorrect and missleading, as it's your opinion / observation based on some assumptions, not something confirmed by anyone other than yourself.
I'm sorry if you can't see that logical problem, it's not my opinion, it's a logical problem. `stake_amount` is calculated in `recalc_trade_from_orders()` that has this line:
`price = avg_price if is_exit else tmp_price`

Which means `stake_amount` decrements by the base amount sold multiplied by the average price for sells, *not* the price it sold at, meaning if you were to sell above the average price the simulated balance wouldn't reflect that profit and would be too low compared to what the exchange would have in live. If you were to sell below the average price the simulated balance would appear to be higher, again not what an exchange would have.

Just to add to this, I'm referencing the code now, the UI screenshots just gave a hint (actually a very strong hint since the calculations matched exactly) what might be going on in the code. The `stake_amount` is subtracted from the current closed balance in `_update_dry(self)` using the following lines:

`tot_in_trades = sum(trade.stake_amount for trade in open_trades)`
and
`current_stake = self.start_cap + tot_profit - tot_in_trades`


As an aside, the reason there's such a large discrepency in those screenshots between the simulated wallet (showing a significant profit) and the projected profit (showing a significant loss) is because I'm running a grid bot that often sells below the average price, and in that trade the price dropped below the bottom of the grid, and I had to sell some at signifcantly below the average price to liberate some stake so it could continue to trade in a shifted down grid. As I said above, selling below the average price when subtracting `stake_amount` means the simulated balance is too high.

My analysis suggested quite strongly that `stake_amount` was very likely being subtracted from the current closed balance, but at no point did I say it actually was until I had looked at the code. Statements beginning with `it appears that` and `I think that` are not definitive. So your assertion that `Stating it as if it were a fact is incorrect and missleading, as it's your opinion / observation based on some assumptions` was completely unfounded and unjustified, I had previously referenced the code where it was happening, logically you cannot mix the partial profit way of calculating profit with the sum of the costs way, and a simulated wallet uses the latter while `stake_amount` is part of the former.

Screenshots like that are not information free, they can hint at possible or even probable problems in the code, they cannot be just dismissed as not having any relevance. That was the only information I used to track this down, and it took me 30 seconds to find it in the code. I understand you don't want people to just post screenshots and say 'hey, there's a problem here please fix it', but in my case I provided some detailed analysis of what frequi was appearing to say which if was true would strongly suggest a likely logical error in the code, and where it was.
> was completely unfounded and unjustified, 

Was referencing the below - which i find quite definitive to me.

> I'm sorry if you can't see that logical problem, it's not my opinion, it's a logical problem.

seems like you didn't read (or understand) what i said above.
I didn't **look** at this problem for more than "what's the info i will probably need". 
No line of code has been read for this problem until now.

As such - it's an **unverified Issue report**. Everyone reporting an issue will think they're right - and is as such their opinion. it's neither personal, nor limited to this particular issue.

That report might be true / correct - or might not - but it's not a **confirmed logical problem**, but a **suspected problem** (logical or not).
I never said you're wrong - i said i can neither confirm nor deny it's true - and that's still the case.

> Screenshots like that are not information free,

Sometimes - but in the above case, it assumes quite precise knowing of your situation. Extracting such a situation to a signle trade (like i'll do below) makes it much easier to actually understand the problem.
> As an aside, the reason there's such a large discrepency in those screenshots between the simulated wallet (showing a significant profit) and the projected profit (showing a significant loss) is because I'm running a grid bot that often sells below the average price, and in that trade the price dropped below the bottom of the grid, and I had to sell some at signifcantly below the average price to liberate some stake so it could continue to trade in a shifted down grid. As I said above, selling below the average price when subtracting stake_amount means the simulated balance is too high.

the actual profit or strategy running doesn't really matter :) 
every strategy will have it's downturns  at some point.

>  I'm referencing the code now, the UI screenshots just gave a hint

Referencing at the code and "this will fix it" doesn't really describe what the **problem is** though.
I'm still not sure what the actual problem is you're hinting at, and are "sure it's a logical problem".
Your initial description (everything else is basically "this code is wrong, this needs fixing") doesn't account for realized profit at all, and therefore these numbers can't match (that number is neither shown, nor accounted for)

As mentioned above, i'm not saying it is or isn't there - but i need to **understand** the problem first, and then find time to look at the problem.

---


If I look at the balance report code - it's using the sum of all open stakes (yes, based on their average entry prices) - adding the total profit already persisted (closed trades) - and subtracting the current "in trade" stakes.

The thing that's wrong here (to me) is not the usage of stake_amount (i struggle to see why you think that's wrong) - but the account for realized profit on open trades.

On your provided trade, that's ~-230$ - which is neither information that's been provided in the description - but it's what's Actually missing in your balance.
if i add in that logic - then your trade now look as follows (starting balance 2000$ - but reserving a small percentage)

![image](https://github.com/freqtrade/freqtrade/assets/5024695/77da666f-cf23-4587-89b5-31b708ac1d63)

![image](https://github.com/freqtrade/freqtrade/assets/5024695/6c4cd6b6-4bd7-4ec4-8cb0-2ae8574a5b2d)

Detail screenshot - as it contains the total profit
![image](https://github.com/freqtrade/freqtrade/assets/5024695/d3654d42-370b-4ece-b687-724dbbcc818b)


---

Making a very simple example (from the docs), but with stake amount added.

Starting capital = 5000$
Buy 100@8$ (800$)
Buy 100@9$ -> Avg price: 8.5$, stake_amount is 200 * 8.5 = 1700.0 (that's the same as 800$ + 900$) - we now have 3300$ left in the account.
Sell 100@10$ -> Avg price: 8.5$, realized profit 150$,stake-amount 100 * 8.5 = 850$ (USDT balance is now 5000 + 150 - 850 = 4300$)
buy 150@11$ -> Avg price: 10$, realized profit 150$, stake_amount = 250 * 10 = 2500$ (USDT balance is now 5000 + 150 - 2500 = 2650)

This seems like the correct value to me - and needs a much smaller (but quite different) adjustment to the code than yours, and is a lot safer, as `order.cost` will be filled unreliably when used in the context of futures.
Funnily enough - that's also exactly the result of `5000 - (100 * 8 + 100 * 9 - 100 * 10 + 150 * 11)` - which is using the logic you posted above (ignoring fees ...) - but might suffer from severe inconsistencies when using futures (even though these are only present on live - it's still pretty dangerous to actually use them in dry-run.





OK, if you add in realized profit to this what you're doing is logically identical to using the sell cost, since the realized profit is the difference between the the real price and the average price times the base sold, and you've already added the average price part. A more convoluted way than using costs directly I think, but logically the same. Using `stake_amount` by itself _is_ a logical problem though, my point still stands, that doesn't represent the difference between the costs of buying and the costs of selling which is what a simulated wallet should be showing. That's because a wallet is effectively summing up the difference between the buy costs that leave the wallet and the sell costs that return (importantly the base sold times the price it sold at), but `stake_amount` only decreases by the base sold multiplied by the average price for sells, not the sold at price, and if it didn't do that the average price would change with sells which we know shouldn't and doesn't happen.

Looking at that example you gave with just sum of costs it is equivalent to your version with realized profit added in:
```
Buy 100@8$ (800$) : USDT balance now 5000$ - 800$ = 4200$
Buy 100@9$ (900$) : USDT balance now 5000$ - 800$ - 900$ = 3300$
Sell 100@10$ ($1000) : USDT balance now 5000$ - 800$ - 900$ + $1000 = $4300
Buy 150@11 (1650$): USDT balance now 5000$ - 800$ - 900$ + 1000$ - 1650$ = 2650$
```

Resolving patch:
diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py
--- a/freqtrade/wallets.py
+++ b/freqtrade/wallets.py
@@ -84,6 +84,7 @@ def _update_dry(self) -> None:
             tot_profit = Trade.get_total_closed_profit()
         else:
             tot_profit = LocalTrade.total_profit
+        tot_profit += sum(trade.realized_profit for trade in open_trades)
         tot_in_trades = sum(trade.stake_amount for trade in open_trades)
         used_stake = 0.0
 


Test patch:
diff --git a/tests/test_integration.py b/tests/test_integration.py
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -493,6 +493,8 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
         get_funding_fees=MagicMock(return_value=0),
     )
     mocker.patch(f"{EXMS}.get_max_leverage", return_value=10)
+    starting_amount = freqtrade.wallets.get_total('USDT')
+    assert starting_amount == 1000
 
     patch_get_signal(freqtrade)
     freqtrade.strategy.leverage = MagicMock(return_value=leverage)
@@ -505,6 +507,11 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
     assert trade.leverage == leverage
     assert pytest.approx(trade.amount) == 30.0 * leverage
     assert trade.open_rate == 2.0
+    assert pytest.approx(freqtrade.wallets.get_free('USDT')) == starting_amount - 60
+    if spot:
+        assert pytest.approx(freqtrade.wallets.get_total('USDT')) == starting_amount - 60
+    else:
+        assert freqtrade.wallets.get_total('USDT') == starting_amount
 
     # Too small size
     freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-59)
@@ -527,6 +534,14 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
     assert trade.open_rate == 2.0
     assert trade.is_open
     assert trade.realized_profit > 0.098 * leverage
+    expected_profit = starting_amount - 40.1980 + trade.realized_profit
+    assert pytest.approx(freqtrade.wallets.get_free('USDT')) == expected_profit
+
+    if spot:
+        assert pytest.approx(freqtrade.wallets.get_total('USDT')) == expected_profit
+    else:
+        # total won't change in futures mode, only free / used will.
+        assert freqtrade.wallets.get_total('USDT') == starting_amount + trade.realized_profit
     caplog.clear()
 
     # Sell more than what we got (we got ~20 coins left)
@@ -551,3 +566,10 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, levera
     assert pytest.approx(trade.stake_amount) == 40.198
     assert trade.is_open
     assert log_has_re('Amount to exit is 0.0 due to exchange limits - not exiting.', caplog)
+    expected_profit = starting_amount - 40.1980 + trade.realized_profit
+    assert pytest.approx(freqtrade.wallets.get_free('USDT')) == expected_profit
+    if spot:
+        assert pytest.approx(freqtrade.wallets.get_total('USDT')) == expected_profit
+    else:
+        # total won't change in futures mode, only free / used will.
+        assert freqtrade.wallets.get_total('USDT') == starting_amount + trade.realized_profit
diff --git a/tests/test_wallets.py b/tests/test_wallets.py
--- a/tests/test_wallets.py
+++ b/tests/test_wallets.py
@@ -8,7 +8,8 @@
 from freqtrade.constants import UNLIMITED_STAKE_AMOUNT
 from freqtrade.exceptions import DependencyException
 from freqtrade.persistence import Trade
-from tests.conftest import EXMS, create_mock_trades, get_patched_freqtradebot, patch_wallet
+from tests.conftest import (EXMS, create_mock_trades, create_mock_trades_usdt,
+                            get_patched_freqtradebot, patch_wallet)
 
 
 def test_sync_wallet_at_boot(mocker, default_conf):
@@ -341,6 +342,33 @@ def test_sync_wallet_futures_live(mocker, default_conf):
     assert 'ETH/USDT:USDT' not in freqtrade.wallets._positions
 
 
+def test_sync_wallet_dry(mocker, default_conf_usdt, fee):
+    default_conf_usdt['dry_run'] = True
+    freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
+    assert len(freqtrade.wallets._wallets) == 1
+    assert len(freqtrade.wallets._positions) == 0
+    assert freqtrade.wallets.get_total('USDT') == 1000
+
+    create_mock_trades_usdt(fee, is_short=None)
+
+    freqtrade.wallets.update()
+
+    assert len(freqtrade.wallets._wallets) == 5
+    assert len(freqtrade.wallets._positions) == 0
+    bal = freqtrade.wallets.get_all_balances()
+    assert bal['NEO'].total == 10
+    assert bal['XRP'].total == 10
+    assert bal['LTC'].total == 2
+    assert bal['USDT'].total == 922.74
+
+    assert freqtrade.wallets.get_starting_balance() == default_conf_usdt['dry_run_wallet']
+    total = freqtrade.wallets.get_total('LTC')
+    free = freqtrade.wallets.get_free('LTC')
+    used = freqtrade.wallets.get_used('LTC')
+    assert free != 0
+    assert free + used == total
+
+
 def test_sync_wallet_futures_dry(mocker, default_conf, fee):
     default_conf['dry_run'] = True
     default_conf['trading_mode'] = 'futures'