Files
robinhood/docs/CHART_FIX_SUMMARY.md

5.9 KiB

Chart Fix Summary - Timestamp and Timeframe Issues

Problem Description

The chart was experiencing two main issues:

  1. Error: "Cannot update oldest data, last time=[object Object], new time=[object Object]"
  2. 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 interval parameter 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:

  1. Increase pollInterval to 30000 (30 seconds) or more
  2. Consider caching the current price on the backend
  3. 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

  1. Simulated Intraday Data: Free APIs don't provide real intraday OHLC data - we generate it
  2. Rate Limits: Free API tier has rate limits (fix: increase poll interval)
  3. No Real-time Ticks: 10-second polls, not true tick-by-tick data
  4. 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