UNPKG

@neabyte/chart-to-image

Version:

Convert trading charts to images using Node.js canvas with advanced features: 6 chart types, VWAP/EMA/SMA indicators, custom colors, themes, hide elements, scaling, and PNG/JPEG export formats.

2 lines • 5.52 kB
#!/usr/bin/env node import{ChartRenderer}from"./core/renderer.js";import{ChartConfig}from"./core/config.js";import{parseArgs,validateArgs,showHelp}from"./utils/cli.js";import{fetchMarketData,generateMultipleCharts}from"./index.js";import{ComparisonService}from"./core/comparison.js";async function main(){try{const o=parseArgs();if(o.help)return void showHelp();if(validateArgs(o)||process.exit(1),o.batch){console.log("šŸ”„ Processing batch charts...");const e=o.batch.map(o=>({symbol:o.symbol,outputPath:o.output,timeframe:o.timeframe||"1h",exchange:o.exchange||"binance",width:o.width||800,height:o.height||600,theme:o.theme||"dark"})),r=await generateMultipleCharts(e);return console.log("\nšŸ“Š Batch Results:"),void r.forEach((o,e)=>{o.success?console.log(`āœ… Chart ${e+1}: ${o.outputPath}`):console.log(`āŒ Chart ${e+1}: ${o.error}`)})}if(o.fetch){console.log(`šŸ“ˆ Fetching market data for ${o.symbol}...`);const e=await fetchMarketData(o.symbol,o.timeframe||"1h",o.exchange||"binance",o.limit||100);return console.log(`šŸ“Š Fetched ${e.length} candles`),void console.log("Sample data:",e.slice(0,3))}if(o.compare)return void await handleComparison(o);console.log(`šŸŽØ Generating chart for ${o.symbol}...`);const e={symbol:o.symbol,outputPath:o.output};if(o.timeframe&&(e.timeframe=o.timeframe),o.exchange&&(e.exchange=o.exchange),o.width&&(e.width=o.width),o.height&&(e.height=o.height),o.theme&&(e.theme=o.theme),o.backgroundColor&&(e.backgroundColor=o.backgroundColor),o.textColor&&(e.textColor=o.textColor),o.chartType&&(e.chartType=o.chartType),o.title&&(e.title=o.title),(o.scaleX||o.scaleY||o.autoScale||o.minScale||o.maxScale)&&(e.scale={},void 0!==o.scaleX&&(e.scale.x=o.scaleX),void 0!==o.scaleY&&(e.scale.y=o.scaleY),o.autoScale&&(e.scale.autoScale=!0),void 0!==o.minScale&&(e.scale.minScale=o.minScale),void 0!==o.maxScale&&(e.scale.maxScale=o.maxScale)),o.customColors){const r=o.customColors.split(",");e.customBarColors={},r.forEach(o=>{const[r,a]=o.split("=");r&&a&&(e.customBarColors[r.trim()]=a.trim())})}if(o.levels){const r=o.levels.split(",");e.horizontalLevels=r.map(o=>{const[e,r,a,t]=o.split(":");return{value:parseFloat(e),color:r,lineStyle:a,label:t,type:"custom"}})}o.watermark&&(o.watermarkPosition||o.watermarkColor||o.watermarkSize||o.watermarkOpacity?e.watermark={text:o.watermark,position:o.watermarkPosition,color:o.watermarkColor,fontSize:o.watermarkSize,opacity:o.watermarkOpacity}:e.watermark=o.watermark),o.hideTitle&&(e.showTitle=!1),o.hideTimeAxis&&(e.showTimeAxis=!1),o.hideGrid&&(e.showGrid=!1),o.showVWAP&&(e.showVWAP=!0),o.showEMA&&(e.showEMA=!0,e.emaPeriod=o.emaPeriod||20),o.showSMA&&(e.showSMA=!0,e.smaPeriod=o.smaPeriod||20),o.showBollingerBands&&(e.showBollingerBands=!0,e.bbPeriod=o.bbPeriod||20,e.bbStandardDeviations=o.bbStandardDeviations||2,(o.bbUpperColor||o.bbMiddleColor||o.bbLowerColor||o.bbBackgroundColor)&&(e.bbColors={},o.bbUpperColor&&(e.bbColors.upper=o.bbUpperColor),o.bbMiddleColor&&(e.bbColors.middle=o.bbMiddleColor),o.bbLowerColor&&(e.bbColors.lower=o.bbLowerColor),o.bbBackgroundColor&&(e.bbColors.background=o.bbBackgroundColor),void 0!==o.bbBackgroundOpacity&&(e.bbColors.backgroundOpacity=o.bbBackgroundOpacity)));const r=new ChartConfig(e),a=new ChartRenderer(r),t=await a.generateChart();t.success?(console.log(`āœ… Chart saved to: ${t.outputPath}`),t.dataUrl&&console.log(`šŸ“Š Data URL available: ${t.dataUrl.substring(0,50)}...`)):(console.error(`āŒ Failed to generate chart: ${t.error}`),process.exit(1))}catch(o){console.error("āŒ Error:",o instanceof Error?o.message:o),process.exit(1)}}async function handleComparison(o){o.compare||(console.error("Error: --compare requires comma-separated symbols"),process.exit(1)),o.output||(console.error("Error: --output is required for comparison charts"),process.exit(1));const e=o.compare.split(",").map(o=>o.trim());e.length<2&&(console.error("Error: Comparison requires at least 2 symbols"),process.exit(1)),console.log(`šŸ”„ Generating comparison chart for: ${e.join(", ")}`);const r={symbols:e,outputPath:o.output,timeframe:o.timeframe,exchange:o.exchange,theme:o.theme,chartType:o.chartType,showVWAP:o.showVWAP,showEMA:o.showEMA,emaPeriod:o.emaPeriod,showSMA:o.showSMA,smaPeriod:o.smaPeriod,showBollingerBands:o.showBollingerBands,bbPeriod:o.bbPeriod,bbStandardDeviations:o.bbStandardDeviations};if(o.showBollingerBands&&(o.bbUpperColor||o.bbMiddleColor||o.bbLowerColor||o.bbBackgroundColor)&&(r.bbColors={},o.bbUpperColor&&(r.bbColors.upper=o.bbUpperColor),o.bbMiddleColor&&(r.bbColors.middle=o.bbMiddleColor),o.bbLowerColor&&(r.bbColors.lower=o.bbLowerColor),o.bbBackgroundColor&&(r.bbColors.background=o.bbBackgroundColor),void 0!==o.bbBackgroundOpacity&&(r.bbColors.backgroundOpacity=o.bbBackgroundOpacity)),o.customColors){const e=o.customColors.split(","),a={};e.forEach(o=>{const[e,r]=o.split("=");e&&r&&(a[e.trim()]=r.trim())}),Object.keys(a).length>0&&(r.customBarColors=a)}if(o.timeframes){const e=o.timeframes.split(",").map(o=>o.trim());r.timeframes=e}let a;if("grid"===o.layout){const t=o.columns||2;a=await ComparisonService.grid(e,t,o.output,r)}else a=await ComparisonService.sideBySide(e,o.output,r);a.success?console.log(`āœ… Comparison chart saved to: ${a.outputPath}`):(console.error(`āŒ Failed to generate comparison: ${a.error}`),process.exit(1))}process.on("uncaughtException",o=>{console.error("āŒ Uncaught Exception:",o.message),process.exit(1)}),process.on("unhandledRejection",o=>{console.error("āŒ Unhandled Rejection:",o),process.exit(1)}),main();