커스텀
This commit is contained in:
@@ -449,8 +449,8 @@ const ChartRightToolbar: React.FC<ChartRightToolbarProps> = ({
|
|||||||
? paneItems.find(p => p.id === openMenuId)
|
? paneItems.find(p => p.id === openMenuId)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const showCustomBtn = !!(showOverlayIcons && !overlayControlsOnly && onCustomOverlayActiveChange && onOpenCustomOverlaySettings);
|
const showCustomBtn = !!(showOverlayIcons && onCustomOverlayActiveChange && onOpenCustomOverlaySettings);
|
||||||
const showCustom1Btn = !!(showOverlayIcons && !overlayControlsOnly && onCustom1OverlayActiveChange && onOpenCustom1OverlaySettings);
|
const showCustom1Btn = !!(showOverlayIcons && onCustom1OverlayActiveChange && onOpenCustomOverlaySettings);
|
||||||
const customMenuOpen = openMenuId === CUSTOM_MENU_ID;
|
const customMenuOpen = openMenuId === CUSTOM_MENU_ID;
|
||||||
const custom1MenuOpen = openMenuId === CUSTOM1_MENU_ID;
|
const custom1MenuOpen = openMenuId === CUSTOM1_MENU_ID;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import TradingChart from '../TradingChart';
|
import TradingChart from '../TradingChart';
|
||||||
|
import ChartCustomOverlaySettingsModal from '../ChartCustomOverlaySettingsModal';
|
||||||
import { MarketSearchPanel } from '../MarketSearchPanel';
|
import { MarketSearchPanel } from '../MarketSearchPanel';
|
||||||
import type { ChartType, IndicatorConfig, OHLCVBar, Theme, Timeframe } from '../../types';
|
import type { ChartType, IndicatorConfig, OHLCVBar, Theme, Timeframe } from '../../types';
|
||||||
import type { ChartManager } from '../../utils/ChartManager';
|
import type { ChartManager } from '../../utils/ChartManager';
|
||||||
@@ -22,6 +23,14 @@ import {
|
|||||||
} from '../../utils/backtestWarmup';
|
} from '../../utils/backtestWarmup';
|
||||||
import type { EvalIndicatorParams } from '../../utils/strategyEvaluationParams';
|
import type { EvalIndicatorParams } from '../../utils/strategyEvaluationParams';
|
||||||
import { DISPLAY_COUNT } from '../../hooks/useUpbitData';
|
import { DISPLAY_COUNT } from '../../hooks/useUpbitData';
|
||||||
|
import {
|
||||||
|
createDefaultChartCustomOverlaySelection,
|
||||||
|
isCustomOverlaySlotActive,
|
||||||
|
resolveActiveCustomOverlaySlot,
|
||||||
|
syncChartManagerCustomOverlaysByActiveSlot,
|
||||||
|
type ChartCustomOverlaySelection,
|
||||||
|
type ChartCustomOverlaySlotId,
|
||||||
|
} from '../../utils/chartCustomOverlay';
|
||||||
import {
|
import {
|
||||||
chartOverlayKeyForType,
|
chartOverlayKeyForType,
|
||||||
DEFAULT_CHART_OVERLAY_VISIBILITY,
|
DEFAULT_CHART_OVERLAY_VISIBILITY,
|
||||||
@@ -202,6 +211,73 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const [customOverlaySelection, setCustomOverlaySelection] = useState<ChartCustomOverlaySelection>(
|
||||||
|
() => createDefaultChartCustomOverlaySelection(),
|
||||||
|
);
|
||||||
|
const [custom1OverlaySelection, setCustom1OverlaySelection] = useState<ChartCustomOverlaySelection>(
|
||||||
|
() => createDefaultChartCustomOverlaySelection(),
|
||||||
|
);
|
||||||
|
const [activeCustomOverlaySlot, setActiveCustomOverlaySlot] = useState<ChartCustomOverlaySlotId | null>(null);
|
||||||
|
const [customOverlaySettingsSlot, setCustomOverlaySettingsSlot] = useState<ChartCustomOverlaySlotId | null>(null);
|
||||||
|
const customOverlayActive = isCustomOverlaySlotActive(activeCustomOverlaySlot, 'custom');
|
||||||
|
const custom1OverlayActive = isCustomOverlaySlotActive(activeCustomOverlaySlot, 'custom1');
|
||||||
|
|
||||||
|
const syncCustomOverlaysToManager = useCallback((mgr: ChartManager) => {
|
||||||
|
syncChartManagerCustomOverlaysByActiveSlot(
|
||||||
|
mgr,
|
||||||
|
activeCustomOverlaySlot,
|
||||||
|
customOverlaySelection,
|
||||||
|
custom1OverlaySelection,
|
||||||
|
);
|
||||||
|
}, [activeCustomOverlaySlot, customOverlaySelection, custom1OverlaySelection]);
|
||||||
|
|
||||||
|
const handleCustomOverlayActiveChange = useCallback((active: boolean) => {
|
||||||
|
const nextSlot = resolveActiveCustomOverlaySlot('custom', active, activeCustomOverlaySlot);
|
||||||
|
setActiveCustomOverlaySlot(nextSlot);
|
||||||
|
const mgr = managerRef.current;
|
||||||
|
if (mgr) {
|
||||||
|
syncChartManagerCustomOverlaysByActiveSlot(
|
||||||
|
mgr,
|
||||||
|
nextSlot,
|
||||||
|
customOverlaySelection,
|
||||||
|
custom1OverlaySelection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [activeCustomOverlaySlot, customOverlaySelection, custom1OverlaySelection]);
|
||||||
|
|
||||||
|
const handleCustom1OverlayActiveChange = useCallback((active: boolean) => {
|
||||||
|
const nextSlot = resolveActiveCustomOverlaySlot('custom1', active, activeCustomOverlaySlot);
|
||||||
|
setActiveCustomOverlaySlot(nextSlot);
|
||||||
|
const mgr = managerRef.current;
|
||||||
|
if (mgr) {
|
||||||
|
syncChartManagerCustomOverlaysByActiveSlot(
|
||||||
|
mgr,
|
||||||
|
nextSlot,
|
||||||
|
customOverlaySelection,
|
||||||
|
custom1OverlaySelection,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [activeCustomOverlaySlot, customOverlaySelection, custom1OverlaySelection]);
|
||||||
|
|
||||||
|
const handleSaveCustomOverlaySelection = useCallback((
|
||||||
|
slot: ChartCustomOverlaySlotId,
|
||||||
|
selection: ChartCustomOverlaySelection,
|
||||||
|
) => {
|
||||||
|
const nextCustomSel = slot === 'custom' ? selection : customOverlaySelection;
|
||||||
|
const nextCustom1Sel = slot === 'custom1' ? selection : custom1OverlaySelection;
|
||||||
|
if (slot === 'custom') setCustomOverlaySelection(selection);
|
||||||
|
else setCustom1OverlaySelection(selection);
|
||||||
|
setCustomOverlaySettingsSlot(null);
|
||||||
|
const mgr = managerRef.current;
|
||||||
|
if (!mgr) return;
|
||||||
|
syncChartManagerCustomOverlaysByActiveSlot(
|
||||||
|
mgr,
|
||||||
|
activeCustomOverlaySlot,
|
||||||
|
nextCustomSel,
|
||||||
|
nextCustom1Sel,
|
||||||
|
);
|
||||||
|
}, [activeCustomOverlaySlot, customOverlaySelection, custom1OverlaySelection]);
|
||||||
|
|
||||||
const auxPaneCount = useMemo(
|
const auxPaneCount = useMemo(
|
||||||
() => countNonOverlayIndicatorPanes(indicators, isOverlayType),
|
() => countNonOverlayIndicatorPanes(indicators, isOverlayType),
|
||||||
[indicators],
|
[indicators],
|
||||||
@@ -367,12 +443,13 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
managerRef.current = mgr;
|
managerRef.current = mgr;
|
||||||
setChartMgr(mgr);
|
setChartMgr(mgr);
|
||||||
mgr.setChartOverlayVisibility(overlayVisibilityRef.current);
|
mgr.setChartOverlayVisibility(overlayVisibilityRef.current);
|
||||||
|
syncCustomOverlaysToManager(mgr);
|
||||||
if (paneAreaRatio && paneAreaRatio.aux > 0) {
|
if (paneAreaRatio && paneAreaRatio.aux > 0) {
|
||||||
mgr.setPaneAreaRatio(paneAreaRatio.candle, paneAreaRatio.aux);
|
mgr.setPaneAreaRatio(paneAreaRatio.candle, paneAreaRatio.aux);
|
||||||
}
|
}
|
||||||
applyMarkers();
|
applyMarkers();
|
||||||
fitChartViewport();
|
fitChartViewport();
|
||||||
}, [paneAreaRatio, applyMarkers, fitChartViewport]);
|
}, [paneAreaRatio, applyMarkers, fitChartViewport, syncCustomOverlaysToManager]);
|
||||||
|
|
||||||
const onCandlesReady = useCallback(() => {
|
const onCandlesReady = useCallback(() => {
|
||||||
const mgr = managerRef.current;
|
const mgr = managerRef.current;
|
||||||
@@ -625,6 +702,12 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
showCandleOverlayControls
|
showCandleOverlayControls
|
||||||
candleOverlayToggles={candleOverlayToggles}
|
candleOverlayToggles={candleOverlayToggles}
|
||||||
onToggleCandleOverlay={handleToggleCandleOverlay}
|
onToggleCandleOverlay={handleToggleCandleOverlay}
|
||||||
|
customOverlayActive={customOverlayActive}
|
||||||
|
onCustomOverlayActiveChange={handleCustomOverlayActiveChange}
|
||||||
|
onOpenCustomOverlaySettings={() => setCustomOverlaySettingsSlot('custom')}
|
||||||
|
custom1OverlayActive={custom1OverlayActive}
|
||||||
|
onCustom1OverlayActiveChange={handleCustom1OverlayActiveChange}
|
||||||
|
onOpenCustom1OverlaySettings={() => setCustomOverlaySettingsSlot('custom1')}
|
||||||
magnifierEnabled={magnifierActive}
|
magnifierEnabled={magnifierActive}
|
||||||
onMagnifierClose={() => setMagnifierActive(false)}
|
onMagnifierClose={() => setMagnifierActive(false)}
|
||||||
resolveInitialDisplayCount={resolveInitialDisplayCount}
|
resolveInitialDisplayCount={resolveInitialDisplayCount}
|
||||||
@@ -637,6 +720,24 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
|||||||
onSelectedBarIndexChange={onSelectedBarIndexChange}
|
onSelectedBarIndexChange={onSelectedBarIndexChange}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{customOverlaySettingsSlot === 'custom' && (
|
||||||
|
<ChartCustomOverlaySettingsModal
|
||||||
|
title="Custom 표시 설정"
|
||||||
|
selection={customOverlaySelection}
|
||||||
|
onSave={sel => handleSaveCustomOverlaySelection('custom', sel)}
|
||||||
|
onCancel={() => setCustomOverlaySettingsSlot(null)}
|
||||||
|
smaParams={baseIndicators.find(i => i.type === 'SMA')?.params}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{customOverlaySettingsSlot === 'custom1' && (
|
||||||
|
<ChartCustomOverlaySettingsModal
|
||||||
|
title="Custom1 표시 설정"
|
||||||
|
selection={custom1OverlaySelection}
|
||||||
|
onSave={sel => handleSaveCustomOverlaySelection('custom1', sel)}
|
||||||
|
onCancel={() => setCustomOverlaySettingsSlot(null)}
|
||||||
|
smaParams={baseIndicators.find(i => i.type === 'SMA')?.params}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!loading && !error && bars.length === 0 && (
|
{!loading && !error && bars.length === 0 && (
|
||||||
|
|||||||
Reference in New Issue
Block a user