Spaces:
Running
Running
| // scripts/generateDaily.js | |
| // --------------------------------------------------------------- | |
| // Generates daily Gold 24K prices (INR/gram) for the last 3 years | |
| // using FREE data sources: | |
| // 1. Monthly gold spot USD/oz β GitHub datasets | |
| // 2. Daily USD/INR rates β frankfurter.app | |
| // | |
| // Saves to src/data/history.json | |
| // --------------------------------------------------------------- | |
| require('dotenv').config(); | |
| const axios = require('axios'); | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| // India duty formula | |
| function calcGold24k(goldUsdPerOz, usdInr) { | |
| const perGram = goldUsdPerOz / 31.1035; | |
| const inINR = perGram * usdInr; | |
| const withDuty = inINR * 1.15; // 15% import duty | |
| const withGST = withDuty * 1.03; // 3% GST | |
| return Math.round(withGST * 100) / 100; | |
| } | |
| async function main() { | |
| console.log('πͺ Generating 3 years of daily Gold 24K prices...\n'); | |
| // 1. Fetch monthly gold USD prices | |
| console.log('π₯ Step 1: Fetching gold spot prices (USD/oz)...'); | |
| const goldRes = await axios.get('https://raw.githubusercontent.com/datasets/gold-prices/main/data/monthly.csv'); | |
| const goldLines = goldRes.data.trim().split('\n').slice(1); | |
| const monthlyGold = {}; | |
| for (const line of goldLines) { | |
| const [dateStr, priceStr] = line.split(','); | |
| if (dateStr && priceStr) { | |
| monthlyGold[dateStr.trim()] = parseFloat(priceStr.trim()); | |
| } | |
| } | |
| console.log(` β Got ${Object.keys(monthlyGold).length} months of gold data\n`); | |
| // 2. Fetch daily USD/INR for last 3 years (in chunks β frankfurter limits range) | |
| console.log('π₯ Step 2: Fetching daily USD/INR rates...'); | |
| const allUsdInr = {}; | |
| const today = new Date(); | |
| // Fetch year by year (frankfurter handles this better) | |
| for (let i = 3; i >= 0; i--) { | |
| const yearStart = new Date(today); | |
| yearStart.setFullYear(today.getFullYear() - i); | |
| yearStart.setMonth(0, 1); | |
| const yearEnd = new Date(yearStart); | |
| yearEnd.setFullYear(yearStart.getFullYear(), 11, 31); | |
| // Don't go past today | |
| if (yearEnd > today) { | |
| yearEnd.setTime(today.getTime() - 86400000); // yesterday | |
| } | |
| const startStr = yearStart.toISOString().split('T')[0]; | |
| const endStr = yearEnd.toISOString().split('T')[0]; | |
| if (startStr >= endStr) continue; | |
| try { | |
| console.log(` Fetching ${startStr} to ${endStr}...`); | |
| const url = `https://api.frankfurter.app/${startStr}..${endStr}?from=USD&to=INR`; | |
| const { data } = await axios.get(url, { timeout: 30000 }); | |
| for (const [date, val] of Object.entries(data.rates)) { | |
| allUsdInr[date] = val.INR; | |
| } | |
| } catch (e) { | |
| console.warn(` β οΈ Failed for ${startStr}..${endStr}: ${e.message}`); | |
| } | |
| } | |
| console.log(` β Got ${Object.keys(allUsdInr).length} days of USD/INR rates\n`); | |
| // 3. Generate daily Gold 24K prices | |
| console.log('π Step 3: Calculating daily Gold 24K (INR/gram)...'); | |
| const sortedMonths = Object.keys(monthlyGold).sort(); | |
| const sortedDays = Object.keys(allUsdInr).sort(); | |
| // For each day with USD/INR, find the closest monthly gold price | |
| const dailyPrices = []; | |
| for (const day of sortedDays) { | |
| const usdInr = allUsdInr[day]; | |
| const dayMonth = day.substring(0, 7); // YYYY-MM | |
| // Find gold price: exact month or closest previous month | |
| let goldUsd = monthlyGold[dayMonth]; | |
| if (!goldUsd) { | |
| // Find closest previous month | |
| for (let i = sortedMonths.length - 1; i >= 0; i--) { | |
| if (sortedMonths[i] <= dayMonth) { | |
| goldUsd = monthlyGold[sortedMonths[i]]; | |
| break; | |
| } | |
| } | |
| } | |
| if (!goldUsd || !usdInr) continue; | |
| const gold24k = calcGold24k(goldUsd, usdInr); | |
| dailyPrices.push({ | |
| date: day, | |
| gold24k: gold24k | |
| }); | |
| } | |
| // Sort oldest to newest | |
| dailyPrices.sort((a, b) => a.date.localeCompare(b.date)); | |
| console.log(` β Generated ${dailyPrices.length} daily prices\n`); | |
| console.log(` π From: ${dailyPrices[0]?.date} β To: ${dailyPrices[dailyPrices.length - 1]?.date}`); | |
| console.log(` π° First price: βΉ${dailyPrices[0]?.gold24k}/g`); | |
| console.log(` π° Last price: βΉ${dailyPrices[dailyPrices.length - 1]?.gold24k}/g\n`); | |
| // 4. Save to file | |
| const outDir = path.join(__dirname, '..', 'src', 'data'); | |
| if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }); | |
| const outFile = path.join(outDir, 'history.json'); | |
| fs.writeFileSync(outFile, JSON.stringify(dailyPrices, null, 0)); | |
| const sizeKB = Math.round(fs.statSync(outFile).size / 1024); | |
| console.log(`πΎ Saved to src/data/history.json (${sizeKB} KB)`); | |
| console.log(`π Total records: ${dailyPrices.length}`); | |
| console.log('\nβ Done! Your /api/history endpoint now has 3 years of daily data!'); | |
| } | |
| main().catch(err => { | |
| console.error('β Failed:', err.message); | |
| process.exit(1); | |
| }); | |