vibe-stocks
Version:
Terminal-based stock market viewer with real-time data streaming
50 lines (41 loc) • 1.86 kB
JavaScript
const axios = require('axios');
const chalk = require('chalk');
const ora = require('ora');
const config = require('./config');
module.exports = {
run: async (symbol) => {
const spinner = ora(`Loading quote for ${symbol}...`).start();
try {
const response = await axios.get(`${config.MCP_SERVER_URL}${config.endpoints.quote(symbol)}`);
const quote = response.data;
spinner.stop();
console.clear();
console.log(chalk.cyan.bold(`${quote.symbol} - ${quote.name || 'N/A'}`));
console.log(chalk.gray('─'.repeat(50)));
const change = quote.changesPercentage || 0;
const changeColor = change > 0 ? chalk.green : change < 0 ? chalk.red : chalk.gray;
console.log(`\nPrice: ${chalk.bold.white(formatCurrency(quote.price))}`);
console.log(`Change: ${changeColor(`${change >= 0 ? '+' : ''}${change.toFixed(2)}%`)}`);
console.log(`\nVolume: ${formatNumber(quote.volume)}`);
console.log(`Market Cap: ${formatNumber(quote.marketCap)}`);
console.log(`\nDay Range: ${formatCurrency(quote.dayLow)} - ${formatCurrency(quote.dayHigh)}`);
console.log(`52W Range: ${formatCurrency(quote.yearLow)} - ${formatCurrency(quote.yearHigh)}`);
console.log(`\nP/E Ratio: ${quote.pe?.toFixed(2) || 'N/A'}`);
console.log(`EPS: ${formatCurrency(quote.eps)}`);
} catch (error) {
spinner.fail(`Failed to load quote for ${symbol}`);
console.error(chalk.red('Error:'), error.message);
}
}
};
function formatCurrency(num) {
if (num === null || num === undefined) return 'N/A';
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(num);
}
function formatNumber(num) {
if (num === null || num === undefined) return 'N/A';
return new Intl.NumberFormat('en-US').format(num);
}