# Current Price Fix - Yahoo Finance API Update
## Date
December 13, 2025
## Problem
**Current Price** column in Holdings page was showing ₹0 for all stocks.
## Root Cause
Yahoo Finance blocked their **v7/finance/quote** API endpoint (401 Unauthorized error).
This is a common issue in late 2024/2025 as Yahoo Finance tightened access to their free API endpoints.
## Solution Applied ✅
### Changed Yahoo Finance API Endpoint
**From (Old - Blocked):**
```
https://query1.finance.yahoo.com/v7/finance/quote?symbols=RELIANCE.NS,TCS.NS
```
**To (New - Working):**
```
https://query1.finance.yahoo.com/v8/finance/chart/RELIANCE.NS?interval=1d&range=1d
```
### Key Changes
#### 1. API Endpoint Switch
- **Old**: v7/quote (batch requests, now blocked)
- **New**: v8/chart (individual requests, still working)
#### 2. Request Method
- **Old**: Batch all symbols in one request
- **New**: Fetch each symbol individually with 100ms delay
#### 3. Price Extraction
- **Old**: `data.quoteResponse.result[i].regularMarketPrice`
- **New**: `data.chart.result[0].meta.regularMarketPrice`
#### 4. Headers Updated
Added more browser-like headers to avoid detection:
```typescript
{
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': '*/*',
'Accept-Language': 'en-US,en;q=0.9',
'Referer': 'https://finance.yahoo.com',
}
```
## Files Modified
### 1. `equity/lib/yahoo-finance.ts`
- Updated `getCurrentPrices()` function
- Changed from v7/quote to v8/chart endpoint
- Changed from batch requests to individual requests
- Updated headers for better success rate
- Added fallback to previousClose if regularMarketPrice unavailable
### 2. `equity/app/api/stats/route.ts`
- Added detailed logging to track which symbols are being fetched
- Added warnings for symbols with missing/zero prices
- Helps diagnose issues in production
## Test Results
### Before Fix:
```
Response Status: 401 Unauthorized
❌ All prices showing as ₹0
```
### After Fix:
```
Response Status: 200 OK
✅ RELIANCE: ₹1556.50
✅ Market State: REGULAR
✅ Currency: INR
```
## Performance Impact
### Before (Batch):
- 100 symbols = 1 request
- Fast, but blocked by Yahoo
### After (Individual):
- 100 symbols = 100 requests
- ~100ms delay between each = ~10 seconds total
- Slightly slower but works reliably
### Optimization Recommendations:
1. **Implement Caching** (5-minute cache):
- First load: Fetches from Yahoo Finance
- Subsequent loads: Uses cached prices
- Reduces API calls by 90%
2. **Background Refresh**:
- Update prices in background every 5 minutes
- User always sees cached (fast) prices
- Never waits for Yahoo Finance
3. **Parallel Requests** (if needed):
- Currently sequential to avoid rate limiting
- Can be parallelized with 3-5 concurrent requests
- Reduces 10 seconds to 3-4 seconds
## How It Works Now
### Flow:
```
1. Holdings Page loads
↓
2. API calls /api/stats
↓
3. Gets symbols from database: ['RELIANCE', 'TCS', 'INFY', ...]
↓
4. For each symbol:
- Fetch https://query1.finance.yahoo.com/v8/finance/chart/RELIANCE.NS
- Extract: data.chart.result[0].meta.regularMarketPrice
- Store: { 'RELIANCE': 1556.50 }
- Wait 100ms (rate limiting)
↓
5. Returns prices: { 'RELIANCE': 1556.50, 'TCS': 3800.00, ... }
↓
6. Calculate:
- Current Value = Quantity × Current Price
- Unrealized P&L = Current Value - Cost Basis
↓
7. Display in Holdings table
```
### Server Logs (Normal):
```
[Stats API] Fetching prices for 5 symbols: [ 'RELIANCE', 'TCS', 'INFY', 'HDFCBANK', 'ICICIBANK' ]
[YahooFinance] Fetching prices for 5 symbols...
[YahooFinance] RELIANCE: ₹1556.50
[YahooFinance] TCS: ₹3800.25
[YahooFinance] INFY: ₹1450.80
[YahooFinance] HDFCBANK: ₹1600.00
[YahooFinance] ICICIBANK: ₹950.50
[Stats API] Prices received: { RELIANCE: 1556.5, TCS: 3800.25, INFY: 1450.8, ... }
```
### Server Logs (With Issues):
```
[Stats API] Fetching prices for 5 symbols: [ 'RELIANCE', 'TCS', 'BADSTOCK', ... ]
[YahooFinance] Fetching prices for 5 symbols...
[YahooFinance] RELIANCE: ₹1556.50
[YahooFinance] TCS: ₹3800.25
[YahooFinance] HTTP error for BADSTOCK: 404
[YahooFinance] No price data for BADSTOCK
[Stats API] Prices received: { RELIANCE: 1556.5, TCS: 3800.25, BADSTOCK: 0 }
[Stats API] ⚠️ Symbols with 0 or missing prices: [ 'BADSTOCK' ]
```
## Symbol Format
Yahoo Finance requires `.NS` suffix for NSE stocks:
| Your Symbol | Yahoo Symbol | Status |
|-------------|--------------|--------|
| RELIANCE | RELIANCE.NS | ✅ Works |
| TCS | TCS.NS | ✅ Works |
| INFY | INFY.NS | ✅ Works |
| HDFCBANK | HDFCBANK.NS | ✅ Works |
**BSE Alternative:**
If NSE doesn't work, use `.BO` suffix:
```typescript
await getYahooPrices(symbols, 'BSE') // Uses .BO suffix
```
## Testing
### Quick Test:
```bash
cd equity
node test-yahoo-prices.js
```
Expected output:
```
✅ Price Found:
RELIANCE: ₹1556.50
Market State: REGULAR
Currency: INR
```
### Full Test:
1. Navigate to Holdings page
2. Check server console for logs
3. Verify prices show in "Current Price" column
4. Verify "Current Value" = Quantity × Current Price
5. Verify "Unrealized P&L" calculates correctly
## Troubleshooting
### Still Showing ₹0?
**Check 1: Server Logs**
Look for error messages in your Next.js server console.
**Check 2: Symbol Format**
Ensure your symbols match Yahoo Finance format:
- Visit: https://finance.yahoo.com/quote/RELIANCE.NS
- If "Symbol not found", stock doesn't exist on Yahoo
**Check 3: Network**
Test direct API access:
```bash
curl "https://query1.finance.yahoo.com/v8/finance/chart/RELIANCE.NS?interval=1d&range=1d"
```
**Check 4: Rate Limiting**
If you have many symbols (>50), Yahoo might rate limit. Add delays:
```typescript
// In yahoo-finance.ts, increase delay
await new Promise(resolve => setTimeout(resolve, 200)); // 200ms instead of 100ms
```
## Known Limitations
### 1. Individual Requests are Slower
- **Solution**: Implement caching (see recommendations above)
### 2. Yahoo Finance May Block Again
- **Fallback**: Have alternative price sources ready
- **Options**:
- Alpha Vantage (500 free calls/day)
- NSE official API (requires registration)
- Manual price entry feature
### 3. Market Closed = Previous Close
- **Behavior**: When market is closed, shows previous day's close price
- **Solution**: Add timestamp showing "Last updated: 3:30 PM IST"
### 4. Some Stocks May Not Exist
- **Behavior**: Shows ₹0 if stock not found on Yahoo Finance
- **Solution**: Log warnings, allow manual price entry
## Future Enhancements
### 1. Price Caching (Recommended)
```typescript
// Cache prices for 5 minutes
const cache = new Map<string, {price: number, timestamp: number}>();
function getCachedPrice(symbol: string) {
const cached = cache.get(symbol);
if (cached && Date.now() - cached.timestamp < 300000) {
return cached.price;
}
return null;
}
```
### 2. Background Refresh
```typescript
// Update prices every 5 minutes in background
setInterval(async () => {
await updatePricesInBackground();
}, 5 * 60 * 1000);
```
### 3. WebSocket Real-time Prices
For live market tracking, consider WebSocket connection to NSE/BSE.
### 4. Multiple Price Sources
Fetch from multiple sources and use first successful response:
```typescript
const price = await getPrice(symbol)
.catch(() => getBackupPrice(symbol))
.catch(() => getManualPrice(symbol))
.catch(() => 0);
```
## Summary
✅ **Root Cause**: Yahoo Finance v7 API blocked (401 error)
✅ **Solution**: Switched to v8/chart endpoint
✅ **Status**: Working - prices now load successfully
✅ **Performance**: Slightly slower (individual requests) but reliable
✅ **Tested**: RELIANCE shows ₹1556.50 correctly
Your Current Price column should now show actual stock prices! 🎉
## Verification
To verify the fix is working:
1. ✅ Restart your Next.js development server
2. ✅ Navigate to Holdings page
3. ✅ Check "Current Price" column - should show actual prices
4. ✅ Check "Current Value" column - should be Quantity × Price
5. ✅ Check server console - should see successful Yahoo Finance logs
If you still see ₹0 after restarting, check the troubleshooting section above.