Files
portfolio-tracker/docs/CURRENCY_CONVERSION.md
T
2025-07-05 03:44:53 +02:00

8.8 KiB

Currency Conversion Feature

Overview

The Portfolio Tracker now supports automatic currency conversion with historical exchange rates for transactions that are in different currencies than the portfolio's base currency. This feature uses the actual exchange rates from the transaction date, providing accurate historical conversion and allowing users to have a unified view of their investments across multiple currencies.

How It Works

Automatic Historical 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, historical conversion rates from the transaction date are fetched
  • Converted values using historical rates are displayed alongside original values for transparency
  • Falls back to current rates if historical rates are unavailable (marked with *)

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. Historical Currency Conversion

  • Historical exchange rates are fetched from exchangerate-api.com and frankfurter.app for accurate transaction-date conversion
  • Historical rates are cached for 24 hours, current rates for 1 hour to improve performance
  • Falls back to current rates when historical rates are unavailable
  • Supports all major world currencies with date-specific accuracy

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"
  • If historical rate unavailable: shows converted amount with "*" indicator (using current rate)

3. Portfolio Summary

  • Total invested amount is automatically converted to portfolio base currency using historical rates
  • Summary shows "(historical rates)" or "(converted)" indicator when multi-currency transactions exist
  • Provides most accurate historical portfolio valuation

4. Currency Information Panel

A new information panel explains:

  • That transactions in other currencies are automatically converted using historical exchange rates
  • Historical rates are fetched for the actual transaction date
  • Falls back to current rates when historical data is unavailable (marked with *)
  • Conversion provides accurate historical portfolio tracking

Technical Implementation

Currency Conversion Utility (internal/util/currency.go)

Key Functions:

// Get current exchange rate between two currencies
GetExchangeRate(fromCurrency, toCurrency string) (float64, error)

// Get historical exchange rate for a specific date
GetHistoricalExchangeRate(fromCurrency, toCurrency string, date time.Time) (float64, error)

// Convert amount from one currency to another using current rates
ConvertCurrency(amount float64, fromCurrency, toCurrency string) (float64, error)

// Convert amount using historical exchange rate for a specific date
ConvertCurrencyHistorical(amount float64, fromCurrency, toCurrency string, date time.Time) (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 using historical rates
getConvertedPrice(activity model.Activity, portfolioBaseCurrency string) string

// Get converted total for display using historical rates
getConvertedTotal(activity model.Activity, portfolioBaseCurrency string) string

// Get converted total with fallback information
getConvertedTotalWithFallbackInfo(activity model.Activity, portfolioBaseCurrency string) string

// Calculate total invested in base currency using historical rates
calculateTotalInvestedInBaseCurrency(activities []model.Activity, baseCurrency string) float64

// Format total with historical 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

  1. User adds transaction for Apple (AAPL) in USD to EUR portfolio
  2. System detects USD currency from Yahoo Finance
  3. Fetches USD/EUR exchange rate
  4. Displays both original (USD) and converted (EUR) amounts
  5. 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

  1. Historical Rates: Use transaction date for accurate historical conversion
  2. Multiple Rate Providers: Fallback to alternative APIs
  3. Custom Rate Override: Allow manual exchange rate input
  4. Currency Trends: Show exchange rate history
  5. Base Currency Change: Convert entire portfolio to new base currency

API Improvements

  1. Rate Provider Selection: Choose between multiple APIs
  2. Custom Update Intervals: Configurable cache duration
  3. 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