@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 • 2.98 kB
JavaScript
import{CONSTANTS}from"../constants.js";import{CandleSet}from"../chart/candle-set.js";export class ChartData{mainCandleSet;visibleCandleSet;terminalSize={width:0,height:0};height=0;width=0;constructor(t,e={}){this.mainCandleSet=new CandleSet(t),this.visibleCandleSet=new CandleSet([]);const{width:i=0,height:s=0}=e;this.setSize(i||this.getTerminalSize().width,s||this.getTerminalSize().height),this.computeVisibleCandles()}getTerminalSize(){if(void 0===globalThis.process||!globalThis.process.stdout)return{width:120,height:30};const t=this.tryGetWindowSize();if(t)return t;const e=this.tryGetStdoutSize();if(e)return e;const i=this.tryGetEnvSize();return i||{width:120,height:30}}tryGetWindowSize(){try{if(globalThis.process.stdout.isTTY){const[t,e]=globalThis.process.stdout.getWindowSize();if(t&&e&&t>0&&e>0)return{width:t,height:e}}}catch{}return null}tryGetStdoutSize(){try{const{columns:t,rows:e}=globalThis.process.stdout;if(t&&e&&t>0&&e>0)return{width:t,height:e}}catch{}return null}tryGetEnvSize(){try{const t=globalThis.process.env.COLUMNS?parseInt(globalThis.process.env.COLUMNS):null,e=globalThis.process.env.LINES?parseInt(globalThis.process.env.LINES):null;if(t&&e&&t>0&&e>0)return{width:t,height:e}}catch{}return null}computeHeight(t){const e=t||0,i=this.terminalSize.height-CONSTANTS.MARGIN_TOP-e;this.height=Math.max(i-2,10)}computeVisibleCandles(){const t=this.getTerminalSize().width-CONSTANTS.WIDTH-this.margins.left-this.margins.right,e=this.mainCandleSet.candles;let i=e;if("fixed"===this.scalingMode&&this.timeRange){const{start:t,end:s}=this.timeRange;i=e.slice(t,s+1)}else if("price"===this.scalingMode&&this.priceRange){const{min:t,max:s}=this.priceRange;i=e.filter(e=>{const i=Math.min(e.open,e.close),n=Math.max(e.open,e.close);return i<=s&&n>=t})}else i=(this.scalingMode,this.sampleCandlesForWidth(e,t));this.visibleCandleSet.setCandles(i)}sampleCandlesForWidth(t,e){const i=t.length;if(0===i)return[];const s=Math.max(1,Math.floor((e-2)/1.1));if(i<=s)return t;const n=Math.max(0,i-s);return t.slice(n)}resetCandles(){this.mainCandleSet.setCandles([]),this.visibleCandleSet.setCandles([])}addCandles(t){this.mainCandleSet.addCandles(t),this.visibleCandleSet.setCandles([])}setSize(t,e){this.terminalSize={width:t,height:e},this.width=t,this.height=e}margins={top:3,right:4,bottom:2,left:0};scalingMode="fit";timeRange;priceRange;setMargins(t,e,i,s){this.margins={top:t,right:e,bottom:i,left:s},this.computeVisibleCandles()}setScalingMode(t){this.scalingMode=t,this.computeVisibleCandles()}setPriceRange(t,e){if(t>=e)throw new Error("Minimum price must be less than maximum price");this.priceRange={min:t,max:e},this.computeVisibleCandles()}setTimeRange(t,e){if(t>=e)throw new Error("Start index must be less than end index");if(t<0||e<0)throw new Error("Indices must be non-negative");this.timeRange={start:t,end:e},this.computeVisibleCandles()}fitToData(){this.scalingMode="fit",this.timeRange=void 0,this.priceRange=void 0,this.computeVisibleCandles()}}