Repository navigation
fix: ReflectorService uses random price variation instead of static fallback when oracle is down #61
Description
Problem
When the Reflector oracle is unavailable or returns stale data, ReflectorService in backend/src/services/reflector.ts falls back to random price variation instead of using the last known good price. This makes portfolio values jitter randomly whenever the oracle hiccups.
The fallback logic does something like:
// When Reflector is unavailable
const basePrice = lastKnownPrice || hardcodedPrice;
const variation = (Math.random() - 0.5) * 0.02; // ±1% random noise
return basePrice * (1 + variation);This means:
- Portfolio values fluctuate even when no trades happen
- Rebalancing triggers can fire based on phantom price movements (the random variation might push a portfolio past its drift threshold)
- Risk metrics (VaR, volatility) are computed on noise, not real data
- The circuit breaker might trigger unnecessarily
Proposed Fix
1. Use last known price with no variation
When the oracle is down, return the last successfully fetched price with zero variation:
async getPrice(asset: string): Promise<PriceData> {
try {
const price = await this.fetchFromReflector(asset);
this.cachePrice(asset, price); // store for fallback
return price;
} catch (error) {
const cached = this.getLastKnownPrice(asset);
if (cached) {
logger.warn(`Reflector unavailable for ${asset}, using cached price from ${cached.timestamp}`);
return { ...cached, source: 'cached', stale: true };
}
throw new Error(`No price data available for ${asset}`);
}
}2. Track staleness
Each cached price should have a timestamp. If the cached price is older than a configurable threshold (e.g., 1 hour), mark it as stale: true so downstream consumers can decide how to handle it:
- Portfolio value calculations: use stale prices but show a "stale data" indicator
- Rebalancing decisions: skip rebalancing if any asset price is stale (don't trade on bad data)
- Risk metrics: pause VaR/volatility calculations if prices are stale
3. Cache prices in the database
Currently prices might only be cached in memory. Store them in PostgreSQL so they survive restarts:
CREATE TABLE IF NOT EXISTS price_cache (
asset VARCHAR(32) PRIMARY KEY,
price NUMERIC(20, 8) NOT NULL,
source VARCHAR(32) NOT NULL,
fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);The analyticsSnapshotWorker already runs periodically — have it also refresh the price cache.
4. Graceful degradation in the frontend
When the backend returns prices with stale: true, the frontend should:
- Show a yellow warning banner: "Price data may be outdated"
- Disable the "Rebalance Now" button
- Still show portfolio value but with a lower opacity or asterisk
Files to modify
backend/src/services/reflector.ts— replace random variation with cached fallback, add staleness trackingbackend/src/db/— addprice_cachetable and query methodsbackend/src/services/rebalancing.ts— skip rebalancing when prices are stalebackend/src/services/riskManagements.ts— pause risk calculations when prices are stalefrontend/src/components/Dashboard.tsx— show stale data indicatorfrontend/src/components/PriceTracker.tsx— show last-updated timestamp
Acceptance Criteria
- ReflectorService returns cached price when oracle is down (no random variation)
- Cached prices include a timestamp and staleness flag
- Prices older than 1 hour are marked as
stale: true - Rebalancing is skipped when any price is stale
- Risk calculations are paused when prices are stale
- Frontend shows a warning when using stale prices
- Price cache persists across backend restarts (stored in PostgreSQL)
- No phantom rebalancing triggers from random price noise
References
- Reflector service:
backend/src/services/reflector.ts - Risk management:
backend/src/services/riskManagements.ts - Rebalancing:
backend/src/services/rebalancing.ts - Related issue (was Use static fallback prices instead of random variation in ReflectorService #48): use static fallback prices
Affected Area
Backend, Frontend
Activity
bernardev254 commentedon Aug 22, 2026
I’d like to fix the Reflector oracle fallback logic to use cached prices instead of random variations. I’ll implement staleness tracking, store prices in PostgreSQL, and ensure graceful degradation in the frontend (e.g., warnings for stale data, disabling rebalancing). This will prevent phantom price fluctuations and improve reliability
brightpixel-dev commentedon Aug 22, 2026
Please assign this issue to me
grantfox-oss commentedon Aug 22, 2026
🦊 GrantFox — @brightpixel-dev has been assigned to this issue as part of the Third Campaign campaign!
Next steps:
Closes #61)Good luck! Track your progress on GrantFox.
grantfox-oss commentedon Aug 22, 2026
🎉 This issue has been marked as completed on GrantFox as part of the Third Campaign campaign!
@brightpixel-dev's PR #67 was approved and merged by @Uchechukwu-Ekezie.
🏆 @brightpixel-dev: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (952 total points). Track your full progress on GrantFox.
👏 Great work, @brightpixel-dev! Keep contributing to grantFoxin.