Initial commit: Gold Trading Simulator with AI-powered analysis
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
# 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)
|
||||
```typescript
|
||||
// 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)
|
||||
```typescript
|
||||
// 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`
|
||||
|
||||
```python
|
||||
@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`
|
||||
|
||||
```typescript
|
||||
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`:
|
||||
```typescript
|
||||
pollInterval: 10000, // 10 seconds - increase to reduce API calls
|
||||
```
|
||||
|
||||
### Supported Timeframes for Live Updates
|
||||
In `App.tsx`:
|
||||
```typescript
|
||||
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
|
||||
Reference in New Issue
Block a user