stock-average-calculator
Version:
A comprehensive utility for calculating stock price averages and managing investment portfolios
313 lines (254 loc) • 10.9 kB
JavaScript
const readline = require('readline');
const {
calculateAveragePrice,
calculatePortfolioMetrics,
calculateDollarCostAveraging,
calculateOptimalAveragingStrategy,
formatAveragePriceResult,
formatPortfolioMetricsResult,
formatDCAResult,
quickCalculateAverage
} = require('./index');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// ANSI color codes for better output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
underscore: '\x1b[4m',
blink: '\x1b[5m',
reverse: '\x1b[7m',
hidden: '\x1b[8m',
fg: {
black: '\x1b[30m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m'
},
bg: {
black: '\x1b[40m',
red: '\x1b[41m',
green: '\x1b[42m',
yellow: '\x1b[43m',
blue: '\x1b[44m',
magenta: '\x1b[45m',
cyan: '\x1b[46m',
white: '\x1b[47m'
}
};
// Display the welcome message
function displayWelcome() {
console.log(`
${colors.bright}${colors.fg.cyan}====================================${colors.reset}
${colors.bright}${colors.fg.cyan} STOCK AVERAGE CALCULATOR ${colors.reset}
${colors.bright}${colors.fg.cyan}====================================${colors.reset}
Calculate stock price averages and portfolio metrics.
`);
}
// Display available calculation types
function displayCalculationTypes() {
console.log(`${colors.bright}Available calculations:${colors.reset}\n`);
console.log(`${colors.fg.green}1. Quick Average Calculation${colors.reset}`);
console.log(` ${colors.dim}Calculate average stock price from multiple purchases${colors.reset}\n`);
console.log(`${colors.fg.green}2. Portfolio Metrics${colors.reset}`);
console.log(` ${colors.dim}Calculate average plus profit/loss with current market price${colors.reset}\n`);
console.log(`${colors.fg.green}3. Dollar Cost Averaging${colors.reset}`);
console.log(` ${colors.dim}Calculate results of a dollar cost averaging strategy${colors.reset}\n`);
console.log(`${colors.fg.green}4. Target Average Strategy${colors.reset}`);
console.log(` ${colors.dim}Calculate optimal strategy to reach a target average price${colors.reset}\n`);
}
// Function to prompt for input
function prompt(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
// Process quick average calculation
async function processQuickAverage() {
console.log(`\n${colors.fg.yellow}Enter transaction details for average calculation:${colors.reset}`);
const transactions = [];
let addMore = true;
let counter = 1;
while (addMore) {
console.log(`\n${colors.fg.cyan}Transaction #${counter}:${colors.reset}`);
const sharesStr = await prompt(`${colors.fg.cyan}Enter number of shares: ${colors.reset}`);
const priceStr = await prompt(`${colors.fg.cyan}Enter price per share: $${colors.reset}`);
try {
const shares = parseFloat(sharesStr);
const price = parseFloat(priceStr);
transactions.push({ shares, price });
counter++;
const addMoreStr = await prompt(`\n${colors.fg.yellow}Add another transaction? (y/n): ${colors.reset}`);
addMore = addMoreStr.toLowerCase() === 'y';
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
try {
const result = calculateAveragePrice(transactions);
console.log(`\n${colors.bright}${colors.fg.green}Calculation Result:${colors.reset}`);
console.log(formatAveragePriceResult(result));
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
// Process portfolio metrics calculation
async function processPortfolioMetrics() {
console.log(`\n${colors.fg.yellow}Enter transaction details for portfolio metrics:${colors.reset}`);
const transactions = [];
let addMore = true;
let counter = 1;
while (addMore) {
console.log(`\n${colors.fg.cyan}Transaction #${counter}:${colors.reset}`);
const sharesStr = await prompt(`${colors.fg.cyan}Enter number of shares: ${colors.reset}`);
const priceStr = await prompt(`${colors.fg.cyan}Enter price per share: $${colors.reset}`);
try {
const shares = parseFloat(sharesStr);
const price = parseFloat(priceStr);
transactions.push({ shares, price });
counter++;
const addMoreStr = await prompt(`\n${colors.fg.yellow}Add another transaction? (y/n): ${colors.reset}`);
addMore = addMoreStr.toLowerCase() === 'y';
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
const currentPriceStr = await prompt(`\n${colors.fg.cyan}Enter current market price per share: $${colors.reset}`);
try {
const currentPrice = parseFloat(currentPriceStr);
const result = calculatePortfolioMetrics(transactions, currentPrice);
console.log(`\n${colors.bright}${colors.fg.green}Portfolio Analysis:${colors.reset}`);
console.log(formatPortfolioMetricsResult(result));
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
// Process dollar cost averaging calculation
async function processDCA() {
try {
const initialInvestmentStr = await prompt(`${colors.fg.cyan}Enter initial investment amount: $${colors.reset}`);
const periodicInvestmentStr = await prompt(`${colors.fg.cyan}Enter periodic investment amount: $${colors.reset}`);
const frequencyStr = await prompt(`${colors.fg.cyan}Enter investment frequency (weekly, monthly, quarterly): ${colors.reset}`);
console.log(`\n${colors.fg.yellow}Now enter the stock price for each period:${colors.reset}`);
const prices = [];
let addMore = true;
let counter = 1;
while (addMore) {
const priceStr = await prompt(`${colors.fg.cyan}Price for period #${counter}: $${colors.reset}`);
prices.push(parseFloat(priceStr));
counter++;
if (counter > 2) {
const addMoreStr = await prompt(`\n${colors.fg.yellow}Add another period? (y/n): ${colors.reset}`);
addMore = addMoreStr.toLowerCase() === 'y';
}
}
const initialInvestment = parseFloat(initialInvestmentStr);
const periodicInvestment = parseFloat(periodicInvestmentStr);
const frequency = frequencyStr.toLowerCase();
const result = calculateDollarCostAveraging(initialInvestment, periodicInvestment, prices, frequency);
console.log(`\n${colors.bright}${colors.fg.green}Dollar Cost Averaging Analysis:${colors.reset}`);
console.log(formatDCAResult(result));
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
// Process target average strategy
async function processTargetStrategy() {
console.log(`\n${colors.fg.yellow}Enter your current holdings:${colors.reset}`);
const transactions = [];
let addMore = true;
let counter = 1;
while (addMore) {
console.log(`\n${colors.fg.cyan}Transaction #${counter}:${colors.reset}`);
const sharesStr = await prompt(`${colors.fg.cyan}Enter number of shares: ${colors.reset}`);
const priceStr = await prompt(`${colors.fg.cyan}Enter price per share: $${colors.reset}`);
try {
const shares = parseFloat(sharesStr);
const price = parseFloat(priceStr);
transactions.push({ shares, price });
counter++;
const addMoreStr = await prompt(`\n${colors.fg.yellow}Add another transaction? (y/n): ${colors.reset}`);
addMore = addMoreStr.toLowerCase() === 'y';
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
const targetPriceStr = await prompt(`\n${colors.fg.cyan}Enter target average price: $${colors.reset}`);
const currentPriceStr = await prompt(`${colors.fg.cyan}Enter current market price: $${colors.reset}`);
try {
const targetPrice = parseFloat(targetPriceStr);
const currentPrice = parseFloat(currentPriceStr);
const result = calculateOptimalAveragingStrategy(transactions, targetPrice, currentPrice);
console.log(`\n${colors.bright}${colors.fg.green}Target Average Strategy:${colors.reset}`);
console.log(`\nCurrent Average: $${result.currentAverage.toFixed(2)}`);
console.log(`Target Average: $${result.targetAverage.toFixed(2)}`);
if (!result.achievable) {
console.log(`\n${colors.fg.yellow}${result.message}${colors.reset}`);
} else {
if (result.suggestedAction) {
const action = result.suggestedAction.action;
const actionColor = action === 'BUY' ? colors.fg.green : colors.fg.red;
console.log(`\nSuggested Action: ${actionColor}${action}${colors.reset}`);
console.log(`Number of Shares: ${result.suggestedAction.shares}`);
console.log(`At Price: $${result.suggestedAction.price.toFixed(2)}`);
console.log(`Total Investment: $${result.suggestedAction.investment.toFixed(2)}`);
console.log(`\nAfter this transaction:`);
console.log(`Total Shares: ${result.newTotalShares}`);
console.log(`Total Cost: $${result.newTotalCost.toFixed(2)}`);
console.log(`New Average: $${result.targetAverage.toFixed(2)}`);
} else {
console.log(`\n${colors.fg.green}${result.message}${colors.reset}`);
}
}
} catch (error) {
console.error(`\n${colors.fg.red}Error: ${error.message}${colors.reset}\n`);
}
}
// Main function
async function main() {
displayWelcome();
let continueCalculating = true;
while (continueCalculating) {
displayCalculationTypes();
const typeChoice = await prompt(`${colors.fg.yellow}Select a calculation type (1-4): ${colors.reset}`);
switch (typeChoice) {
case '1':
await processQuickAverage();
break;
case '2':
await processPortfolioMetrics();
break;
case '3':
await processDCA();
break;
case '4':
await processTargetStrategy();
break;
default:
console.log(`\n${colors.fg.red}Invalid choice. Please try again.${colors.reset}\n`);
continue;
}
const continueStr = await prompt(`\n${colors.fg.yellow}Perform another calculation? (y/n): ${colors.reset}`);
continueCalculating = continueStr.toLowerCase() === 'y';
if (continueCalculating) {
console.log('\n');
}
}
console.log(`\n${colors.fg.cyan}Thank you for using the Stock Average Calculator!${colors.reset}\n`);
rl.close();
}
// Start the program
main().catch(error => {
console.error(`\n${colors.fg.red}An unexpected error occurred: ${error.message}${colors.reset}\n`);
rl.close();
});