7.3 KiB
7.3 KiB
Currency Conversion Feature
Overview
The Portfolio Tracker now supports automatic currency conversion for transactions that are in different currencies than the portfolio's base currency. This feature allows users to have a unified view of their investments across multiple currencies.
How It Works
Automatic Detection
- When a transaction is added, the system automatically detects the stock's currency from Yahoo Finance
- If the transaction currency differs from the portfolio's base currency, conversion rates are fetched
- Converted values are displayed alongside original values for transparency
Display Format
The transaction table now includes additional columns when multi-currency transactions are present:
| Original Column | New Column | Description |
|---|---|---|
| Preis | Preis (BASE_CURRENCY) | Shows converted price in portfolio base currency |
| Gesamt | Gesamt (BASE_CURRENCY) | Shows converted total in portfolio base currency |
Example Display
Original: 150.00 USD
Converted: 135.50 EUR (when EUR is portfolio base currency)
Features
1. Real-time Currency Conversion
- Exchange rates are fetched from
exchangerate-api.io - Rates are cached for 1 hour to improve performance
- Supports all major world currencies
2. Smart Display Logic
- If transaction currency = portfolio currency: shows "-" in conversion columns
- If currencies differ: shows converted amount
- If conversion fails: shows "Conv. Error"
3. Portfolio Summary
- Total invested amount is automatically converted to portfolio base currency
- Summary shows "(converted)" indicator when multi-currency transactions exist
4. Currency Information Panel
A new information panel explains:
- That transactions in other currencies are automatically converted
- Exchange rates are updated hourly
- Conversion is for display purposes only
Technical Implementation
Currency Conversion Utility (internal/util/currency.go)
Key Functions:
// Get exchange rate between two currencies
GetExchangeRate(fromCurrency, toCurrency string) (float64, error)
// Convert amount from one currency to another
ConvertCurrency(amount float64, fromCurrency, toCurrency string) (float64, error)
// Format currency with appropriate symbol
FormatCurrencyWithSymbol(amount float64, currency string) string
// Batch convert multiple amounts efficiently
BatchConvertCurrency(amounts []float64, fromCurrency, toCurrency string) ([]float64, error)
Caching System:
- Cache Duration: 1 hour per exchange rate
- Cache Key Format:
FROM_TO(e.g., "USD_EUR") - Memory Usage: Minimal - only stores rate and timestamp
- Thread Safe: Uses RWMutex for concurrent access
Template Helper Functions (internal/web/templates/helpers.go)
Key Helper Functions:
// Get converted price for display
getConvertedPrice(activity model.Activity, portfolioBaseCurrency string) string
// Get converted total for display
getConvertedTotal(activity model.Activity, portfolioBaseCurrency string) string
// Calculate total invested in base currency
calculateTotalInvestedInBaseCurrency(activities []model.Activity, baseCurrency string) float64
// Format total with conversion indicator
formatTotalInvestedWithConversion(activities []model.Activity, baseCurrency string) string
Supported Currencies
The system supports all currencies provided by the exchange rate API, including:
| Currency | Code | Symbol |
|---|---|---|
| US Dollar | USD | $ |
| Euro | EUR | € |
| British Pound | GBP | £ |
| Japanese Yen | JPY | ¥ |
| Swiss Franc | CHF | CHF |
| Canadian Dollar | CAD | C$ |
| Australian Dollar | AUD | A$ |
| And many more... |
Error Handling
API Failures
- If exchange rate API is unavailable: shows "Conv. Error"
- Original transaction data is always preserved
- System continues to function normally
Invalid Currencies
- Unknown currency codes are handled gracefully
- System falls back to displaying original amounts
- No data loss occurs
Network Issues
- Cached rates are used when possible
- Graceful degradation to original currency display
- User is informed via "Conv. Error" message
Performance Considerations
Caching Strategy
- Hit Rate: High due to 1-hour cache duration
- API Calls: Minimized through intelligent caching
- Memory Usage: Low - only active currency pairs cached
- Cleanup: Automatic cache expiration
Batch Operations
- Multiple conversions use single API call when possible
- Efficient for portfolios with many same-currency transactions
- Reduces API rate limit consumption
Configuration
API Limits
- Free Tier: 1,500 requests per month
- Rate Limiting: Built-in request throttling
- Fallback: Graceful degradation when limits exceeded
Cache Management
// Clear cache manually (for testing/debugging)
util.ClearCache()
// Get cache statistics
cacheInfo := util.GetCacheInfo()
Usage Examples
Adding Multi-Currency Transaction
- User adds transaction for Apple (AAPL) in USD to EUR portfolio
- System detects USD currency from Yahoo Finance
- Fetches USD/EUR exchange rate
- Displays both original (USD) and converted (EUR) amounts
- Caches exchange rate for future use
Portfolio Summary
Portfolio: "My Investments" (EUR)
Total Invested: 15,430.50 EUR (converted)
Recent Transactions:
- AAPL: 150.00 USD (~135.50 EUR)
- BMW.DE: 85.30 EUR (-)
- NESN.SW: 110.20 CHF (~102.15 EUR)
Testing
Unit Tests
- All currency utilities have comprehensive test coverage
- Tests include edge cases and error conditions
- Performance benchmarks included
Integration Tests
- Test with real transaction data
- Verify UI display logic
- Cache behavior validation
Future Enhancements
Planned Features
- Historical Rates: Use transaction date for accurate historical conversion
- Multiple Rate Providers: Fallback to alternative APIs
- Custom Rate Override: Allow manual exchange rate input
- Currency Trends: Show exchange rate history
- Base Currency Change: Convert entire portfolio to new base currency
API Improvements
- Rate Provider Selection: Choose between multiple APIs
- Custom Update Intervals: Configurable cache duration
- Offline Mode: Store rates locally for offline use
Troubleshooting
Common Issues
"Conv. Error" Displayed
- Cause: Exchange rate API unavailable or rate limit exceeded
- Solution: Wait and refresh, or check internet connection
- Impact: Original data still visible and functional
Slow Loading
- Cause: First-time rate fetching or cache expiration
- Solution: Subsequent loads will be faster due to caching
- Mitigation: Consider pre-warming cache for common currencies
Incorrect Rates
- Cause: API data delay or temporary inconsistency
- Solution: Rates update automatically within 1 hour
- Manual Fix: Clear cache to force immediate refresh
Debug Commands
# Clear currency cache
curl -X POST http://localhost:8080/api/admin/clear-currency-cache
# Get cache status
curl http://localhost:8080/api/admin/currency-cache-info
Security Considerations
- No API Keys Required: Uses free public API
- Rate Limiting: Built-in protection against abuse
- Data Privacy: No sensitive data sent to external APIs
- Fallback Security: System functions without external dependencies