Compare commits

...

10 Commits

Author SHA1 Message Date
3cd3be87bf
Bitcoin historic price data upload
Some checks failed
Pull changes and deploy API / Build (push) Has been cancelled
Data upto December 25, 2012
2025-01-05 16:06:51 +05:30
c9f0414df4
Update price-history.min.js 2025-01-05 16:02:50 +05:30
ba876a434b
Update price-history.js 2025-01-05 16:01:30 +05:30
ce30b07ec8
Update price-history.min.js 2024-10-23 07:26:11 +05:30
616983559a
Update price-history.js 2024-10-23 07:25:38 +05:30
f6a2a52a19
Update price-history.min.js 2024-10-22 19:29:27 +05:30
966baaf437
Update price-history.js 2024-10-22 19:28:56 +05:30
c2f2a01bf4
Update price-history.min.js 2024-10-22 19:15:56 +05:30
c0b7418e24
Update price-history.js 2024-10-22 19:14:07 +05:30
714ad06eae
Update price-history.js 2024-10-22 18:26:30 +05:30
5 changed files with 30144 additions and 18 deletions

26281
btc_price_history.json Normal file

File diff suppressed because it is too large Load Diff

3754
btc_price_history_full.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,11 @@ const Schema = new mongoose.Schema({
inr: {
type: Number,
required: true
},
count: {
type: Number, // New field to track the number of updates for the day
default: 1
}
});
module.exports = mongoose.model('PriceHistory', Schema);
module.exports = mongoose.model('PriceHistory', Schema);

View File

@ -6,20 +6,27 @@ const fs = require('fs');
const path = require('path');
const csv = require('csv-parser');
// Import the PriceHistory model from the external file
const PriceHistory = require('../models/price-history');
const CSV_FILE_PATH = '/home/production/deployed/utility-api/btc_price_history_full.csv';
function logWithTimestamp(message) {
console.log(`[${new Date().toISOString()}] ${message}`);
}
// Function to read CSV file and return data
function readCsvFile() {
return new Promise((resolve, reject) => {
const results = [];
fs.createReadStream(CSV_FILE_PATH)
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => resolve(results))
.on('error', (err) => reject(err));
});
// Function to log errors with the current timestamp
function errorWithTimestamp(message, error) {
console.error(`[${new Date().toISOString()}] ERROR: ${message}`, error);
}
// Function to parse dates in different formats (e.g., 2024-10-2 or 2024-9-3)
function parseDateString(dateStr) {
const parts = dateStr.split('-');
const year = parseInt(parts[0]);
const month = parseInt(parts[1]) - 1; // Months are 0-indexed in JavaScript Date
const day = parseInt(parts[2]);
return new Date(year, month, day).setHours(0, 0, 0, 0); // Set time to 00:00:00.000
}
// Function to fetch BTC prices in USD and INR from BitPay API
@ -34,14 +41,16 @@ async function fetchBtcPrices() {
return { usd: btcUsdRate, inr: btcInrRate };
} catch (error) {
console.error('Error fetching BTC prices from BitPay:', error);
errorWithTimestamp('Error fetching BTC prices from BitPay:', error);
return null;
}
}
// Function to update daily average in the database
async function updateDailyAverage(newPrice) {
const today = new Date().setHours(0, 0, 0, 0);
// Set the date to the start of the day (00:00:00.000)
const today = new Date();
today.setHours(0, 0, 0, 0);
try {
// Fetch the current record for the day
@ -73,9 +82,9 @@ async function updateDailyAverage(newPrice) {
});
}
console.log('Daily average updated successfully.');
logWithTimestamp('Daily average updated successfully.');
} catch (err) {
console.error('Error updating daily average:', err);
errorWithTimestamp('Error updating daily average:', err);
}
}
@ -89,9 +98,86 @@ async function collectAndUpdatePrices() {
}
}
// Route to handle price history requests
router.get("/", async (req, res) => {
try {
let { from, to, on, limit = 100, asset = 'btc', currency, sort, dates } = req.query;
const searchParams = {
asset
};
// Convert 'from' and 'to' dates to proper format
if (from && to) {
from = parseDateString(from);
to = parseDateString(to);
if (from > to) {
const temp = from;
from = to;
to = temp;
}
}
if (from) {
searchParams.date = { $gte: from };
}
if (to) {
searchParams.date = { ...searchParams.date, $lte: to };
}
// If the 'dates' parameter is used
if (dates) {
const datesArray = dates.split(',').map(date => parseDateString(date.trim()));
searchParams.date = { $in: datesArray };
}
// If the 'on' parameter is used for a single date
if (on) {
const onDate = parseDateString(on);
searchParams.date = { $eq: onDate };
}
if (currency) {
searchParams[currency] = { $exists: true };
}
if (sort) {
if (['asc', 'desc', 'ascending', 'descending', '1', '-1'].includes(sort)) {
sort = { date: sort === 'asc' || sort === 'ascending' || sort === '1' ? 1 : -1 };
} else {
return res.status(400).json({ error: 'Invalid sort. Valid values are asc | desc | ascending | descending | 1 | -1' });
}
} else {
sort = { date: -1 };
}
// Formatting the data to exclude certain fields
const dataFormat = { _id: 0, __v: 0, asset: 0 };
if (currency === 'inr') {
dataFormat.usd = 0;
}
if (currency === 'usd') {
dataFormat.inr = 0;
}
const priceHistory = await PriceHistory.find(searchParams, dataFormat)
.sort(sort)
.limit(limit === 'all' ? 0 : parseInt(limit))
.lean();
if (!priceHistory || priceHistory.length === 0) {
return res.status(404).json({ message: 'No data found' });
}
res.json(priceHistory);
} catch (err) {
errorWithTimestamp('Error serving data',err);
res.status(500).json({ error: err });
}
});
// Cron job to collect prices every 4 hours
cron.schedule('0 */4 * * *', async () => {
console.log('Starting price collection for daily averaging...');
logWithTimestamp('Starting price collection for daily averaging...');
await collectAndUpdatePrices();
});

