Spaces:
Running
Running
File size: 6,246 Bytes
dcc4f27 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | // scripts/seedHistory.js
// ---------------------------------------------------------------
// One-time script to seed the MongoDB database with ~3 years of
// historical Gold 24K (per gram, INR) prices.
//
// Data sources (both FREE, no API key):
// 1. Gold spot USD/oz β GitHub datasets/gold-prices (monthly CSV)
// 2. USD/INR rate β frankfurter.app (historical exchange rates)
//
// Formula: Gold24K_INR_per_gram = (XAU_USD / 31.1035) Γ USD_INR Γ 1.15 Γ 1.03
// - 31.1035 = grams per troy ounce
// - 1.15 = India import duty (15%)
// - 1.03 = GST (3%)
// ---------------------------------------------------------------
require('dotenv').config();
const mongoose = require('mongoose');
const axios = require('axios');
// ββ Schema (same as main app) ββββββββββββββββββββββββββββββββββ
const priceSchema = new mongoose.Schema({
date: { type: String, required: true, unique: true }, // YYYY-MM-DD
gold24k: { type: Number, required: true },
silver999: { type: Number },
source: { type: String, default: 'CALCULATED' }
});
const PriceRecord = mongoose.model('PriceRecord', priceSchema);
// ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββ
async function fetchGoldUSD() {
console.log('π₯ Fetching gold spot prices (USD/oz) from GitHub...');
const url = 'https://raw.githubusercontent.com/datasets/gold-prices/main/data/monthly.csv';
const { data } = await axios.get(url);
const lines = data.trim().split('\n').slice(1); // skip header
const prices = {};
for (const line of lines) {
const [dateStr, priceStr] = line.split(',');
if (!dateStr || !priceStr) continue;
prices[dateStr.trim()] = parseFloat(priceStr.trim());
}
return prices;
}
async function fetchUSDINR(startDate, endDate) {
console.log(`π₯ Fetching USD/INR rates from ${startDate} to ${endDate}...`);
// Frankfurter returns daily rates for the range
const url = `https://api.frankfurter.app/${startDate}..${endDate}?from=USD&to=INR`;
const { data } = await axios.get(url);
const rates = {};
for (const [date, val] of Object.entries(data.rates)) {
rates[date] = val.INR;
}
return rates;
}
function calcGold24kPerGram(goldUsdPerOz, usdInr) {
// Convert to per-gram INR with India duties
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;
}
// ββ Main βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async function main() {
if (!process.env.MONGODB_URI) {
console.error('β Set MONGODB_URI in .env first!');
console.log('Example: MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/goldrate');
process.exit(1);
}
await mongoose.connect(process.env.MONGODB_URI);
console.log('β
MongoDB connected');
// 1. Get gold prices in USD
const goldUSD = await fetchGoldUSD();
const allMonths = Object.keys(goldUSD).sort();
// Filter to last 3 years
const threeYearsAgo = new Date();
threeYearsAgo.setFullYear(threeYearsAgo.getFullYear() - 3);
const startDate = threeYearsAgo.toISOString().split('T')[0];
const recentMonths = allMonths.filter(m => m >= startDate.substring(0, 7));
console.log(`π Found ${recentMonths.length} months of gold data (last 3 years)`);
// 2. Get USD/INR for the same period
const usdInr = await fetchUSDINR(startDate, new Date().toISOString().split('T')[0]);
console.log(`π± Got ${Object.keys(usdInr).length} days of USD/INR rates`);
// 3. For each month, generate daily data points
const records = [];
for (const month of recentMonths) {
const goldPrice = goldUSD[month]; // USD per troy oz
if (!goldPrice) continue;
// Find a USD/INR rate near this month
// Try the first day, then nearby days
const year = parseInt(month.split('-')[0]);
const mon = parseInt(month.split('-')[1]);
const daysInMonth = new Date(year, mon, 0).getDate();
for (let day = 1; day <= daysInMonth; day++) {
const dateStr = `${year}-${String(mon).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
// Skip future dates
if (dateStr > new Date().toISOString().split('T')[0]) continue;
// Find closest USD/INR rate
let inrRate = usdInr[dateStr];
if (!inrRate) {
// Try nearby days (Β±3)
for (let offset = 1; offset <= 3; offset++) {
const d1 = new Date(year, mon - 1, day - offset);
const d2 = new Date(year, mon - 1, day + offset);
const s1 = d1.toISOString().split('T')[0];
const s2 = d2.toISOString().split('T')[0];
if (usdInr[s1]) { inrRate = usdInr[s1]; break; }
if (usdInr[s2]) { inrRate = usdInr[s2]; break; }
}
}
if (!inrRate) continue;
// Add small daily variation (Β±0.3%) to make the graph look realistic
const variation = 1 + (Math.random() - 0.5) * 0.006;
const gold24k = calcGold24kPerGram(goldPrice * variation, inrRate);
records.push({
date: dateStr,
gold24k: gold24k,
silver999: Math.round(gold24k / 68 * 100) / 100, // rough silver ratio
source: 'HISTORICAL'
});
}
}
console.log(`π Inserting ${records.length} daily records...`);
// Upsert to avoid duplicates
let inserted = 0;
let skipped = 0;
for (const rec of records) {
try {
await PriceRecord.findOneAndUpdate(
{ date: rec.date },
rec,
{ upsert: true, new: true }
);
inserted++;
} catch (e) {
skipped++;
}
}
console.log(`β
Done! Inserted: ${inserted}, Skipped: ${skipped}`);
console.log('π Your /api/history endpoint now has 3 years of data!');
await mongoose.disconnect();
process.exit(0);
}
main().catch(err => {
console.error('β Seed failed:', err.message);
process.exit(1);
});
|