Phase 4: Economic Calendar API Integration

Implemented comprehensive economic calendar system for trading event alerts:

Backend (economic_calendar.py):
- GET /api/economic-calendar/events: Fetch events by days, countries, impact level
- GET /api/economic-calendar/today: Get today's scheduled events
- GET /api/economic-calendar/upcoming: Events within X hours (1-168)
- GET /api/economic-calendar/high-impact: Only critical events (next 30 days)
- GET /api/economic-calendar/by-country/{country}: Country-specific events
- GET /api/economic-calendar/impact-analysis: Gold trading impact analysis
- GET /api/economic-calendar/calendar-view: Calendar view with events by day
- POST /api/economic-calendar/events/{event_id}/notify: Set reminder notifications
- GET /api/economic-calendar/stats: Event statistics and busiest days

Features:
- Sample economic events: NFP, CPI, Unemployment, Fed Rate Decision, ECB Rate
- Impact levels: High/Medium/Low with color coding
- Forecast, previous, and actual values tracking
- Event filtering by country, impact, and days ahead
- Multiple sort options: date, importance, impact
- Notifications 15-120 minutes before events
- Gold trading correlation analysis
- Statistics for 7-day and 30-day windows

Frontend (EconomicCalendar.tsx):
- Calendar overview with event statistics
- Upcoming and high-impact event tabs
- Country-based filtering
- Impact-based color coding (red/yellow/blue)
- Event details: forecast, previous, actual values
- Trading tips for different event types
- Event time display with timezone consideration
- Correlation guidance (USD inverse, rates inverse)
- Visual indicators for pending/actual events

Integration:
- Registered economic_calendar router in main.py
- Added EconomicCalendar tab to App.tsx
- Integrated with navigation system
- Full TypeScript support