View File

@ -1 +1 @@
const express=require("express"),router=express.Router(),cron=require("node-cron"),axios=require("axios"),fs=require("fs"),path=require("path"),csv=require("csv-parser"),PriceHistory=require("../models/price-history"),CSV_FILE_PATH="/home/production/deployed/utility-api/btc_price_history_full.csv";function readCsvFile(){return new Promise(((e,r)=>{const t=[];fs.createReadStream(CSV_FILE_PATH).pipe(csv()).on("data",(e=>t.push(e))).on("end",(()=>e(t))).on("error",(e=>r(e)))}))}async function fetchBtcPrices(){try{const e=(await axios.get("https://bitpay.com/api/rates")).data,r=e.find((e=>"USD"===e.code&&"US Dollar"===e.name)).rate;return{usd:r,inr:e.find((e=>"INR"===e.code&&"Indian Rupee"===e.name)).rate}}catch(e){return console.error("Error fetching BTC prices from BitPay:",e),null}}async function updateDailyAverage(e){const r=(new Date).setHours(0,0,0,0);try{const t=await PriceHistory.findOne({date:r,asset:"btc"});if(t){const a=(t.usd*t.count+e.usd)/(t.count+1),c=(t.inr*t.count+e.inr)/(t.count+1);await PriceHistory.updateOne({date:r,asset:"btc"},{$set:{usd:a,inr:c,count:t.count+1}})}else await PriceHistory.create({date:r,asset:"btc",usd:e.usd,inr:e.inr,count:1});console.log("Daily average updated successfully.")}catch(e){console.error("Error updating daily average:",e)}}async function collectAndUpdatePrices(){const e=await fetchBtcPrices();e&&await updateDailyAverage(e)}cron.schedule("0 */4 * * *",(async()=>{console.log("Starting price collection for daily averaging..."),await collectAndUpdatePrices()})),module.exports=router;
const express=require("express"),router=express.Router(),cron=require("node-cron"),axios=require("axios"),fs=require("fs"),path=require("path"),csv=require("csv-parser"),PriceHistory=require("../models/price-history");function logWithTimestamp(e){console.log(`[${(new Date).toISOString()}] ${e}`)}function errorWithTimestamp(e,t){console.error(`[${(new Date).toISOString()}] ERROR: ${e}`,t)}function parseDateString(e){const t=e.split("-"),r=parseInt(t[0]),s=parseInt(t[1])-1,a=parseInt(t[2]);return new Date(r,s,a).setHours(0,0,0,0)}async function fetchBtcPrices(){try{const e=(await axios.get("https://bitpay.com/api/rates")).data,t=e.find((e=>"USD"===e.code&&"US Dollar"===e.name)).rate;return{usd:t,inr:e.find((e=>"INR"===e.code&&"Indian Rupee"===e.name)).rate}}catch(e){return errorWithTimestamp("Error fetching BTC prices from BitPay:",e),null}}async function updateDailyAverage(e){const t=new Date;t.setHours(0,0,0,0);try{const r=await PriceHistory.findOne({date:t,asset:"btc"});if(r){const s=(r.usd*r.count+e.usd)/(r.count+1),a=(r.inr*r.count+e.inr)/(r.count+1);await PriceHistory.updateOne({date:t,asset:"btc"},{$set:{usd:s,inr:a,count:r.count+1}})}else await PriceHistory.create({date:t,asset:"btc",usd:e.usd,inr:e.inr,count:1});logWithTimestamp("Daily average updated successfully.")}catch(e){errorWithTimestamp("Error updating daily average:",e)}}async function collectAndUpdatePrices(){const e=await fetchBtcPrices();e&&await updateDailyAverage(e)}router.get("/",(async(e,t)=>{try{let{from:r,to:s,on:a,limit:i=100,asset:n="btc",currency:c,sort:o,dates:d}=e.query;const u={asset:n};if(r&&s&&(r=parseDateString(r),s=parseDateString(s),r>s)){const e=r;r=s,s=e}if(r&&(u.date={$gte:r}),s&&(u.date={...u.date,$lte:s}),d){const e=d.split(",").map((e=>parseDateString(e.trim())));u.date={$in:e}}if(a){const e=parseDateString(a);u.date={$eq:e}}if(c&&(u[c]={$exists:!0}),o){if(!["asc","desc","ascending","descending","1","-1"].includes(o))return t.status(400).json({error:"Invalid sort. Valid values are asc | desc | ascending | descending | 1 | -1"});o={date:"asc"===o||"ascending"===o||"1"===o?1:-1}}else o={date:-1};const l={_id:0,__v:0,asset:0};"inr"===c&&(l.usd=0),"usd"===c&&(l.inr=0);const p=await PriceHistory.find(u,l).sort(o).limit("all"===i?0:parseInt(i)).lean();if(!p||0===p.length)return t.status(404).json({message:"No data found"});t.json(p)}catch(e){errorWithTimestamp("Error serving data",e),t.status(500).json({error:e})}})),cron.schedule("0 */4 * * *",(async()=>{logWithTimestamp("Starting price collection for daily averaging..."),await collectAndUpdatePrices()})),module.exports=router;