dipping-charts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/__tests__/FullFeaturedChart.test.d.ts +2 -0
- package/dist/__tests__/FullFeaturedChart.test.d.ts.map +1 -0
- package/dist/__tests__/indicators-accuracy.test.d.ts +2 -0
- package/dist/__tests__/indicators-accuracy.test.d.ts.map +1 -0
- package/dist/__tests__/indicators.test.d.ts +2 -0
- package/dist/__tests__/indicators.test.d.ts.map +1 -0
- package/dist/__tests__/setup.d.ts +1 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/validateCandle.test.d.ts +2 -0
- package/dist/__tests__/validateCandle.test.d.ts.map +1 -0
- package/dist/chart/index.d.ts +2 -0
- package/dist/chart/index.js +5 -0
- package/dist/chart/index.js.map +1 -0
- package/dist/components/TradingChart.d.ts +24 -0
- package/dist/components/TradingChart.d.ts.map +1 -0
- package/dist/components/TradingChart.js +100 -0
- package/dist/components/TradingChart.js.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/dipping-charts.css +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/indicators/atr.d.ts +15 -0
- package/dist/indicators/atr.d.ts.map +1 -0
- package/dist/indicators/atr.js +30 -0
- package/dist/indicators/atr.js.map +1 -0
- package/dist/indicators/bollingerBands.d.ts +11 -0
- package/dist/indicators/bollingerBands.d.ts.map +1 -0
- package/dist/indicators/bollingerBands.js +39 -0
- package/dist/indicators/bollingerBands.js.map +1 -0
- package/dist/indicators/currencyStrength.d.ts +43 -0
- package/dist/indicators/currencyStrength.d.ts.map +1 -0
- package/dist/indicators/currencyStrength.js +53 -0
- package/dist/indicators/currencyStrength.js.map +1 -0
- package/dist/indicators/ema.d.ts +11 -0
- package/dist/indicators/ema.d.ts.map +1 -0
- package/dist/indicators/ema.js +24 -0
- package/dist/indicators/ema.js.map +1 -0
- package/dist/indicators/index.d.ts +19 -0
- package/dist/indicators/index.d.ts.map +1 -0
- package/dist/indicators/index.js +23 -0
- package/dist/indicators/index.js.map +1 -0
- package/dist/indicators/macd.d.ts +11 -0
- package/dist/indicators/macd.d.ts.map +1 -0
- package/dist/indicators/macd.js +52 -0
- package/dist/indicators/macd.js.map +1 -0
- package/dist/indicators/rsi.d.ts +11 -0
- package/dist/indicators/rsi.d.ts.map +1 -0
- package/dist/indicators/rsi.js +29 -0
- package/dist/indicators/rsi.js.map +1 -0
- package/dist/indicators/sma.d.ts +13 -0
- package/dist/indicators/sma.d.ts.map +1 -0
- package/dist/indicators/sma.js +22 -0
- package/dist/indicators/sma.js.map +1 -0
- package/dist/indicators/stochastic.d.ts +15 -0
- package/dist/indicators/stochastic.d.ts.map +1 -0
- package/dist/indicators/stochastic.js +34 -0
- package/dist/indicators/stochastic.js.map +1 -0
- package/dist/indicators/types.d.ts +102 -0
- package/dist/indicators/types.d.ts.map +1 -0
- package/dist/indicators/vwap.d.ts +14 -0
- package/dist/indicators/vwap.d.ts.map +1 -0
- package/dist/indicators/vwap.js +17 -0
- package/dist/indicators/vwap.js.map +1 -0
- package/dist/indicators/williamsR.d.ts +17 -0
- package/dist/indicators/williamsR.d.ts.map +1 -0
- package/dist/indicators/williamsR.js +19 -0
- package/dist/indicators/williamsR.js.map +1 -0
- package/dist/react/FullFeaturedChart.d.ts +3 -0
- package/dist/react/FullFeaturedChart.d.ts.map +1 -0
- package/dist/react/FullFeaturedChart.js +640 -0
- package/dist/react/FullFeaturedChart.js.map +1 -0
- package/dist/react/components/IndicatorSettings.d.ts +20 -0
- package/dist/react/components/IndicatorSettings.d.ts.map +1 -0
- package/dist/react/components/IndicatorSettings.js +748 -0
- package/dist/react/components/IndicatorSettings.js.map +1 -0
- package/dist/react/hooks/useChart.d.ts +15 -0
- package/dist/react/hooks/useChart.d.ts.map +1 -0
- package/dist/react/hooks/useChart.js +155 -0
- package/dist/react/hooks/useChart.js.map +1 -0
- package/dist/react/hooks/useIndicators.d.ts +10 -0
- package/dist/react/hooks/useIndicators.d.ts.map +1 -0
- package/dist/react/hooks/useIndicators.js +264 -0
- package/dist/react/hooks/useIndicators.js.map +1 -0
- package/dist/react/hooks/useLineTools.d.ts +26 -0
- package/dist/react/hooks/useLineTools.d.ts.map +1 -0
- package/dist/react/hooks/useLineTools.js +189 -0
- package/dist/react/hooks/useLineTools.js.map +1 -0
- package/dist/react/hooks/useShiftSnap.d.ts +12 -0
- package/dist/react/hooks/useShiftSnap.d.ts.map +1 -0
- package/dist/react/hooks/useShiftSnap.js +54 -0
- package/dist/react/hooks/useShiftSnap.js.map +1 -0
- package/dist/react/index.d.ts +14 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +18 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/loadLightweightCharts.d.ts +18 -0
- package/dist/react/loadLightweightCharts.d.ts.map +1 -0
- package/dist/react/loadLightweightCharts.js +32 -0
- package/dist/react/loadLightweightCharts.js.map +1 -0
- package/dist/react/locale.d.ts +79 -0
- package/dist/react/locale.d.ts.map +1 -0
- package/dist/react/locale.js +158 -0
- package/dist/react/locale.js.map +1 -0
- package/dist/react/types.d.ts +130 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/getToolId.d.ts +9 -0
- package/dist/utils/getToolId.d.ts.map +1 -0
- package/dist/utils/getToolId.js +12 -0
- package/dist/utils/getToolId.js.map +1 -0
- package/dist/utils/mockData.d.ts +10 -0
- package/dist/utils/mockData.d.ts.map +1 -0
- package/dist/utils/mockData.js +61 -0
- package/dist/utils/mockData.js.map +1 -0
- package/dist/utils/snapCrosshair.d.ts +25 -0
- package/dist/utils/snapCrosshair.d.ts.map +1 -0
- package/dist/utils/validateCandle.d.ts +30 -0
- package/dist/utils/validateCandle.d.ts.map +1 -0
- package/dist/utils/validateCandle.js +21 -0
- package/dist/utils/validateCandle.js.map +1 -0
- package/examples/css/base.css +209 -0
- package/examples/css/chart.css +282 -0
- package/examples/css/indicators.css +255 -0
- package/examples/index.html +163 -0
- package/examples/js/chart.js +370 -0
- package/examples/js/indicators.js +27 -0
- package/examples/js/main.js +6 -0
- package/examples/js/ui.js +1641 -0
- package/lib/lightweight-charts.standalone.production.js +7 -0
- package/package.json +106 -0
- package/src/react/FullFeaturedChart.css +1007 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndicatorSettings.js","sources":["../../../src/react/components/IndicatorSettings.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { IndicatorType, IndicatorConfig, BollingerBandsConfig, MACDConfig, StochasticConfig, VWAPConfig, IndicatorConfigs } from '../types';\nimport type { Locale, LocaleStrings } from '../locale';\nimport { getLocaleStrings } from '../locale';\n\nconst COLOR_PALETTE = [\n '#3C4043', '#1A73E8', '#9334E6', '#B80000', '#E37400', '#F9AB00', '#007B83', '#1E8E3E',\n '#5F6368', '#4285F4', '#A142F4', '#D93025', '#F57C00', '#FDD835', '#12B5CB', '#34A853',\n '#9AA0A6', '#8AB4F8', '#C58AF9', '#EE675C', '#FF8A65', '#FFB300', '#4DB6AC', '#81C995',\n '#DADCE0', '#AECBFA', '#D7AEFB', '#F28B82', '#FFAB91', '#FFD54F', '#80DEEA', '#A5D6A7'\n];\n\nconst DEFAULT_COLORS = ['#26a69a', '#ef5350', '#2196f3', '#ff6f00', '#ab47bc', '#66bb6a', '#ffa726', '#42a5f5'];\n\nfunction getIndicatorInfo(t: LocaleStrings) {\n return {\n sma: { title: t.ind_sma, desc: t.ind_sma_desc, defaultValue: 20 },\n ema: { title: t.ind_ema, desc: t.ind_ema_desc, defaultValue: 12 },\n rsi: { title: t.ind_rsi, desc: t.ind_rsi_desc, defaultValue: 14 },\n macd: { title: t.ind_macd, desc: t.ind_macd_desc, defaultValue: 26 },\n bbands: { title: t.ind_bbands, desc: t.ind_bbands_desc, defaultValue: 20 },\n stochastic: { title: t.ind_stochastic, desc: t.ind_stochastic_desc, defaultValue: 14 },\n atr: { title: t.ind_atr, desc: t.ind_atr_desc, defaultValue: 14 },\n vwap: { title: t.ind_vwap, desc: t.ind_vwap_desc, defaultValue: 0 },\n williamsR: { title: t.ind_williamsR, desc: t.ind_williamsR_desc, defaultValue: 14 },\n };\n}\n\ninterface ColorPalettePopupProps {\n currentColor: string;\n onSelect: (color: string) => void;\n onClose: () => void;\n position: { top: number; left: number };\n colorTitle?: string;\n}\n\nfunction ColorPalettePopup({ currentColor, onSelect, onClose, position, colorTitle = 'Color' }: ColorPalettePopupProps) {\n const paletteRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (paletteRef.current && !paletteRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n\n // 약간의 지연 후 이벤트 리스너 등록 (현재 클릭 이벤트가 완료된 후)\n const timer = setTimeout(() => {\n document.addEventListener('mousedown', handleClickOutside);\n }, 100);\n\n return () => {\n clearTimeout(timer);\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [onClose]);\n\n const paletteElement = (\n <div\n ref={paletteRef}\n className=\"color-palette-popup show\"\n style={{\n top: position.top,\n left: position.left\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"color-palette-title\">{colorTitle}</div>\n <div className=\"color-palette-grid\">\n {COLOR_PALETTE.map(color => (\n <div\n key={color}\n className={`color-palette-item ${color === currentColor ? 'selected' : ''}`}\n style={{ background: color }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect(color);\n onClose();\n }}\n />\n ))}\n </div>\n </div>\n );\n\n // Portal을 사용해 document.body에 직접 렌더링\n return createPortal(paletteElement, document.body);\n}\n\ninterface IndicatorSettingsProps {\n indicator: IndicatorType | null;\n configs: IndicatorConfigs;\n isChecked: boolean;\n onConfigChange: (indicator: IndicatorType, configs: any[]) => void;\n macdColors: { line: string; signal: string };\n onMacdColorsChange: (colors: { line: string; signal: string }) => void;\n locale?: Locale;\n}\n\nexport function IndicatorSettings({\n indicator,\n configs,\n isChecked,\n onConfigChange,\n macdColors,\n onMacdColorsChange,\n locale: localeProp = 'en',\n}: IndicatorSettingsProps) {\n const t = getLocaleStrings(localeProp);\n const INDICATOR_INFO = getIndicatorInfo(t);\n const [colorPaletteOpen, setColorPaletteOpen] = useState<{ index?: number; type?: string; position: { top: number; left: number } } | null>(null);\n\n if (!indicator) {\n return <div className=\"indicator-empty-state\">{t.selectIndicator}</div>;\n }\n\n const info = INDICATOR_INFO[indicator];\n const config = configs[indicator];\n\n if (!isChecked || config.length === 0) {\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div className=\"indicator-empty-state\">{t.enableIndicator}</div>\n </div>\n );\n }\n\n const handleColorClick = (e: React.MouseEvent, index?: number, type?: string) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n setColorPaletteOpen({\n index,\n type,\n position: { top: rect.bottom + 5, left: rect.left }\n });\n };\n\n // RSI\n if (indicator === 'rsi') {\n const rsiConfig = config[0] as IndicatorConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start', marginBottom: 12 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.color}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: rsiConfig.color, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, 0)}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.period}</div>\n <input\n type=\"number\"\n value={rsiConfig.value}\n onChange={(e) => onConfigChange(indicator, [{ ...rsiConfig, value: parseInt(e.target.value) || 14 }])}\n min=\"1\"\n max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n </div>\n <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.oversold}</div>\n <input\n type=\"number\"\n value={rsiConfig.oversold ?? 30}\n onChange={(e) => onConfigChange(indicator, [{ ...rsiConfig, oversold: parseInt(e.target.value) || 30 }])}\n min=\"0\"\n max=\"100\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.overbought}</div>\n <input\n type=\"number\"\n value={rsiConfig.overbought ?? 70}\n onChange={(e) => onConfigChange(indicator, [{ ...rsiConfig, overbought: parseInt(e.target.value) || 70 }])}\n min=\"0\"\n max=\"100\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.index === 0 && (\n <ColorPalettePopup\n currentColor={rsiConfig.color}\n onSelect={(color) => onConfigChange(indicator, [{ ...rsiConfig, color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // MACD\n if (indicator === 'macd') {\n const macdConfig = config[0] as MACDConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.ind_macd}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: macdColors.line, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'macd-line')}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.signal}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: macdColors.signal, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'macd-signal')}\n />\n </div>\n </div>\n\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.bullish}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: macdConfig.histUpColor || '#26a69a', width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'hist-up')}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.bearish}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: macdConfig.histDownColor || '#ef5350', width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'hist-down')}\n />\n </div>\n </div>\n\n <div style={{ display: 'flex', gap: 8 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.fast}</div>\n <input\n type=\"number\"\n value={macdConfig.fastPeriod}\n onChange={(e) => onConfigChange(indicator, [{ ...macdConfig, fastPeriod: parseInt(e.target.value) || 12 }])}\n min=\"1\"\n max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.slow}</div>\n <input\n type=\"number\"\n value={macdConfig.slowPeriod}\n onChange={(e) => onConfigChange(indicator, [{ ...macdConfig, slowPeriod: parseInt(e.target.value) || 26 }])}\n min=\"1\"\n max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.signal}</div>\n <input\n type=\"number\"\n value={macdConfig.signalPeriod}\n onChange={(e) => onConfigChange(indicator, [{ ...macdConfig, signalPeriod: parseInt(e.target.value) || 9 }])}\n min=\"1\"\n max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.type === 'macd-line' && (\n <ColorPalettePopup\n currentColor={macdColors.line}\n onSelect={(color) => onMacdColorsChange({ ...macdColors, line: color })}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'macd-signal' && (\n <ColorPalettePopup\n currentColor={macdColors.signal}\n onSelect={(color) => onMacdColorsChange({ ...macdColors, signal: color })}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'hist-up' && (\n <ColorPalettePopup\n currentColor={macdConfig.histUpColor || '#26a69a'}\n onSelect={(color) => onConfigChange(indicator, [{ ...macdConfig, histUpColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'hist-down' && (\n <ColorPalettePopup\n currentColor={macdConfig.histDownColor || '#ef5350'}\n onSelect={(color) => onConfigChange(indicator, [{ ...macdConfig, histDownColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // Bollinger Bands\n if (indicator === 'bbands') {\n const bbConfig = config[0] as BollingerBandsConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.upper}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: bbConfig.upperColor, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'bb-upper')}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.middle}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: bbConfig.middleColor, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'bb-middle')}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.lower}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: bbConfig.lowerColor, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'bb-lower')}\n />\n </div>\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.period}</div>\n <input\n type=\"number\"\n value={bbConfig.value}\n onChange={(e) => onConfigChange(indicator, [{ ...bbConfig, value: parseInt(e.target.value) || 20 }])}\n min=\"1\"\n max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40 }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.stdDev}</div>\n <input\n type=\"number\"\n value={bbConfig.stdDev}\n onChange={(e) => onConfigChange(indicator, [{ ...bbConfig, stdDev: parseFloat(e.target.value) || 2 }])}\n min=\"0.5\"\n max=\"5\"\n step=\"0.1\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40 }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.thickness}</div>\n <div\n style={{ width: '100%', height: 40, border: '1px solid #e0e0e0', borderRadius: 6, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 500, cursor: 'pointer', background: 'white' }}\n onClick={() => onConfigChange(indicator, [{ ...bbConfig, thickness: (bbConfig.thickness % 5) + 1 }])}\n >\n {bbConfig.thickness}px\n </div>\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.type === 'bb-upper' && (\n <ColorPalettePopup\n currentColor={bbConfig.upperColor}\n onSelect={(color) => onConfigChange(indicator, [{ ...bbConfig, upperColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'bb-middle' && (\n <ColorPalettePopup\n currentColor={bbConfig.middleColor}\n onSelect={(color) => onConfigChange(indicator, [{ ...bbConfig, middleColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'bb-lower' && (\n <ColorPalettePopup\n currentColor={bbConfig.lowerColor}\n onSelect={(color) => onConfigChange(indicator, [{ ...bbConfig, lowerColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // Stochastic\n if (indicator === 'stochastic') {\n const stochConfig = config[0] as StochasticConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.kLine}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: stochConfig.kColor, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'stoch-k')}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.dLine}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: stochConfig.dColor, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, undefined, 'stoch-d')}\n />\n </div>\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.kPeriod}</div>\n <input\n type=\"number\"\n value={stochConfig.kPeriod}\n onChange={(e) => onConfigChange(indicator, [{ ...stochConfig, kPeriod: parseInt(e.target.value) || 14 }])}\n min=\"1\" max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.dPeriod}</div>\n <input\n type=\"number\"\n value={stochConfig.dPeriod}\n onChange={(e) => onConfigChange(indicator, [{ ...stochConfig, dPeriod: parseInt(e.target.value) || 3 }])}\n min=\"1\" max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.smooth}</div>\n <input\n type=\"number\"\n value={stochConfig.smooth}\n onChange={(e) => onConfigChange(indicator, [{ ...stochConfig, smooth: parseInt(e.target.value) || 3 }])}\n min=\"1\" max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.type === 'stoch-k' && (\n <ColorPalettePopup\n currentColor={stochConfig.kColor}\n onSelect={(color) => onConfigChange(indicator, [{ ...stochConfig, kColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n {colorPaletteOpen && colorPaletteOpen.type === 'stoch-d' && (\n <ColorPalettePopup\n currentColor={stochConfig.dColor}\n onSelect={(color) => onConfigChange(indicator, [{ ...stochConfig, dColor: color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // VWAP\n if (indicator === 'vwap') {\n const vwapConfig = config[0] as VWAPConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.color}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: vwapConfig.color, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, 0)}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.thickness}</div>\n <div\n style={{ width: '100%', height: 40, border: '1px solid #e0e0e0', borderRadius: 6, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, fontWeight: 500, cursor: 'pointer', background: 'white' }}\n onClick={() => onConfigChange(indicator, [{ ...vwapConfig, thickness: (vwapConfig.thickness % 5) + 1 }])}\n >\n {vwapConfig.thickness}px\n </div>\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.index === 0 && (\n <ColorPalettePopup\n currentColor={vwapConfig.color}\n onSelect={(color) => onConfigChange(indicator, [{ ...vwapConfig, color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // ATR, Williams %R — single period indicator (like RSI but without oversold/overbought)\n if (indicator === 'atr' || indicator === 'williamsR') {\n const singleConfig = config[0] as IndicatorConfig;\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n <div style={{ marginTop: 16 }}>\n <div style={{ display: 'flex', gap: 12, alignItems: 'flex-start' }}>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.color}</div>\n <div\n className=\"period-color-picker\"\n style={{ background: singleConfig.color, width: '100%', height: 40, cursor: 'pointer', borderRadius: 6, border: '1px solid #e0e0e0' }}\n onClick={(e) => handleColorClick(e, 0)}\n />\n </div>\n <div style={{ flex: 1 }}>\n <div style={{ fontSize: 13, color: '#666', marginBottom: 8 }}>{t.period}</div>\n <input\n type=\"number\"\n value={singleConfig.value}\n onChange={(e) => onConfigChange(indicator, [{ ...singleConfig, value: parseInt(e.target.value) || 14 }])}\n min=\"1\" max=\"500\"\n style={{ width: '100%', padding: 8, border: '1px solid #e0e0e0', borderRadius: 6, fontSize: 14, height: 40, boxSizing: 'border-box' }}\n />\n </div>\n </div>\n </div>\n {colorPaletteOpen && colorPaletteOpen.index === 0 && (\n <ColorPalettePopup\n currentColor={singleConfig.color}\n onSelect={(color) => onConfigChange(indicator, [{ ...singleConfig, color }])}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n }\n\n // SMA, EMA - 다중 기간 지원\n return (\n <div>\n <div className=\"indicator-settings-title\">{info.title}</div>\n <div className=\"indicator-settings-desc\">{info.desc}</div>\n {(config as IndicatorConfig[]).map((cfg, index) => (\n <div key={index} className=\"indicator-period-row\">\n <span className=\"period-label-col\">{t.periodN(index + 1)}</span>\n <div\n className=\"period-color-picker\"\n style={{ background: cfg.color, cursor: 'pointer' }}\n onClick={(e) => handleColorClick(e, index)}\n />\n <div\n className=\"period-thickness-display\"\n onClick={() => {\n const newConfigs = [...(config as IndicatorConfig[])];\n newConfigs[index] = { ...newConfigs[index], thickness: (newConfigs[index].thickness % 5) + 1 };\n onConfigChange(indicator, newConfigs);\n }}\n >\n {cfg.thickness}px\n </div>\n <select\n className=\"period-source-dropdown\"\n value={cfg.source}\n onChange={(e) => {\n const newConfigs = [...(config as IndicatorConfig[])];\n newConfigs[index] = { ...newConfigs[index], source: e.target.value as any };\n onConfigChange(indicator, newConfigs);\n }}\n >\n <option value=\"close\">{t.src_close}</option>\n <option value=\"open\">{t.src_open}</option>\n <option value=\"high\">{t.src_high}</option>\n <option value=\"low\">{t.src_low}</option>\n </select>\n <input\n type=\"number\"\n className=\"period-value-field\"\n value={cfg.value}\n onChange={(e) => {\n const newConfigs = [...(config as IndicatorConfig[])];\n newConfigs[index] = { ...newConfigs[index], value: parseInt(e.target.value) || 1 };\n onConfigChange(indicator, newConfigs);\n }}\n min=\"1\"\n max=\"500\"\n />\n {config.length > 1 && (\n <button\n className=\"period-delete-btn\"\n onClick={() => {\n const newConfigs = (config as IndicatorConfig[]).filter((_, i) => i !== index);\n onConfigChange(indicator, newConfigs);\n }}\n >\n ×\n </button>\n )}\n </div>\n ))}\n <button\n className=\"add-period-button\"\n onClick={() => {\n const lastConfig = (config as IndicatorConfig[])[config.length - 1];\n const nextColorIdx = (DEFAULT_COLORS.indexOf(lastConfig.color) + 1) % DEFAULT_COLORS.length;\n onConfigChange(indicator, [\n ...(config as IndicatorConfig[]),\n {\n color: DEFAULT_COLORS[nextColorIdx],\n thickness: 2,\n source: 'close' as const,\n value: info.defaultValue\n }\n ]);\n }}\n >\n {t.addPeriod}\n </button>\n {colorPaletteOpen && colorPaletteOpen.index !== undefined && (\n <ColorPalettePopup\n currentColor={(config as IndicatorConfig[])[colorPaletteOpen.index].color}\n onSelect={(color) => {\n const newConfigs = [...(config as IndicatorConfig[])];\n newConfigs[colorPaletteOpen.index!] = { ...newConfigs[colorPaletteOpen.index!], color };\n onConfigChange(indicator, newConfigs);\n }}\n onClose={() => setColorPaletteOpen(null)}\n position={colorPaletteOpen.position}\n colorTitle={t.colorPaletteTitle}\n />\n )}\n </div>\n );\n}\n"],"names":["COLOR_PALETTE","DEFAULT_COLORS","getIndicatorInfo","t","ColorPalettePopup","currentColor","onSelect","onClose","position","colorTitle","paletteRef","useRef","useEffect","handleClickOutside","e","timer","paletteElement","jsxs","jsx","color","createPortal","IndicatorSettings","indicator","configs","isChecked","onConfigChange","macdColors","onMacdColorsChange","localeProp","getLocaleStrings","INDICATOR_INFO","colorPaletteOpen","setColorPaletteOpen","useState","info","config","handleColorClick","index","type","rect","rsiConfig","macdConfig","bbConfig","stochConfig","vwapConfig","singleConfig","cfg","newConfigs","_","i","lastConfig","nextColorIdx"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IChartApi, ISeriesApi } from 'lightweight-charts';
|
|
2
|
+
import { CandleData } from '../../types';
|
|
3
|
+
export interface UseChartOptions {
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface UseChartReturn {
|
|
8
|
+
chartRef: React.RefObject<HTMLDivElement | null>;
|
|
9
|
+
chart: IChartApi | null;
|
|
10
|
+
candleSeries: ISeriesApi<'Candlestick'> | null;
|
|
11
|
+
volumeSeries: ISeriesApi<'Histogram'> | null;
|
|
12
|
+
setData: (data: CandleData[], shouldFit?: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function useChart(options?: UseChartOptions): UseChartReturn;
|
|
15
|
+
//# sourceMappingURL=useChart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useChart.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useChart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAQ,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACjD,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC/C,YAAY,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;IAC7C,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5D;AAED,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CAiRtE"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { useRef as s, useState as C, useEffect as V } from "react";
|
|
2
|
+
import { filterValidCandles as z } from "../../utils/validateCandle.js";
|
|
3
|
+
import { loadLightweightCharts as I } from "../loadLightweightCharts.js";
|
|
4
|
+
function x(h = {}) {
|
|
5
|
+
const i = s(null), r = s(null), a = s(null), u = s(null), n = s(!1), m = s(null), [L, v] = C(null), [F, y] = C(null), [k, S] = C(null);
|
|
6
|
+
V(() => {
|
|
7
|
+
if (!i.current) return;
|
|
8
|
+
let o = !1;
|
|
9
|
+
return n.current = !1, (async () => {
|
|
10
|
+
let l;
|
|
11
|
+
try {
|
|
12
|
+
l = await I();
|
|
13
|
+
} catch {
|
|
14
|
+
if (typeof LightweightCharts < "u")
|
|
15
|
+
l = LightweightCharts;
|
|
16
|
+
else {
|
|
17
|
+
console.error("[useChart] LightweightCharts is not loaded. Make sure to include the script in your HTML or place the standalone JS in a known path.");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (o || !i.current) return;
|
|
22
|
+
const { createChart: f } = l, d = h.width || i.current.clientWidth, b = h.height || 600, e = f(i.current, {
|
|
23
|
+
width: d,
|
|
24
|
+
height: b,
|
|
25
|
+
layout: {
|
|
26
|
+
background: { color: "#ffffff" },
|
|
27
|
+
textColor: "#333"
|
|
28
|
+
},
|
|
29
|
+
grid: {
|
|
30
|
+
vertLines: { color: "#f0f0f0" },
|
|
31
|
+
horzLines: { color: "#f0f0f0" }
|
|
32
|
+
},
|
|
33
|
+
crosshair: {
|
|
34
|
+
mode: 0
|
|
35
|
+
},
|
|
36
|
+
rightPriceScale: {
|
|
37
|
+
borderColor: "#cccccc"
|
|
38
|
+
},
|
|
39
|
+
timeScale: {
|
|
40
|
+
borderColor: "#cccccc",
|
|
41
|
+
timeVisible: !0,
|
|
42
|
+
secondsVisible: !1
|
|
43
|
+
}
|
|
44
|
+
}), p = e.addCandlestickSeries({
|
|
45
|
+
upColor: "#ef4444",
|
|
46
|
+
downColor: "#3b82f6",
|
|
47
|
+
borderUpColor: "#ef4444",
|
|
48
|
+
borderDownColor: "#3b82f6",
|
|
49
|
+
wickUpColor: "#ef4444",
|
|
50
|
+
wickDownColor: "#3b82f6"
|
|
51
|
+
}), t = e.addHistogramSeries({
|
|
52
|
+
color: "#ef4444",
|
|
53
|
+
priceFormat: { type: "volume" },
|
|
54
|
+
priceScaleId: ""
|
|
55
|
+
});
|
|
56
|
+
t.priceScale().applyOptions({
|
|
57
|
+
scaleMargins: {
|
|
58
|
+
top: 0.8,
|
|
59
|
+
bottom: 0
|
|
60
|
+
}
|
|
61
|
+
}), r.current = e, a.current = p, u.current = t, v(e), y(p), S(t);
|
|
62
|
+
const c = () => {
|
|
63
|
+
if (!n.current && i.current && r.current) {
|
|
64
|
+
const w = i.current.clientWidth, N = i.current.clientHeight;
|
|
65
|
+
if (w > 0 && N > 0)
|
|
66
|
+
try {
|
|
67
|
+
r.current.applyOptions({
|
|
68
|
+
width: w,
|
|
69
|
+
height: N
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, R = new ResizeObserver(() => {
|
|
75
|
+
c();
|
|
76
|
+
});
|
|
77
|
+
R.observe(i.current), window.addEventListener("resize", c), m.current = () => {
|
|
78
|
+
R.disconnect(), window.removeEventListener("resize", c), r.current = null, a.current = null, u.current = null, v(null), y(null), S(null);
|
|
79
|
+
try {
|
|
80
|
+
e.remove();
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
})(), () => {
|
|
85
|
+
o = !0, n.current = !0, m.current && (m.current(), m.current = null);
|
|
86
|
+
};
|
|
87
|
+
}, [h.width, h.height]);
|
|
88
|
+
const D = s(null);
|
|
89
|
+
return {
|
|
90
|
+
chartRef: i,
|
|
91
|
+
chart: L,
|
|
92
|
+
candleSeries: F,
|
|
93
|
+
volumeSeries: k,
|
|
94
|
+
setData: (o, g = !1) => {
|
|
95
|
+
if (n.current || !a.current || !u.current || !r.current) return;
|
|
96
|
+
if (!o || !Array.isArray(o) || o.length === 0) {
|
|
97
|
+
console.warn("[useChart] No data provided, skipping setData");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
let l = null;
|
|
101
|
+
if (!g && o.length > 0 && D.current !== null)
|
|
102
|
+
try {
|
|
103
|
+
const e = r.current.timeScale().getVisibleLogicalRange();
|
|
104
|
+
e && (l = { from: e.from, to: e.to });
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
const f = z(o, "useChart");
|
|
108
|
+
if (f.length === 0) {
|
|
109
|
+
console.warn("[useChart] No valid candle data to display");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
D.current = f[0].time;
|
|
113
|
+
const d = f.map((e) => ({
|
|
114
|
+
time: e.time,
|
|
115
|
+
open: e.open,
|
|
116
|
+
high: e.high,
|
|
117
|
+
low: e.low,
|
|
118
|
+
close: e.close
|
|
119
|
+
})), b = f.map((e) => ({
|
|
120
|
+
time: e.time,
|
|
121
|
+
value: Number.isFinite(e.volume) ? e.volume : 0,
|
|
122
|
+
// NaN/Infinity/null/undefined 모두 0으로 처리
|
|
123
|
+
color: e.close >= e.open ? "#ef444466" : "#3b82f666"
|
|
124
|
+
}));
|
|
125
|
+
try {
|
|
126
|
+
if (n.current || !a.current || !u.current)
|
|
127
|
+
return;
|
|
128
|
+
const e = d.filter((t) => {
|
|
129
|
+
const c = typeof t.time == "number" ? t.time : Number(t.time);
|
|
130
|
+
return Number.isFinite(c) && c > 0 && Number.isFinite(t.open) && Number.isFinite(t.high) && Number.isFinite(t.low) && Number.isFinite(t.close);
|
|
131
|
+
}), p = b.filter((t) => {
|
|
132
|
+
const c = typeof t.time == "number" ? t.time : Number(t.time);
|
|
133
|
+
return Number.isFinite(c) && c > 0 && Number.isFinite(t.value);
|
|
134
|
+
});
|
|
135
|
+
if (e.length === 0) {
|
|
136
|
+
console.warn("[useChart] No valid candle data after final null check");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (a.current && !n.current && a.current.setData(e), u.current && !n.current && u.current.setData(p), g && r.current && !n.current)
|
|
140
|
+
r.current.timeScale().fitContent();
|
|
141
|
+
else if (l && r.current && !n.current)
|
|
142
|
+
try {
|
|
143
|
+
r.current.timeScale().setVisibleLogicalRange(l);
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
} catch (e) {
|
|
147
|
+
n.current || console.error("[useChart] Error in setData:", e, "Data sample:", d.slice(0, 3));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
x as useChart
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=useChart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useChart.js","sources":["../../../src/react/hooks/useChart.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { IChartApi, ISeriesApi, Time } from 'lightweight-charts';\nimport type { CandleData } from '../../types';\nimport { filterValidCandles } from '../../utils/validateCandle';\nimport { loadLightweightCharts } from '../loadLightweightCharts';\n\n// 전역 LightweightCharts 객체 (커스텀 빌드 - Line Tools 포함)\ndeclare const LightweightCharts: any;\n\nexport interface UseChartOptions {\n width?: number;\n height?: number;\n}\n\nexport interface UseChartReturn {\n chartRef: React.RefObject<HTMLDivElement | null>;\n chart: IChartApi | null;\n candleSeries: ISeriesApi<'Candlestick'> | null;\n volumeSeries: ISeriesApi<'Histogram'> | null;\n setData: (data: CandleData[], shouldFit?: boolean) => void;\n}\n\nexport function useChart(options: UseChartOptions = {}): UseChartReturn {\n const chartRef = useRef<HTMLDivElement>(null);\n const chartInstanceRef = useRef<IChartApi | null>(null);\n const candleSeriesRef = useRef<ISeriesApi<'Candlestick'> | null>(null);\n const volumeSeriesRef = useRef<ISeriesApi<'Histogram'> | null>(null);\n const isDestroyedRef = useRef<boolean>(false);\n const cleanupRef = useRef<(() => void) | null>(null);\n\n const [chart, setChart] = useState<IChartApi | null>(null);\n const [candleSeries, setCandleSeries] = useState<ISeriesApi<'Candlestick'> | null>(null);\n const [volumeSeries, setVolumeSeries] = useState<ISeriesApi<'Histogram'> | null>(null);\n\n // 차트 초기화\n useEffect(() => {\n if (!chartRef.current) return;\n\n let cancelled = false;\n\n // 초기화 시 파괴 플래그 리셋\n isDestroyedRef.current = false;\n\n const init = async () => {\n // 자동 로딩 시도 (이미 로드되어 있으면 즉시 resolve)\n let LWC: any;\n try {\n LWC = await loadLightweightCharts();\n } catch {\n // 폴백: 전역 LightweightCharts 확인 (수동 script 태그)\n if (typeof LightweightCharts !== 'undefined') {\n LWC = LightweightCharts;\n } else {\n console.error('[useChart] LightweightCharts is not loaded. Make sure to include the script in your HTML or place the standalone JS in a known path.');\n return;\n }\n }\n\n if (cancelled || !chartRef.current) return;\n\n const { createChart } = LWC;\n const width = options.width || chartRef.current.clientWidth;\n const height = options.height || 600;\n\n const chartInstance = createChart(chartRef.current, {\n width,\n height,\n layout: {\n background: { color: '#ffffff' },\n textColor: '#333',\n },\n grid: {\n vertLines: { color: '#f0f0f0' },\n horzLines: { color: '#f0f0f0' },\n },\n crosshair: {\n mode: 0,\n },\n rightPriceScale: {\n borderColor: '#cccccc',\n },\n timeScale: {\n borderColor: '#cccccc',\n timeVisible: true,\n secondsVisible: false,\n },\n });\n\n // 캔들스틱 시리즈\n const candleSeriesInstance = chartInstance.addCandlestickSeries({\n upColor: '#ef4444',\n downColor: '#3b82f6',\n borderUpColor: '#ef4444',\n borderDownColor: '#3b82f6',\n wickUpColor: '#ef4444',\n wickDownColor: '#3b82f6',\n });\n\n // 거래량 시리즈\n const volumeSeriesInstance = chartInstance.addHistogramSeries({\n color: '#ef4444',\n priceFormat: { type: 'volume' },\n priceScaleId: '',\n });\n\n volumeSeriesInstance.priceScale().applyOptions({\n scaleMargins: {\n top: 0.8,\n bottom: 0,\n },\n });\n\n chartInstanceRef.current = chartInstance;\n candleSeriesRef.current = candleSeriesInstance;\n volumeSeriesRef.current = volumeSeriesInstance;\n\n setChart(chartInstance);\n setCandleSeries(candleSeriesInstance);\n setVolumeSeries(volumeSeriesInstance);\n\n // 리사이즈 핸들러 - width와 height 모두 업데이트\n const handleResize = () => {\n // 차트가 파괴된 경우 무시\n if (isDestroyedRef.current) return;\n\n if (chartRef.current && chartInstanceRef.current) {\n const newWidth = chartRef.current.clientWidth;\n const newHeight = chartRef.current.clientHeight;\n if (newWidth > 0 && newHeight > 0) {\n try {\n chartInstanceRef.current.applyOptions({\n width: newWidth,\n height: newHeight,\n });\n } catch (e) {\n // 차트가 이미 파괴된 경우 무시\n }\n }\n }\n };\n\n // ResizeObserver로 컨테이너 크기 변화 감지 (height 포함)\n const resizeObserver = new ResizeObserver(() => {\n handleResize();\n });\n resizeObserver.observe(chartRef.current);\n\n // window resize도 백업으로 유지\n window.addEventListener('resize', handleResize);\n\n cleanupRef.current = () => {\n resizeObserver.disconnect();\n window.removeEventListener('resize', handleResize);\n\n // refs 정리\n chartInstanceRef.current = null;\n candleSeriesRef.current = null;\n volumeSeriesRef.current = null;\n\n // state 정리\n setChart(null);\n setCandleSeries(null);\n setVolumeSeries(null);\n\n // 차트 파괴\n try {\n chartInstance.remove();\n } catch (e) {\n // 이미 파괴된 경우 무시\n }\n };\n }; // end of init()\n\n init();\n\n return () => {\n cancelled = true;\n // 파괴 플래그 먼저 설정 (다른 effect들이 참조하지 않도록)\n isDestroyedRef.current = true;\n\n if (cleanupRef.current) {\n cleanupRef.current();\n cleanupRef.current = null;\n }\n };\n }, [options.width, options.height]);\n\n // 이전 데이터의 첫번째 timestamp 저장 (타임존 변경 시 오프셋 계산용)\n const prevFirstTimestampRef = useRef<number | null>(null);\n\n // 데이터 설정 함수\n const setData = (data: CandleData[], shouldFit: boolean = false) => {\n // 차트가 파괴된 경우 무시\n if (isDestroyedRef.current) return;\n if (!candleSeriesRef.current || !volumeSeriesRef.current || !chartInstanceRef.current) return;\n\n // 데이터가 없거나 빈 배열이면 무시 (에러 방지)\n if (!data || !Array.isArray(data) || data.length === 0) {\n console.warn('[useChart] No data provided, skipping setData');\n return;\n }\n\n // 현재 visible range 저장 (shouldFit이 false일 때만)\n let savedRange: { from: number; to: number } | null = null;\n\n if (!shouldFit && data.length > 0 && prevFirstTimestampRef.current !== null) {\n try {\n const visibleRange = chartInstanceRef.current.timeScale().getVisibleLogicalRange();\n if (visibleRange) {\n savedRange = { from: visibleRange.from, to: visibleRange.to };\n }\n } catch (e) {\n // ignore\n }\n }\n\n const validData = filterValidCandles(data, 'useChart');\n\n if (validData.length === 0) {\n console.warn('[useChart] No valid candle data to display');\n return;\n }\n\n // 첫번째 timestamp 저장\n prevFirstTimestampRef.current = validData[0].time as number;\n\n const candleData = validData.map(c => ({\n time: c.time as Time,\n open: c.open,\n high: c.high,\n low: c.low,\n close: c.close,\n }));\n\n const volumeData = validData.map(c => ({\n time: c.time as Time,\n value: Number.isFinite(c.volume) ? c.volume : 0, // NaN/Infinity/null/undefined 모두 0으로 처리\n color: c.close >= c.open ? '#ef444466' : '#3b82f666',\n }));\n\n try {\n // 차트가 파괴된 경우 재확인 (race condition 방지)\n if (isDestroyedRef.current || !candleSeriesRef.current || !volumeSeriesRef.current) {\n return;\n }\n\n const finalCandleData = candleData.filter(c => {\n const time = typeof c.time === 'number' ? c.time : Number(c.time);\n return Number.isFinite(time) && time > 0 &&\n Number.isFinite(c.open) && Number.isFinite(c.high) &&\n Number.isFinite(c.low) && Number.isFinite(c.close);\n });\n const finalVolumeData = volumeData.filter(v => {\n const time = typeof v.time === 'number' ? v.time : Number(v.time);\n return Number.isFinite(time) && time > 0 && Number.isFinite(v.value);\n });\n\n if (finalCandleData.length === 0) {\n console.warn('[useChart] No valid candle data after final null check');\n return;\n }\n\n // 각 setData 호출 전 ref 체크 (unmount 중 호출 방지)\n if (candleSeriesRef.current && !isDestroyedRef.current) {\n candleSeriesRef.current.setData(finalCandleData);\n }\n if (volumeSeriesRef.current && !isDestroyedRef.current) {\n volumeSeriesRef.current.setData(finalVolumeData);\n }\n\n if (shouldFit && chartInstanceRef.current && !isDestroyedRef.current) {\n chartInstanceRef.current.timeScale().fitContent();\n } else if (savedRange && chartInstanceRef.current && !isDestroyedRef.current) {\n // 저장된 range 복원 (logical range는 인덱스 기반이라 오프셋 불필요)\n try {\n chartInstanceRef.current.timeScale().setVisibleLogicalRange(savedRange);\n } catch (e) {\n // ignore\n }\n }\n } catch (e) {\n // 차트가 파괴된 경우 에러 무시 (정상 unmount)\n if (!isDestroyedRef.current) {\n console.error('[useChart] Error in setData:', e, 'Data sample:', candleData.slice(0, 3));\n }\n }\n };\n\n return {\n chartRef,\n chart,\n candleSeries,\n volumeSeries,\n setData,\n };\n}\n"],"names":["useChart","options","chartRef","useRef","chartInstanceRef","candleSeriesRef","volumeSeriesRef","isDestroyedRef","cleanupRef","chart","setChart","useState","candleSeries","setCandleSeries","volumeSeries","setVolumeSeries","useEffect","cancelled","LWC","loadLightweightCharts","createChart","width","height","chartInstance","candleSeriesInstance","volumeSeriesInstance","handleResize","newWidth","newHeight","resizeObserver","prevFirstTimestampRef","data","shouldFit","savedRange","visibleRange","validData","filterValidCandles","candleData","c","volumeData","finalCandleData","time","finalVolumeData","v"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IChartApi } from 'lightweight-charts';
|
|
2
|
+
import { CandleData } from '../../types';
|
|
3
|
+
import { IndicatorConfigs } from '../types';
|
|
4
|
+
export declare function useIndicators(chart: IChartApi | null, candles: CandleData[]): {
|
|
5
|
+
applyIndicators: (configs: IndicatorConfigs, macdColors?: {
|
|
6
|
+
line: string;
|
|
7
|
+
signal: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=useIndicators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIndicators.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/useIndicators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAmF,MAAM,UAAU,CAAC;AAclI,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE;+BAG5B,gBAAgB,eAAe;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;EAqU9G"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { useRef as g, useCallback as O } from "react";
|
|
2
|
+
import { calculateSMA as $ } from "../../indicators/sma.js";
|
|
3
|
+
import { calculateEMA as U } from "../../indicators/ema.js";
|
|
4
|
+
import { calculateRSI as H } from "../../indicators/rsi.js";
|
|
5
|
+
import { calculateMACD as T } from "../../indicators/macd.js";
|
|
6
|
+
import { calculateBollingerBands as K } from "../../indicators/bollingerBands.js";
|
|
7
|
+
import { calculateATR as C } from "../../indicators/atr.js";
|
|
8
|
+
import { calculateStochastic as j } from "../../indicators/stochastic.js";
|
|
9
|
+
import { calculateWilliamsR as q } from "../../indicators/williamsR.js";
|
|
10
|
+
import { calculateVWAP as z } from "../../indicators/vwap.js";
|
|
11
|
+
import { filterValidIndicatorPoints as G } from "../../utils/validateCandle.js";
|
|
12
|
+
function se(r, d) {
|
|
13
|
+
const o = g([]);
|
|
14
|
+
return { applyIndicators: O((n, m) => {
|
|
15
|
+
var P, k, y, I, w;
|
|
16
|
+
if (!r || !d || d.length === 0) return;
|
|
17
|
+
o.current.forEach((e) => {
|
|
18
|
+
try {
|
|
19
|
+
r.removeSeries(e);
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
}), o.current = [];
|
|
23
|
+
const c = G, L = (((P = n.rsi) == null ? void 0 : P.length) ?? 0) > 0, v = (((k = n.macd) == null ? void 0 : k.length) ?? 0) > 0, D = (((y = n.stochastic) == null ? void 0 : y.length) ?? 0) > 0, f = (((I = n.atr) == null ? void 0 : I.length) ?? 0) > 0, M = (((w = n.williamsR) == null ? void 0 : w.length) ?? 0) > 0, b = [L, v, D, f, M].filter(Boolean).length, W = b > 0 ? Math.min(0.2, 0.5 / b) : 0;
|
|
24
|
+
let V = 1 - W * b;
|
|
25
|
+
const h = () => {
|
|
26
|
+
const e = V;
|
|
27
|
+
return V += W, { top: e, bottom: 1 - V };
|
|
28
|
+
}, R = L ? h() : { top: 0.75, bottom: 0 }, E = v ? h() : { top: 0.75, bottom: 0 }, F = D ? h() : { top: 0.75, bottom: 0 }, A = f ? h() : { top: 0.75, bottom: 0 }, B = M ? h() : { top: 0.75, bottom: 0 };
|
|
29
|
+
n.sma.forEach((e) => {
|
|
30
|
+
const a = $(d, { period: e.value }), l = c(a || []);
|
|
31
|
+
if (l.length > 0) {
|
|
32
|
+
const i = r.addLineSeries({
|
|
33
|
+
color: e.color,
|
|
34
|
+
lineWidth: e.thickness,
|
|
35
|
+
title: `SMA ${e.value}`,
|
|
36
|
+
lastValueVisible: !1,
|
|
37
|
+
priceLineVisible: !1
|
|
38
|
+
});
|
|
39
|
+
i.setData(l.map((t) => ({ ...t, time: t.time }))), o.current.push(i);
|
|
40
|
+
}
|
|
41
|
+
}), n.ema.forEach((e) => {
|
|
42
|
+
const a = U(d, { period: e.value }), l = c(a || []);
|
|
43
|
+
if (l.length > 0) {
|
|
44
|
+
const i = r.addLineSeries({
|
|
45
|
+
color: e.color,
|
|
46
|
+
lineWidth: e.thickness,
|
|
47
|
+
title: `EMA ${e.value}`,
|
|
48
|
+
lastValueVisible: !1,
|
|
49
|
+
priceLineVisible: !1
|
|
50
|
+
});
|
|
51
|
+
i.setData(l.map((t) => ({ ...t, time: t.time }))), o.current.push(i);
|
|
52
|
+
}
|
|
53
|
+
}), n.rsi.forEach((e) => {
|
|
54
|
+
const a = H(d, { period: e.value }), l = c(a || []);
|
|
55
|
+
if (l.length > 0) {
|
|
56
|
+
const i = r.addLineSeries({
|
|
57
|
+
color: e.color,
|
|
58
|
+
lineWidth: e.thickness,
|
|
59
|
+
title: `RSI ${e.value}`,
|
|
60
|
+
priceScaleId: "rsi",
|
|
61
|
+
lastValueVisible: !0,
|
|
62
|
+
priceLineVisible: !1
|
|
63
|
+
});
|
|
64
|
+
i.priceScale().applyOptions({
|
|
65
|
+
scaleMargins: R
|
|
66
|
+
}), i.setData(l.map((s) => ({ ...s, time: s.time })));
|
|
67
|
+
const t = e.oversold ?? 30, p = e.overbought ?? 70;
|
|
68
|
+
i.createPriceLine({
|
|
69
|
+
price: t,
|
|
70
|
+
color: "rgba(150,150,150,0.4)",
|
|
71
|
+
lineWidth: 1,
|
|
72
|
+
lineStyle: 1,
|
|
73
|
+
axisLabelVisible: !1,
|
|
74
|
+
title: "",
|
|
75
|
+
lineVisible: !0
|
|
76
|
+
}), i.createPriceLine({
|
|
77
|
+
price: p,
|
|
78
|
+
color: "rgba(150,150,150,0.4)",
|
|
79
|
+
lineWidth: 1,
|
|
80
|
+
lineStyle: 1,
|
|
81
|
+
axisLabelVisible: !1,
|
|
82
|
+
title: "",
|
|
83
|
+
lineVisible: !0
|
|
84
|
+
}), o.current.push(i);
|
|
85
|
+
}
|
|
86
|
+
}), n.macd.forEach((e) => {
|
|
87
|
+
const a = T(d, {
|
|
88
|
+
fastPeriod: e.fastPeriod,
|
|
89
|
+
slowPeriod: e.slowPeriod,
|
|
90
|
+
signalPeriod: e.signalPeriod
|
|
91
|
+
}), l = c(a.macd || []), i = c(a.signal || []), t = c(a.histogram || []);
|
|
92
|
+
if (l.length > 0) {
|
|
93
|
+
const p = r.addLineSeries({
|
|
94
|
+
color: (m == null ? void 0 : m.line) || "#2962FF",
|
|
95
|
+
lineWidth: e.thickness,
|
|
96
|
+
title: "MACD",
|
|
97
|
+
priceScaleId: "macd",
|
|
98
|
+
lastValueVisible: !0,
|
|
99
|
+
priceLineVisible: !1
|
|
100
|
+
});
|
|
101
|
+
if (p.priceScale().applyOptions({
|
|
102
|
+
scaleMargins: E
|
|
103
|
+
}), p.setData(l.map((s) => ({ ...s, time: s.time }))), o.current.push(p), i.length > 0) {
|
|
104
|
+
const s = r.addLineSeries({
|
|
105
|
+
color: (m == null ? void 0 : m.signal) || "#FF6D00",
|
|
106
|
+
lineWidth: e.thickness,
|
|
107
|
+
title: "Signal",
|
|
108
|
+
priceScaleId: "macd",
|
|
109
|
+
lastValueVisible: !0,
|
|
110
|
+
priceLineVisible: !1
|
|
111
|
+
});
|
|
112
|
+
s.setData(i.map((u) => ({ ...u, time: u.time }))), o.current.push(s);
|
|
113
|
+
}
|
|
114
|
+
if (t.length > 0) {
|
|
115
|
+
const s = r.addHistogramSeries({
|
|
116
|
+
priceScaleId: "macd"
|
|
117
|
+
}), u = e.histUpColor || "#26a69a", x = e.histDownColor || "#ef5350";
|
|
118
|
+
s.setData(t.map((S) => ({
|
|
119
|
+
time: S.time,
|
|
120
|
+
value: S.value,
|
|
121
|
+
color: S.value >= 0 ? u : x
|
|
122
|
+
}))), o.current.push(s);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}), n.bbands.forEach((e) => {
|
|
126
|
+
const a = K(d, { period: e.value, stdDev: e.stdDev || 2 }), l = c(a.upper || []), i = c(a.middle || []), t = c(a.lower || []);
|
|
127
|
+
if (l.length > 0) {
|
|
128
|
+
const p = r.addLineSeries({
|
|
129
|
+
color: e.upperColor || "#F23645",
|
|
130
|
+
lineWidth: 1,
|
|
131
|
+
lineStyle: 1,
|
|
132
|
+
title: "BB Upper",
|
|
133
|
+
crosshairMarkerVisible: !1,
|
|
134
|
+
lastValueVisible: !1,
|
|
135
|
+
priceLineVisible: !1
|
|
136
|
+
});
|
|
137
|
+
if (p.setData(l.map((s) => ({ ...s, time: s.time }))), o.current.push(p), i.length > 0) {
|
|
138
|
+
const s = r.addLineSeries({
|
|
139
|
+
color: e.middleColor || "#2962FF",
|
|
140
|
+
lineWidth: e.thickness,
|
|
141
|
+
lineStyle: 0,
|
|
142
|
+
title: "BB Middle",
|
|
143
|
+
lastValueVisible: !1,
|
|
144
|
+
priceLineVisible: !1
|
|
145
|
+
});
|
|
146
|
+
s.setData(i.map((u) => ({ ...u, time: u.time }))), o.current.push(s);
|
|
147
|
+
}
|
|
148
|
+
if (t.length > 0) {
|
|
149
|
+
const s = r.addLineSeries({
|
|
150
|
+
color: e.lowerColor || "#089981",
|
|
151
|
+
lineWidth: 1,
|
|
152
|
+
lineStyle: 1,
|
|
153
|
+
title: "BB Lower",
|
|
154
|
+
crosshairMarkerVisible: !1,
|
|
155
|
+
lastValueVisible: !1,
|
|
156
|
+
priceLineVisible: !1
|
|
157
|
+
});
|
|
158
|
+
s.setData(t.map((u) => ({ ...u, time: u.time }))), o.current.push(s);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}), (n.stochastic ?? []).forEach((e) => {
|
|
162
|
+
const a = j(d, {
|
|
163
|
+
kPeriod: e.kPeriod,
|
|
164
|
+
dPeriod: e.dPeriod,
|
|
165
|
+
smooth: e.smooth
|
|
166
|
+
}), l = c(a.k || []), i = c(a.d || []);
|
|
167
|
+
if (l.length > 0) {
|
|
168
|
+
const t = r.addLineSeries({
|
|
169
|
+
color: e.kColor || "#2962FF",
|
|
170
|
+
lineWidth: e.thickness,
|
|
171
|
+
title: "%K",
|
|
172
|
+
priceScaleId: "stochastic",
|
|
173
|
+
lastValueVisible: !0,
|
|
174
|
+
priceLineVisible: !1
|
|
175
|
+
});
|
|
176
|
+
if (t.priceScale().applyOptions({ scaleMargins: F }), t.setData(l.map((p) => ({ ...p, time: p.time }))), o.current.push(t), t.createPriceLine({
|
|
177
|
+
price: 80,
|
|
178
|
+
color: "rgba(150,150,150,0.4)",
|
|
179
|
+
lineWidth: 1,
|
|
180
|
+
lineStyle: 1,
|
|
181
|
+
axisLabelVisible: !1,
|
|
182
|
+
title: "",
|
|
183
|
+
lineVisible: !0
|
|
184
|
+
}), t.createPriceLine({
|
|
185
|
+
price: 20,
|
|
186
|
+
color: "rgba(150,150,150,0.4)",
|
|
187
|
+
lineWidth: 1,
|
|
188
|
+
lineStyle: 1,
|
|
189
|
+
axisLabelVisible: !1,
|
|
190
|
+
title: "",
|
|
191
|
+
lineVisible: !0
|
|
192
|
+
}), i.length > 0) {
|
|
193
|
+
const p = r.addLineSeries({
|
|
194
|
+
color: e.dColor || "#FF6D00",
|
|
195
|
+
lineWidth: e.thickness,
|
|
196
|
+
title: "%D",
|
|
197
|
+
priceScaleId: "stochastic",
|
|
198
|
+
lastValueVisible: !0,
|
|
199
|
+
priceLineVisible: !1
|
|
200
|
+
});
|
|
201
|
+
p.setData(i.map((s) => ({ ...s, time: s.time }))), o.current.push(p);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}), (n.atr ?? []).forEach((e) => {
|
|
205
|
+
const a = C(d, { period: e.value }), l = c(a || []);
|
|
206
|
+
if (l.length > 0) {
|
|
207
|
+
const i = r.addLineSeries({
|
|
208
|
+
color: e.color,
|
|
209
|
+
lineWidth: e.thickness,
|
|
210
|
+
title: `ATR ${e.value}`,
|
|
211
|
+
priceScaleId: "atr",
|
|
212
|
+
lastValueVisible: !0,
|
|
213
|
+
priceLineVisible: !1
|
|
214
|
+
});
|
|
215
|
+
i.priceScale().applyOptions({ scaleMargins: A }), i.setData(l.map((t) => ({ ...t, time: t.time }))), o.current.push(i);
|
|
216
|
+
}
|
|
217
|
+
}), (n.vwap ?? []).forEach((e) => {
|
|
218
|
+
const a = z(d), l = c(a || []);
|
|
219
|
+
if (l.length > 0) {
|
|
220
|
+
const i = r.addLineSeries({
|
|
221
|
+
color: e.color || "#E040FB",
|
|
222
|
+
lineWidth: e.thickness,
|
|
223
|
+
title: "VWAP",
|
|
224
|
+
lastValueVisible: !1,
|
|
225
|
+
priceLineVisible: !1
|
|
226
|
+
});
|
|
227
|
+
i.setData(l.map((t) => ({ ...t, time: t.time }))), o.current.push(i);
|
|
228
|
+
}
|
|
229
|
+
}), (n.williamsR ?? []).forEach((e) => {
|
|
230
|
+
const a = q(d, { period: e.value }), l = c(a || []);
|
|
231
|
+
if (l.length > 0) {
|
|
232
|
+
const i = r.addLineSeries({
|
|
233
|
+
color: e.color,
|
|
234
|
+
lineWidth: e.thickness,
|
|
235
|
+
title: `W%R ${e.value}`,
|
|
236
|
+
priceScaleId: "williamsR",
|
|
237
|
+
lastValueVisible: !0,
|
|
238
|
+
priceLineVisible: !1
|
|
239
|
+
});
|
|
240
|
+
i.priceScale().applyOptions({ scaleMargins: B }), i.setData(l.map((t) => ({ ...t, time: t.time }))), i.createPriceLine({
|
|
241
|
+
price: -20,
|
|
242
|
+
color: "rgba(150,150,150,0.4)",
|
|
243
|
+
lineWidth: 1,
|
|
244
|
+
lineStyle: 1,
|
|
245
|
+
axisLabelVisible: !1,
|
|
246
|
+
title: "",
|
|
247
|
+
lineVisible: !0
|
|
248
|
+
}), i.createPriceLine({
|
|
249
|
+
price: -80,
|
|
250
|
+
color: "rgba(150,150,150,0.4)",
|
|
251
|
+
lineWidth: 1,
|
|
252
|
+
lineStyle: 1,
|
|
253
|
+
axisLabelVisible: !1,
|
|
254
|
+
title: "",
|
|
255
|
+
lineVisible: !0
|
|
256
|
+
}), o.current.push(i);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}, [r, d]) };
|
|
260
|
+
}
|
|
261
|
+
export {
|
|
262
|
+
se as useIndicators
|
|
263
|
+
};
|
|
264
|
+
//# sourceMappingURL=useIndicators.js.map
|