Note: Currently uses mock data. In production, integrate with:
- Trading Economics API
- Forexfactory Calendar
- Economic Calendar Pro
- OANDA Calendar
This commit is contained in:
Claude
2025-11-16 05:58:35 +00:00
parent 3f7b69b52c
commit 754b4a62c0
4 changed files with 765 additions and 3 deletions
+450
View File
@@ -0,0 +1,450 @@
"""
Phase 4: Economic Calendar API Integration
Real-time economic events and market-moving indicators
"""
from fastapi import APIRouter, Query, HTTPException
from datetime import datetime, timedelta
from typing import List, Optional
import httpx
router = APIRouter(prefix="/api/economic-calendar", tags=["Economic Calendar"])
# Mock economic calendar data (in production, integrate with real APIs)
# Popular APIs: Trading Economics, Forexfactory, Economic Calendar Pro, etc.
SAMPLE_EVENTS = [
{
"id": 1,
"country": "US",
"indicator": "Non-Farm Payroll",
"event_date": (datetime.now() + timedelta(days=1)).isoformat(),
"time": "08:30",
"impact": "high",
"forecast": "230000",
"previous": "227000",
"actual": None,
"description": "Employment change in the non-agricultural sector",
"importance": 3,
},
{
"id": 2,
"country": "US",
"indicator": "Unemployment Rate",
"event_date": (datetime.now() + timedelta(days=1)).isoformat(),
"time": "08:30",
"impact": "high",
"forecast": "3.8%",
"previous": "3.8%",
"actual": None,
"description": "Percentage of the labor force that is jobless",
"importance": 3,
},
{
"id": 3,
"country": "US",
"indicator": "Consumer Price Index",
"event_date": (datetime.now() + timedelta(days=5)).isoformat(),
"time": "12:30",
"impact": "high",
"forecast": "3.4%",
"previous": "3.4%",
"actual": None,
"description": "Inflation rate measurement",
"importance": 3,
},
{
"id": 4,
"country": "US",
"indicator": "Federal Funds Rate Decision",
"event_date": (datetime.now() + timedelta(days=8)).isoformat(),
"time": "18:00",
"impact": "high",
"forecast": "5.33%",
"previous": "5.33%",
"actual": None,
"description": "Federal Reserve interest rate decision",
"importance": 3,
},
{
"id": 5,
"country": "EUR",
"indicator": "ECB Interest Rate Decision",
"event_date": (datetime.now() + timedelta(days=10)).isoformat(),
"time": "12:45",
"impact": "high",
"forecast": "4.50%",
"previous": "4.50%",
"actual": None,
"description": "European Central Bank rate decision",
"importance": 3,
},
{
"id": 6,
"country": "US",
"indicator": "ISM Manufacturing PMI",
"event_date": (datetime.now() + timedelta(days=2)).isoformat(),
"time": "09:00",
"impact": "medium",
"forecast": "49.5",
"previous": "49.0",
"actual": None,
"description": "Manufacturing sector activity indicator",
"importance": 2,
},
{
"id": 7,
"country": "US",
"indicator": "Initial Jobless Claims",
"event_date": (datetime.now() + timedelta(days=3)).isoformat(),
"time": "08:30",
"impact": "medium",
"forecast": "215000",
"previous": "216000",
"actual": None,
"description": "Weekly unemployment benefit applications",
"importance": 2,
},
{
"id": 8,
"country": "US",
"indicator": "Retail Sales",
"event_date": (datetime.now() + timedelta(days=7)).isoformat(),
"time": "12:30",
"impact": "medium",
"forecast": "0.4%",
"previous": "0.7%",
"actual": None,
"description": "Consumer spending and retail activity",
"importance": 2,
},
]
@router.get("/events")
async def get_economic_events(
days_ahead: int = Query(30, ge=1, le=180),
countries: Optional[str] = Query(None),
impact: Optional[str] = Query(None, regex="^(high|medium|low)$"),
sort_by: str = Query("date", regex="^(date|importance|impact)$"),
):
"""
Get upcoming economic calendar events
- **days_ahead**: Number of days to look ahead (1-180)
- **countries**: Comma-separated country codes (US, EUR, GBP, JPY, etc.)
- **impact**: Filter by impact level (high, medium, low)
- **sort_by**: Sort results by date, importance, or impact
"""
events = SAMPLE_EVENTS.copy()
# Filter by countries
if countries:
country_list = [c.strip() for c in countries.split(",")]
events = [e for e in events if e["country"] in country_list]
# Filter by impact
if impact:
impact_map = {"high": 3, "medium": 2, "low": 1}
events = [e for e in events if e["importance"] == impact_map.get(impact, 2)]
# Filter by days ahead
cutoff_date = datetime.now() + timedelta(days=days_ahead)
events = [
e
for e in events
if datetime.fromisoformat(e["event_date"]) <= cutoff_date
]
# Sort
if sort_by == "importance":
events.sort(key=lambda x: x["importance"], reverse=True)
elif sort_by == "impact":
impact_order = {"high": 3, "medium": 2, "low": 1}
events.sort(key=lambda x: impact_order.get(x["impact"], 1), reverse=True)
else: # date
events.sort(key=lambda x: x["event_date"])
return {
"total": len(events),
"events": events,
"filter_applied": {
"days_ahead": days_ahead,
"countries": countries,
"impact": impact,
},
}
@router.get("/today")
async def get_today_events():
"""Get economic events scheduled for today"""
today = datetime.now().date()
today_start = datetime.combine(today, datetime.min.time()).isoformat()
today_end = datetime.combine(today, datetime.max.time()).isoformat()
events = [
e
for e in SAMPLE_EVENTS
if today_start <= e["event_date"] <= today_end
]
return {
"date": today.isoformat(),
"total": len(events),
"events": events,
}
@router.get("/upcoming")
async def get_upcoming_events(hours: int = Query(24, ge=1, le=168)):
"""
Get upcoming events within specified hours
- **hours**: Number of hours ahead to check (1-168 hours = 1-7 days)
"""
now = datetime.now()
cutoff = now + timedelta(hours=hours)
events = [
e
for e in SAMPLE_EVENTS
if now <= datetime.fromisoformat(e["event_date"]) <= cutoff
]
# Sort by time
events.sort(key=lambda x: x["event_date"])
return {
"now": now.isoformat(),
"hours_ahead": hours,
"total": len(events),
"events": events,
}
@router.get("/high-impact")
async def get_high_impact_events():
"""Get only high-impact economic events for the next 30 days"""
cutoff = datetime.now() + timedelta(days=30)
events = [
e
for e in SAMPLE_EVENTS
if e["importance"] == 3
and datetime.fromisoformat(e["event_date"]) <= cutoff
]
events.sort(key=lambda x: x["event_date"])
return {
"total": len(events),
"events": events,
"note": "Only high-impact events that could significantly move gold prices",
}
@router.get("/by-country/{country}")
async def get_country_events(
country: str, days: int = Query(30, ge=1, le=180)
):
"""
Get economic events for a specific country
- **country**: Country code (US, EUR, GBP, JPY, CHF, CAD, AUD, NZD, etc.)
- **days**: Days to look ahead
"""
cutoff = datetime.now() + timedelta(days=days)
events = [
e
for e in SAMPLE_EVENTS
if e["country"].upper() == country.upper()
and datetime.fromisoformat(e["event_date"]) <= cutoff
]
if not events:
raise HTTPException(
status_code=404, detail=f"No events found for country: {country}"
)
events.sort(key=lambda x: x["event_date"])
return {
"country": country.upper(),
"days": days,
"total": len(events),
"events": events,
}
@router.get("/impact-analysis")
async def get_impact_analysis():
"""
Analyze economic impact on gold prices
Returns analysis of how different economic indicators
typically affect gold trading
"""
return {
"gold_trading_impact": {
"high_impact": {
"indicators": [
"Interest Rate Decisions",
"Inflation Data",
"Employment Reports",
"GDP Growth",
],
"typical_response": "Gold typically moves 100-200 pips on high-impact events",
"best_time": "Around event release time",
},
"medium_impact": {
"indicators": [
"PMI Indices",
"Consumer Confidence",
"Retail Sales",
"Producer Prices",
],
"typical_response": "Gold typically moves 50-100 pips",
"best_time": "Watch 5-30 mins after release",
},
"low_impact": {
"indicators": [
"Housing Starts",
"Factory Orders",
"Building Permits",
],
"typical_response": "Gold rarely moves significantly",
"best_time": "Usually skipped by day traders",
},
},
"inverse_correlation": {
"US_Dollar_Strength": "Strong dollar typically weakens gold (inverse correlation)",
"Interest_Rates": "Higher rates reduce gold appeal (inverse correlation)",
"Risk_Appetite": "Risk-on environment weakens gold demand",
"Inflation": "High inflation supports higher gold prices",
},
"trading_tips": [
"Trade 30 mins after high-impact events when volatility settles",
"Avoid trading during overlapping Fed/ECB announcements",
"Watch preliminary indicators before main events",
"Check gold correlation with USD index and bond yields",
"Set wider stops during high-impact event windows",
],
}
@router.get("/calendar-view")
async def get_calendar_view(
month: Optional[int] = Query(None, ge=1, le=12),
year: Optional[int] = Query(None),
):
"""
Get economic calendar in calendar view format
- **month**: Specific month (1-12), defaults to current month
- **year**: Specific year, defaults to current year
"""
now = datetime.now()
view_month = month or now.month
view_year = year or now.year
calendar_events = {}
for event in SAMPLE_EVENTS:
event_date = datetime.fromisoformat(event["event_date"])
if (
event_date.month == view_month
and event_date.year == view_year
):
day = event_date.day
if day not in calendar_events:
calendar_events[day] = []
calendar_events[day].append(
{
"indicator": event["indicator"],
"time": event["time"],
"impact": event["impact"],
"country": event["country"],
}
)
return {
"month": view_month,
"year": view_year,
"calendar": calendar_events,
"month_name": datetime(view_year, view_month, 1).strftime("%B"),
}
@router.post("/events/{event_id}/notify")
async def set_event_notification(event_id: int, minutes_before: int = Query(30)):
"""
Set a notification reminder for an economic event
- **event_id**: ID of the economic event
- **minutes_before**: Notify X minutes before event (15-120)
"""
event = next((e for e in SAMPLE_EVENTS if e["id"] == event_id), None)
if not event:
raise HTTPException(status_code=404, detail="Event not found")
return {
"status": "notification_set",
"event": event["indicator"],
"notify_minutes_before": minutes_before,
"event_time": event["event_date"],
"notification_time": (
datetime.fromisoformat(event["event_date"])
- timedelta(minutes=minutes_before)
).isoformat(),
}
@router.get("/stats")
async def get_economic_calendar_stats():
"""Get statistics about upcoming economic events"""
now = datetime.now()
next_7_days = now + timedelta(days=7)
next_30_days = now + timedelta(days=30)
events_7 = [
e
for e in SAMPLE_EVENTS
if now <= datetime.fromisoformat(e["event_date"]) <= next_7_days
]
events_30 = [
e
for e in SAMPLE_EVENTS
if now <= datetime.fromisoformat(e["event_date"]) <= next_30_days
]
high_impact = [e for e in events_30 if e["importance"] == 3]
return {
"summary": {
"total_events_30_days": len(events_30),
"total_events_7_days": len(events_7),
"high_impact_events": len(high_impact),
"total_countries": len(set(e["country"] for e in events_30)),
},
"by_impact": {
"high": len([e for e in events_30 if e["importance"] == 3]),
"medium": len([e for e in events_30 if e["importance"] == 2]),
"low": len([e for e in events_30 if e["importance"] == 1]),
},
"busiest_days": sorted(
[
(
e["event_date"].split("T")[0],
len(
[
x
for x in events_30
if x["event_date"].split("T")[0] == e["event_date"].split("T")[0]
]
),
)
for e in events_30
],
key=lambda x: x[1],
reverse=True,
)[:5],
}
+2 -1
View File
@@ -7,7 +7,7 @@ from app.streaming.live_store import periodic_flush, periodic_maintenance
import asyncio import asyncio
# Newly added routers # Newly added routers
from app.api import account, performance, status, settings_api, prompts, daily_helper, analytics from app.api import account, performance, status, settings_api, prompts, daily_helper, analytics, economic_calendar
app = FastAPI( app = FastAPI(
title=settings.APP_NAME, title=settings.APP_NAME,
@@ -43,6 +43,7 @@ app.include_router(settings_api.router, prefix="/api")
app.include_router(prompts.router, prefix="/api") app.include_router(prompts.router, prefix="/api")
app.include_router(daily_helper.router) app.include_router(daily_helper.router)
app.include_router(analytics.router) app.include_router(analytics.router)
app.include_router(economic_calendar.router)
@app.on_event("startup") @app.on_event("startup")
+6 -2
View File
@@ -17,6 +17,9 @@ import DailyChecklistPanel from './components/DailyChecklistPanel'
// Phase 3: Advanced Analytics Components // Phase 3: Advanced Analytics Components
import AnalyticsDashboard from './components/AnalyticsDashboard' import AnalyticsDashboard from './components/AnalyticsDashboard'
// Phase 4: Economic Calendar & Advanced Features
import EconomicCalendar from './components/EconomicCalendar'
function Tabs({ tabs, active, onChange }: { tabs: string[]; active: string; onChange: (t: string) => void }) { function Tabs({ tabs, active, onChange }: { tabs: string[]; active: string; onChange: (t: string) => void }) {
return ( return (
<div style={{ display: 'flex', gap: 8, marginBottom: 12 }}> <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
@@ -30,7 +33,7 @@ function Tabs({ tabs, active, onChange }: { tabs: string[]; active: string; onCh
} }
export default function App() { export default function App() {
const [activeTab, setActiveTab] = useState<'Live' | 'Account' | 'Equity' | 'Decisions' | 'Analytics' | 'Settings' | 'Prompts' | 'Daily Helper'>('Live') const [activeTab, setActiveTab] = useState<'Live' | 'Account' | 'Equity' | 'Decisions' | 'Analytics' | 'Economic Calendar' | 'Settings' | 'Prompts' | 'Daily Helper'>('Live')
const [backendStatus, setBackendStatus] = useState<any>(null) const [backendStatus, setBackendStatus] = useState<any>(null)
const [showProfileSetup, setShowProfileSetup] = useState(false) const [showProfileSetup, setShowProfileSetup] = useState(false)
@@ -47,7 +50,7 @@ export default function App() {
return () => { mounted = false } return () => { mounted = false }
}, []) }, [])
const tabs = ['Live', 'Account', 'Equity', 'Decisions', 'Analytics', 'Daily Helper', 'Settings', 'Prompts'] const tabs = ['Live', 'Account', 'Equity', 'Decisions', 'Analytics', 'Economic Calendar', 'Daily Helper', 'Settings', 'Prompts']
return ( return (
<div className="min-h-screen bg-dark-bg p-6"> <div className="min-h-screen bg-dark-bg p-6">
@@ -84,6 +87,7 @@ export default function App() {
{activeTab === 'Equity' && <EquityPerformancePanel />} {activeTab === 'Equity' && <EquityPerformancePanel />}
{activeTab === 'Decisions' && <DecisionLogPanel />} {activeTab === 'Decisions' && <DecisionLogPanel />}
{activeTab === 'Analytics' && <AnalyticsDashboard />} {activeTab === 'Analytics' && <AnalyticsDashboard />}
{activeTab === 'Economic Calendar' && <EconomicCalendar />}
{activeTab === 'Daily Helper' && ( {activeTab === 'Daily Helper' && (
<div style={{ display: 'grid', gap: 16, gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))' }}> <div style={{ display: 'grid', gap: 16, gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))' }}>
@@ -0,0 +1,307 @@
import { useEffect, useState } from 'react';
import { Calendar, AlertTriangle, TrendingUp, Clock, Globe } from 'lucide-react';
import axios from 'axios';
interface EconomicEvent {
id: number;
country: string;
indicator: string;
event_date: string;
time: string;
impact: 'high' | 'medium' | 'low';
forecast: string;
previous: string;
actual: string | null;
description: string;
importance: number;
}
interface EventStats {
total_events_30_days: number;
total_events_7_days: number;
high_impact_events: number;
total_countries: number;
}
export default function EconomicCalendar() {
const [events, setEvents] = useState<EconomicEvent[]>([]);
const [highImpactEvents, setHighImpactEvents] = useState<EconomicEvent[]>([]);
const [stats, setStats] = useState<EventStats | null>(null);
const [loading, setLoading] = useState(true);
const [activeTab, setActiveTab] = useState<'upcoming' | 'today' | 'high-impact'>('upcoming');
const [selectedCountry, setSelectedCountry] = useState<string | null>(null);
// Fetch events and stats
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
// Fetch upcoming events
const upcomingResponse = await axios.get('/api/economic-calendar/events', {
params: { days_ahead: 30, sort_by: 'date' },
});
setEvents(upcomingResponse.data.events || []);
// Fetch high impact events
const highImpactResponse = await axios.get('/api/economic-calendar/high-impact');
setHighImpactEvents(highImpactResponse.data.events || []);
// Fetch stats
const statsResponse = await axios.get('/api/economic-calendar/stats');
setStats(statsResponse.data.summary || null);
} catch (error) {
console.error('Error fetching economic calendar data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const getImpactColor = (impact: string): string => {
switch (impact) {
case 'high':
return 'bg-red-900 text-red-300 border-red-700';
case 'medium':
return 'bg-yellow-900 text-yellow-300 border-yellow-700';
default:
return 'bg-blue-900 text-blue-300 border-blue-700';
}
};
const getImpactBorder = (impact: string): string => {
switch (impact) {
case 'high':
return 'border-l-4 border-red-500';
case 'medium':
return 'border-l-4 border-yellow-500';
default:
return 'border-l-4 border-blue-500';
}
};
const formatDateTime = (isoDate: string, time: string): string => {
const date = new Date(isoDate);
return `${date.toLocaleDateString()} at ${time}`;
};
const displayedEvents = activeTab === 'high-impact' ? highImpactEvents : events;
const filteredEvents = selectedCountry
? displayedEvents.filter((e) => e.country === selectedCountry)
: displayedEvents;
const countries = Array.from(new Set(events.map((e) => e.country))).sort();
if (loading) {
return (
<div className="card">
<h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
<Calendar className="w-5 h-5 text-blue-500" />
Economic Calendar
</h3>
<div className="text-center text-gray-400 py-8">Loading calendar...</div>
</div>
);
}
return (
<div className="space-y-4">
{/* Stats Overview */}
{stats && (
<div className="card">
<h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-blue-500" />
Calendar Overview (Next 30 Days)
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
<div className="bg-dark-bg rounded-lg p-3 border border-dark-border">
<p className="text-xs text-gray-400 mb-1">Total Events</p>
<p className="text-2xl font-bold text-blue-500">{stats.total_events_30_days}</p>
</div>
<div className="bg-dark-bg rounded-lg p-3 border border-dark-border">
<p className="text-xs text-gray-400 mb-1">High Impact</p>
<p className="text-2xl font-bold text-red-500">{stats.high_impact_events}</p>
</div>
<div className="bg-dark-bg rounded-lg p-3 border border-dark-border">
<p className="text-xs text-gray-400 mb-1">Next 7 Days</p>
<p className="text-2xl font-bold text-yellow-500">{stats.total_events_7_days}</p>
</div>
<div className="bg-dark-bg rounded-lg p-3 border border-dark-border">
<p className="text-xs text-gray-400 mb-1">Countries</p>
<p className="text-2xl font-bold text-green-500">{stats.total_countries}</p>
</div>
</div>
</div>
)}
{/* Main Calendar */}
<div className="card">
<div className="mb-4">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold flex items-center gap-2">
<Calendar className="w-5 h-5 text-blue-500" />
Economic Events
</h3>
</div>
{/* Tabs */}
<div className="flex gap-2 mb-4">
<button
onClick={() => setActiveTab('upcoming')}
className={`px-4 py-2 rounded-lg font-medium transition ${
activeTab === 'upcoming'
? 'bg-blue-600 text-white'
: 'bg-dark-bg text-gray-400 hover:text-gray-200 border border-dark-border'
}`}
>
Upcoming ({events.length})
</button>
<button
onClick={() => setActiveTab('high-impact')}
className={`px-4 py-2 rounded-lg font-medium transition ${
activeTab === 'high-impact'
? 'bg-red-600 text-white'
: 'bg-dark-bg text-gray-400 hover:text-gray-200 border border-dark-border'
}`}
>
<AlertTriangle className="w-4 h-4 inline mr-2" />
High Impact ({highImpactEvents.length})
</button>
</div>
{/* Country Filter */}
<div className="mb-4">
<label className="text-sm text-gray-400 mb-2 block">Filter by Country:</label>
<div className="flex gap-2 flex-wrap">
<button
onClick={() => setSelectedCountry(null)}
className={`px-3 py-1 rounded text-sm transition ${
selectedCountry === null
? 'bg-blue-600 text-white'
: 'bg-dark-bg text-gray-400 hover:text-gray-200 border border-dark-border'
}`}
>
All Countries
</button>
{countries.map((country) => (
<button
key={country}
onClick={() => setSelectedCountry(selectedCountry === country ? null : country)}
className={`px-3 py-1 rounded text-sm transition ${
selectedCountry === country
? 'bg-blue-600 text-white'
: 'bg-dark-bg text-gray-400 hover:text-gray-200 border border-dark-border'
}`}
>
{country}
</button>
))}
</div>
</div>
</div>
{/* Events List */}
<div className="space-y-3 max-h-96 overflow-y-auto">
{filteredEvents.length > 0 ? (
filteredEvents.map((event) => (
<div
key={event.id}
className={`bg-dark-bg rounded-lg p-4 border ${getImpactBorder(event.impact)}`}
>
<div className="flex items-start justify-between mb-2">
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h4 className="font-semibold text-gray-200">{event.indicator}</h4>
<span
className={`text-xs px-2 py-1 rounded border ${getImpactColor(event.impact)}`}
>
{event.impact.toUpperCase()}
</span>
<span className="text-xs bg-gray-700 text-gray-300 px-2 py-1 rounded">
<Globe className="w-3 h-3 inline mr-1" />
{event.country}
</span>
</div>
<p className="text-sm text-gray-400 mb-2">{event.description}</p>
</div>
</div>
<div className="grid grid-cols-3 gap-3 mb-3 text-sm">
<div>
<p className="text-xs text-gray-500 mb-1">Forecast</p>
<p className="font-semibold text-blue-400">{event.forecast}</p>
</div>
<div>
<p className="text-xs text-gray-500 mb-1">Previous</p>
<p className="font-semibold text-gray-300">{event.previous}</p>
</div>
<div>
<p className="text-xs text-gray-500 mb-1">Actual</p>
<p className={`font-semibold ${event.actual ? 'text-green-400' : 'text-gray-500'}`}>
{event.actual || 'Pending'}
</p>
</div>
</div>
<div className="flex items-center gap-3 text-xs text-gray-400 pt-2 border-t border-dark-border">
<Clock className="w-4 h-4" />
<span>{formatDateTime(event.event_date, event.time)}</span>
</div>
</div>
))
) : (
<p className="text-center text-gray-400 py-4">No events found</p>
)}
</div>
</div>
{/* Trading Tips */}
<div className="card">
<h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
<AlertTriangle className="w-5 h-5 text-yellow-500" />
Gold Trading Tips During Economic Events
</h3>
<div className="space-y-3">
<div className="bg-red-900 bg-opacity-20 border border-red-800 rounded-lg p-3">
<p className="text-sm text-red-400 font-semibold mb-1">🔴 High-Impact Events</p>
<p className="text-xs text-gray-300">
Gold typically moves 100-200 pips. Set wider stops and consider doubling
position size around event release time.
</p>
</div>
<div className="bg-yellow-900 bg-opacity-20 border border-yellow-800 rounded-lg p-3">
<p className="text-sm text-yellow-400 font-semibold mb-1">🟡 Medium-Impact Events</p>
<p className="text-xs text-gray-300">
Gold typically moves 50-100 pips. Wait 5-30 mins after release before
trading to let volatility settle.
</p>
</div>
<div className="bg-blue-900 bg-opacity-20 border border-blue-800 rounded-lg p-3">
<p className="text-sm text-blue-400 font-semibold mb-1">🔵 Key Correlations</p>
<p className="text-xs text-gray-300">
Strong USD weakens gold (inverse). High rates reduce gold appeal. Watch
DXY and bond yields for context.
</p>
</div>
<div className="bg-green-900 bg-opacity-20 border border-green-800 rounded-lg p-3">
<p className="text-sm text-green-400 font-semibold mb-1"> Best Practice</p>
<p className="text-xs text-gray-300">
Always check: 1) Event importance 2) USD impact 3) Historical volatility
4) Current gold sentiment before trading.
</p>
</div>
</div>
</div>
</div>
);
}