UNPKG

stock-average-calculator

Version:

A comprehensive utility for calculating stock price averages and managing investment portfolios

313 lines (254 loc) 10.9 kB
#!/usr/bin/env node 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(); });