5.9 KiB
5.9 KiB
Chart Fix Summary - Timestamp and Timeframe Issues
Problem Description
The chart was experiencing two main issues:
- Error: "Cannot update oldest data, last time=[object Object], new time=[object Object]"
- Timeframe switching: Live updates interfering with historical data when changing timeframes (e.g., to 5min)
Root Causes
Issue 1: Timestamp Conflicts
- Live price updates were generating timestamps that could be older than the last candle in historical data
- The lightweight-charts library requires that new updates must have timestamps >= the last candle's timestamp
- When rounded to the nearest minute, the live timestamp could be before the last historical candle
Issue 2: Inappropriate Live Updates
- Live updates were enabled for all timeframes, including daily/weekly historical views
- When switching to intraday timeframes (5min, 15min), stale live updates would conflict with freshly loaded historical data
- No synchronization between the live update interval and the chart's timeframe
Solutions Implemented
1. Smart Timestamp Validation (GoldChart.tsx)
// Only update if the new time is newer than or equal to the last historical time
if (liveUpdate.time < lastHistoricalTime) {
console.log('Skipping live update: timestamp is older than historical data');
return;
}
- Added validation to skip live updates that are older than historical data
- Prevents the "Cannot update oldest data" error
- Logs skipped updates for debugging
2. Conditional Live Updates (App.tsx)
// Live price updates - only enable for intraday timeframes
const enableLiveUpdates = ['1min', '5min', '15min', '30min', '60min'].includes(timeframe);
const { latestPrice, isConnected } = useLivePrice({
enabled: enableLiveUpdates && !isLoading,
pollInterval: 10000,
timeframe: timeframe,
...
});
- Live updates are only enabled for intraday timeframes (1min-60min)
- Disabled for daily/weekly views where live updates don't make sense
- Live updates pause during data loading to prevent conflicts
3. Timeframe-Aware Live Endpoint (Backend)
File: backend/app/api/market.py
@router.get("/gold/live")
async def get_live_gold_price(interval: str = "1min"):
# Map intervals to seconds for rounding
interval_map = {
"1min": 60,
"5min": 5 * 60,
"15min": 15 * 60,
...
}
# Round UP to the next interval to ensure newest timestamp
current_time = ((current_time // interval_seconds) + 1) * interval_seconds
Key improvements:
- Accepts an
intervalparameter matching the chart's timeframe - Rounds timestamps up to the next interval boundary (not down or nearest)
- Ensures live updates always have timestamps newer than historical data
- Aligns with the granularity of the selected timeframe
4. Enhanced Hook with Timeframe Support
File: frontend/src/hooks/useLivePrice.ts
export interface UseLivePriceOptions {
pollInterval?: number; // Renamed from 'interval' for clarity
timeframe?: string; // NEW: Chart timeframe (1min, 5min, etc.)
...
}
- Passes the current timeframe to the backend
- Fetches live data matching the chart's time granularity
- Prevents timestamp misalignment
Testing Checklist
✅ Daily View (1D)
- Live updates are disabled ✓
- No "Live" badge showing
- Historical data loads correctly
- No timestamp errors
✅ Intraday Views (1min, 5min, 15min, etc.)
- Live updates are enabled ✓
- "Live" badge shows with pulse animation
- New candles appear every 10 seconds
- No timestamp errors when switching between timeframes
✅ Timeframe Switching
- Switching from 1D → 5min: Historical data loads, then live updates begin
- Switching from 5min → 1D: Live updates stop, historical data loads
- No errors during transitions
✅ Error Handling
- Gracefully handles API rate limits
- Connection status tracked correctly
- Skips invalid live updates without crashing
Configuration
Adjusting Poll Frequency
In App.tsx:
pollInterval: 10000, // 10 seconds - increase to reduce API calls
Supported Timeframes for Live Updates
In App.tsx:
const enableLiveUpdates = ['1min', '5min', '15min', '30min', '60min'].includes(timeframe);
API Rate Limits
The free FXRatesAPI has rate limits. If you hit 429 errors:
- Increase
pollIntervalto 30000 (30 seconds) or more - Consider caching the current price on the backend
- Implement exponential backoff in the hook
Technical Details
Timestamp Rounding Logic
- 1min: Rounds to next minute boundary
- 5min: Rounds to next 5-minute boundary (e.g., 10:05, 10:10, 10:15)
- 15min: Rounds to next 15-minute boundary
- Always rounds up (not down) to ensure future timestamps
Why Round Up Instead of Down?
- Historical data ends at time T
- Rounding down could create time T-1, causing timestamp conflict
- Rounding up creates time T+1, safely appending after historical data
Lightweight Charts Update Methods
setData(): Replaces all data (used for historical data load)update(): Appends/updates a single candle (used for live updates)update()requires timestamps in ascending order
Known Limitations
- Simulated Intraday Data: Free APIs don't provide real intraday OHLC data - we generate it
- Rate Limits: Free API tier has rate limits (fix: increase poll interval)
- No Real-time Ticks: 10-second polls, not true tick-by-tick data
- SMA Updates: Live SMA updates not yet implemented (only price updates)
Future Enhancements
- Implement WebSocket for true real-time updates (sub-second)
- Update SMA/indicators in real-time as new candles arrive
- Add configurable poll intervals in UI
- Implement smart backoff when API rate limits hit
- Cache current price on backend to reduce external API calls
- Show last update timestamp in the UI