[BUG] Portfolio Value Incorrectly Drops After Adding a Dividend When Market Price is Unavailable
Bug Description
When a live market price for an asset cannot be fetched, the system incorrectly uses the unitPrice of the most recent transaction as a fallback for the current market price. If the most recent transaction is a dividend, the system uses the dividend-per-share amount as the asset's market price. This leads to a significant and incorrect drop in the calculated value of the holding and the overall portfolio.
I believe the root cause is in the CurrentRateService.getValues method. When a live quote fails, the fallback logic fetches the latest activity for the symbol, regardless of its type (including DIVIDEND), and uses its unitPrice as the current marketPrice.
To Reproduce
- Choose an existing holding in your portfolio, preferably one for which live market data might be temporarily unavailable.
- Add a
DIVIDENDtransaction for this asset. Make this the most recent transaction for this holding. - Go to the Holdings page or any view that displays the current market value of your portfolio.
- Observe that the market price for the holding now reflects the dividend-per-share amount, and the total value of the holding has dropped significantly.
Expected Behavior
When a live market price is unavailable, the system should use a more appropriate fallback. The order of preference should be:
- The previous day's closing market price.
- If no historical data is available, the
unitPriceof the most recent trade activity (BUYorSELL). - The
unitPriceof aDIVIDENDtransaction should never be used as a fallback for the market price.
If no valid fallback price can be found, the market price should be displayed as null, and the holding's value should not be calculated based on an incorrect price.
Screenshots
My latest activity:
Logs
I tried logging the unitPriceAtEndDate and latestActivity.unitPrice, both showing the dividend-per-share price:
unitPriceAtEndDate 0.01
latestActivity.unitPrice 0.01Environment
- Ghostfolio Version 2.205.0
- Self-hosted
- Experimental Features enabled
- Chrome Browser
- macOS
Additional Context
The fallback logic is located in apps/api/src/app/portfolio/current-rate.service.ts within the getValues method.
The call to this.orderService.getLatestOrder does not distinguish between activity types, leading it to pick up dividend transactions.
Source: ghostfolio/ghostfolio