Problem
The calculateDayChange function in backend/src/services/analyticsService.ts doesn't use actual price history — it returns a random percentage. The frontend's performance chart and portfolio analytics show made-up numbers.
Looking at the implementation:
// TODO: Replace with actual price history lookup
const dayChange = (Math.random() - 0.5) * 10; // -5% to +5%
Every time the analytics endpoint is called, the "24h change" is a different random number. This makes the analytics dashboard useless for actual portfolio tracking. The PerformanceChart component in frontend/src/components/PerformanceChart.tsx renders a chart based on this data, but the chart is just noise.
Proposed Fix
1. Store price snapshots
The backend already has an analytics_snapshots table that records portfolio values over time. The analyticsService should query this table to compute real day-over-day change:
async calculateDayChange(portfolioId: string): Promise<number> {
const now = new Date();
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const latest = await analyticsDb.getLatestSnapshot(portfolioId);
const previous = await analyticsDb.getSnapshotAt(portfolioId, oneDayAgo);
if (!latest || !previous || previous.totalValue === 0) return 0;
return ((latest.totalValue - previous.totalValue) / previous.totalValue) * 100;
}
2. Ensure snapshots are being recorded
The analyticsSnapshotWorker in backend/src/queue/workers/analyticsSnapshotWorker.ts should be recording snapshots regularly. Verify it's running and storing data. If it's not, fix the worker or add a fallback that records snapshots on portfolio check.
3. Interpolate if no exact 24h snapshot exists
If there's no snapshot exactly 24 hours ago, find the closest one within a 2-hour window and interpolate:
const previous = await analyticsDb.getClosestSnapshot(portfolioId, oneDayAgo, 2 * 60 * 60 * 1000);
If no snapshot exists within the window, return null instead of a random number. The frontend should show "—" or "N/A" instead of fake data.
4. Extend to other time periods
Once 24h change works, add the same pattern for:
- 7-day change
- 30-day change
- All-time change (from first snapshot)
Files to modify
backend/src/services/analyticsService.ts — replace random calculation with real query
backend/src/db/analyticsDb.ts — add getSnapshotAt and getClosestSnapshot query methods
frontend/src/components/PerformanceChart.tsx — handle null change values gracefully
frontend/src/components/Dashboard.tsx — show "—" when change data isn't available
Acceptance Criteria
References
Affected Area
Backend, Frontend
Checklist
Problem
The
calculateDayChangefunction inbackend/src/services/analyticsService.tsdoesn't use actual price history — it returns a random percentage. The frontend's performance chart and portfolio analytics show made-up numbers.Looking at the implementation:
Every time the analytics endpoint is called, the "24h change" is a different random number. This makes the analytics dashboard useless for actual portfolio tracking. The
PerformanceChartcomponent infrontend/src/components/PerformanceChart.tsxrenders a chart based on this data, but the chart is just noise.Proposed Fix
1. Store price snapshots
The backend already has an
analytics_snapshotstable that records portfolio values over time. TheanalyticsServiceshould query this table to compute real day-over-day change:2. Ensure snapshots are being recorded
The
analyticsSnapshotWorkerinbackend/src/queue/workers/analyticsSnapshotWorker.tsshould be recording snapshots regularly. Verify it's running and storing data. If it's not, fix the worker or add a fallback that records snapshots on portfolio check.3. Interpolate if no exact 24h snapshot exists
If there's no snapshot exactly 24 hours ago, find the closest one within a 2-hour window and interpolate:
If no snapshot exists within the window, return
nullinstead of a random number. The frontend should show "—" or "N/A" instead of fake data.4. Extend to other time periods
Once 24h change works, add the same pattern for:
Files to modify
backend/src/services/analyticsService.ts— replace random calculation with real querybackend/src/db/analyticsDb.ts— addgetSnapshotAtandgetClosestSnapshotquery methodsfrontend/src/components/PerformanceChart.tsx— handlenullchange values gracefullyfrontend/src/components/Dashboard.tsx— show "—" when change data isn't availableAcceptance Criteria
calculateDayChangereturns the actual percentage change from 24 hours agonullReferences
backend/src/services/analyticsService.tsbackend/src/db/analyticsDb.tsbackend/src/queue/workers/analyticsSnapshotWorker.tsfrontend/src/components/PerformanceChart.tsxAffected Area
Backend, Frontend
Checklist