solana-price/main.js

234 lines
8.4 KiB
JavaScript

require('dotenv').config();
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const fs = require('fs');
const path = require('path');
let priceHistory = {
currentPrice: 0,
prices: [{
time: Date.now(),
price: 0,
}]
};
const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
});
const solanaPriceChannelId = process.env.SOLANA_PRICE_CHANNEL_ID;
const announcementsChannelId = process.env.ANNOUNCEMENTS_CHANNEL_ID;
const solanaDataFile = './data/solana.json';
let lastAnnouncedPrice;
let lastPriceMessageId;
client.once('ready', async () => {
console.log('Bot is online!');
let solanaData = readSolanaData();
if (solanaData) {
priceHistory = solanaData;
lastAnnouncedPrice = solanaData.lastAnnouncedPrice;
lastPriceMessageId = solanaData.lastPriceMessageId;
}
immediatePriceCheckAndAnnounce();
checkPriceContinuously();
});
async function fetchSolanaPrice() {
const cryptocompareApiUrl = 'https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD';
try {
const fetch = (await import('node-fetch')).default;
const response = await fetch(cryptocompareApiUrl);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
return parseFloat(data.USD).toFixed(2);
} catch (error) {
console.error('Error fetching Solana price:', error);
setTimeout(fetchSolanaPriceAndUpdateHistory, 5 * 60 * 1000);
return null;
}
}
function pruneOldData() {
const sixHoursInMilliseconds = 6 * 60 * 60 * 1000;
const oneDayInMilliseconds = 24 * 60 * 60 * 1000;
const cutoffTime1Day = Date.now() - oneDayInMilliseconds;
priceHistory.prices = priceHistory.prices.filter(pricePoint => pricePoint.time > cutoffTime1Day);
if (priceHistory.prices.length < (sixHoursInMilliseconds / (60 * 1000))) {
console.warn("Warning: Not enough data points for accurate 6-hour calculations.");
}
if (priceHistory.prices.length < (oneDayInMilliseconds / (60 * 1000))) {
console.warn("Warning: Not enough data points for accurate 1-day calculations.");
}
}
async function fetchSolanaPriceAndUpdateHistory() {
const currentPrice = await fetchSolanaPrice();
if (currentPrice) {
pruneOldData();
priceHistory.prices.push({ time: Date.now(), price: currentPrice });
priceHistory.currentPrice = currentPrice;
saveSolanaData(priceHistory);
}
}
function immediatePriceCheckAndAnnounce() {
const solanaData = readSolanaData();
const lastKnownPrice = solanaData ? solanaData.price : null;
const currentPrice = fetchSolanaPrice();
}
const now = Date.now();
function calculateChanges() {
const latestPrice = parseFloat(priceHistory.currentPrice);
let oneMinChange = { percent: 0, dollar: 0 };
let fiveMinChange = { percent: 0, dollar: 0 };
let oneHourChange = { percent: 0, dollar: 0 };
let sixHourChange = { percent: 0, dollar: 0 }
let oneDayChange = { percent: 0, dollar: 0 };
const now = Date.now();
function findPriceAgo(minutesAgo) {
const targetTime = now - minutesAgo * 60 * 1000;
return priceHistory.prices.reduce((prev, curr) => {
return Math.abs(curr.time - targetTime) < Math.abs(prev.time - targetTime) ? curr : prev;
}, priceHistory.prices[0]);
}
if (priceHistory.prices.length >= 2) {
const oneMinAgoPrice = parseFloat(findPriceAgo(1).price);
oneMinChange.percent = ((latestPrice - oneMinAgoPrice) / oneMinAgoPrice) * 100;
oneMinChange.dollar = latestPrice - oneMinAgoPrice;
}
if (priceHistory.prices.length >= 6) {
const fiveMinAgoPrice = parseFloat(findPriceAgo(5).price);
fiveMinChange.percent = ((latestPrice - fiveMinAgoPrice) / fiveMinAgoPrice) * 100;
fiveMinChange.dollar = latestPrice - fiveMinAgoPrice;
}
if (priceHistory.prices.length >= 61) {
const oneHourAgoPrice = parseFloat(findPriceAgo(60).price);
oneHourChange.percent = ((latestPrice - oneHourAgoPrice) / oneHourAgoPrice) * 100;
oneHourChange.dollar = latestPrice - oneHourAgoPrice;
}
if (priceHistory.prices.length >= 1440) {
const oneDayAgoPrice = parseFloat(findPriceAgo(1440).price);
oneDayChange.percent = ((latestPrice - oneDayAgoPrice) / oneDayAgoPrice) * 100;
oneDayChange.dollar = latestPrice - oneDayAgoPrice;
} else {
console.log("Insufficient data for 1-day change calculation.");
}
if (priceHistory.prices.length >= 360) {
const sixHourAgoPrice = parseFloat(findPriceAgo(360).price);
sixHourChange.percent = ((latestPrice - sixHourAgoPrice) / sixHourAgoPrice) * 100;
sixHourChange.dollar = latestPrice - sixHourAgoPrice;
}
return { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange };
}
async function sendNewPriceMessage(embed) {
const sentMessage = await solanaPriceChannel.send({ embeds: [embed] });
lastPriceMessageId = sentMessage.id;
saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id });
}
async function sendNewPriceMessage(solanaPriceChannel, embed) {
const sentMessage = await solanaPriceChannel.send({ embeds: [embed] });
lastPriceMessageId = sentMessage.id;
saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id });
}
async function checkPriceContinuously() {
await fetchSolanaPriceAndUpdateHistory();
const { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange } = calculateChanges();
console.log(`Current Price: ${priceHistory.currentPrice}`);
const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
const embed = new EmbedBuilder()
.setColor(`#${randomColor}`)
.setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png')
.setTitle('Solana (SOL) Price Update')
.setURL('https://coinmarketcap.com/currencies/solana/')
.setDescription(`**Current Price: \`$${priceHistory.currentPrice}\`**`)
.addFields([
{ name: '💰 Current Price', value: `**\`$${priceHistory.currentPrice}\`**`, inline: false },
{ name: '1 Minute Change', value: `${oneMinChange.percent.toFixed(2)}% (${oneMinChange.dollar.toFixed(2)} USD)`, inline: true },
{ name: '5 Minute Change', value: `${fiveMinChange.percent.toFixed(2)}% (${fiveMinChange.dollar.toFixed(2)} USD)`, inline: true },
{ name: '1 Hour Change', value: `${oneHourChange.percent.toFixed(2)}% (${oneHourChange.dollar.toFixed(2)} USD)`, inline: true },
{ name: '6 Hour Change', value: `${sixHourChange.percent.toFixed(2)}% (${sixHourChange.dollar.toFixed(2)} USD)`, inline: true },
{ name: '1 Day Change', value: `${oneDayChange.percent.toFixed(2)}% (${oneDayChange.dollar.toFixed(2)} USD)`, inline: true }
])
.setTimestamp()
.setImage(process.env.IMAGE_URL);
const solanaPriceChannel = await client.channels.fetch(solanaPriceChannelId);
if (lastPriceMessageId) {
try {
const message = await solanaPriceChannel.messages.fetch(lastPriceMessageId);
await message.edit({ embeds: [embed] });
} catch (error) {
console.error('Error updating price message, sending a new one:', error);
sendNewPriceMessage(solanaPriceChannel, embed);
}
} else {
console.log('No lastPriceMessageId found, sending a new message.');
sendNewPriceMessage(solanaPriceChannel, embed);
}
if (lastAnnouncedPrice !== null && (parseFloat(priceHistory.currentPrice) - lastAnnouncedPrice >= 2.5)) {
const announcementsChannel = await client.channels.fetch(announcementsChannelId);
await announcementsChannel.send(`@everyone Solana price has increased significantly! Current price: $${priceHistory.currentPrice}`);
lastAnnouncedPrice = parseFloat(priceHistory.currentPrice);
saveSolanaData({ ...priceHistory, lastAnnouncedPrice });
}
setTimeout(checkPriceContinuously, 60000);
}
function saveSolanaData(data) {
const dir = path.dirname(solanaDataFile);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
const dataToSave = {
...data,
lastAnnouncedPrice: lastAnnouncedPrice,
};
fs.writeFileSync(solanaDataFile, JSON.stringify(dataToSave, null, 2), 'utf8');
}
function readSolanaData() {
try {
if (fs.existsSync(solanaDataFile)) {
const fileContent = fs.readFileSync(solanaDataFile, 'utf8');
const data = JSON.parse(fileContent);
lastAnnouncedPrice = data.lastAnnouncedPrice || null;
return data;
}
} catch (error) {
console.error('Error reading Solana data:', error);
}
return null;
}
client.login(process.env.DISCORD_BOT_TOKEN);