@neabyte/candlestick-cli
Version:
Beautiful terminal candlestick charts with real-time trading data. Create stunning ASCII art charts directly in your terminal with support for live market data, custom colors, and professional trading visualization.
1 lines • 3.36 kB
JavaScript
import{existsSync}from"fs";async function showBanner(){const{default:e}=await import("figlet"),o=e.textSync("Candlestick-CLI",{font:"Slant",horizontalLayout:"fitted",verticalLayout:"default"});console.log(o)}export function validateFile(e){if(!e)throw new Error("File path is required. Use --file or -f option.");if(!e.endsWith(".csv")&&!e.endsWith(".json"))throw new Error("Unsupported file format. Use .csv or .json files.");if(!existsSync(e))throw new Error(`File not found: ${e}`)}export function validateLiveDataOptions(e,o,r){if(!e||"string"!=typeof e)throw new Error("Symbol is required for live data. Use --symbol or -s option.");if(!/^[A-Z]+\/[A-Z]+(:[A-Z]+)?$/.test(e))throw new Error(`Invalid symbol format: ${e}. Use format like BTC/USDT or BTC/USDT:USDT`);const t=["1m","3m","5m","15m","30m","1h","2h","4h","6h","8h","12h","1d","3d","1w","1M"];if(!t.includes(o))throw new Error(`Invalid timeframe: ${o}. Supported: ${t.join(", ")}`);if(r<5||r>1e4)throw new Error("Limit must be between 5 and 10,000 candles")}export function validateCandleFields(e,o){const r=["open","high","low","close"];for(const t of r)if("number"!=typeof e[t]||isNaN(e[t]))throw new Error(`Invalid ${t} value at candle ${o+1}: ${e[t]}`)}export function validateCandleOHLC(e,o){const r=e.high,t=e.low,n=e.open,i=e.close;if(r<t)throw new Error(`Invalid OHLC at candle ${o+1}: high (${r}) cannot be less than low (${t})`);if(n<0||r<0||t<0||i<0)throw new Error(`Invalid negative price at candle ${o+1}`)}export function validateCandleVolume(e,o){if(void 0!==e.volume){if("number"!=typeof e.volume||isNaN(e.volume))throw new Error(`Invalid volume value at candle ${o+1}: ${e.volume}`);if(e.volume<0)throw new Error(`Invalid negative volume at candle ${o+1}`)}}export function validateData(e){if(!Array.isArray(e))throw new Error("Data must be an array of candles");if(e.length<5)throw new Error(`Insufficient data: ${e.length} candles. Minimum required: 5`);if(e.length>1e4)throw new Error(`Too much data: ${e.length} candles. Maximum allowed: 10,000`);e.forEach((e,o)=>{validateCandleFields(e,o),validateCandleOHLC(e,o),validateCandleVolume(e,o)})}export function parseColor(e){if(e.startsWith("#")){const o=e.slice(1);return[parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)]}if(e.includes(",")){const[o,r,t]=e.split(",").map(e=>parseInt(e.trim()));return[o,r,t]}}export function validateColor(e,o){const r=parseColor(e);if(!r)throw new Error(`Invalid ${o} color format: ${e}. Use hex (#ff0000) or RGB (255,0,0) format.`);return r}export function validateDimensions(e,o){if(void 0!==e&&(e<0||e>1e3))throw new Error("Width must be between 0 and 1000");if(void 0!==o&&(o<0||o>1e3))throw new Error("Height must be between 0 and 1000")}export function validateVolumeHeight(e){if(void 0!==e&&(e<1||e>20))throw new Error("Volume height must be between 1 and 20")}export async function validateInputSource(e){e.file||e.symbol||(await showBanner(),console.error("❌ Error: Either file path or symbol is required."),console.error("💡 Use --file/-f for file input or --symbol/-s for live data."),console.error("💡 Use --help for more information."),process.exit(1)),e.file&&e.symbol&&(await showBanner(),console.error("❌ Error: Cannot use both file and symbol options."),console.error("💡 Use either --file/-f OR --symbol/-s, not both."),process.exit(1))}