위젯 종료버튼 겹침문제 수정

This commit is contained in:
Macbook
2026-06-15 20:59:07 +09:00
parent 8b45362a00
commit 44f6ddfa0f
16 changed files with 263 additions and 53 deletions
@@ -9,9 +9,10 @@ import {
} from '../../utils/backendApi';
import { loadAnalysisCandles } from '../../utils/analysisChartData';
import { normalizeChartTimeframe } from '../../utils/backtestUiUtils';
import { mergeWidgetTimeframeOptions } from '../../utils/chartWidgetTimeframes';
import { resolveStrategyPrimaryTimeframe } from '../../utils/strategyToChartIndicators';
import { resolveEvaluationFromLoadedBars } from '../../utils/backtestWarmup';
import type { OHLCVBar, Theme } from '../../types';
import type { OHLCVBar, Theme, Timeframe } from '../../types';
import { useIndicatorSettings } from '../../hooks/useIndicatorSettings';
import {
DEFAULT_PAPER_OVERLAY_VISIBILITY,
@@ -28,6 +29,8 @@ interface Props {
theme?: Theme;
/** 위젯 임베드 시 하단 줌/패닝 툴바 숨김 */
showHoverToolbar?: boolean;
/** 위젯 — 종목 우측 시간봉 선택 */
enableTimeframePicker?: boolean;
}
/**
@@ -35,12 +38,16 @@ interface Props {
* 좌측(과거) 스크롤 시 추가 캔들·보조지표 로드 후 전체 구간 시그널 재계산.
*/
const PaperAnalysisChart: React.FC<Props> = ({
market, strategyId, theme = 'dark', showHoverToolbar = true,
market,
strategyId,
theme = 'dark',
showHoverToolbar = true,
enableTimeframePicker = false,
}) => {
const { getParams } = useIndicatorSettings();
const [signals, setSignals] = useState<BacktestSignal[]>([]);
const [strategy, setStrategy] = useState<StrategyDto | undefined>();
const [timeframe, setTimeframe] = useState('1h');
const [timeframe, setTimeframe] = useState<Timeframe>('1h');
const [running, setRunning] = useState(false);
const [historyLoading, setHistoryLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -53,8 +60,15 @@ const PaperAnalysisChart: React.FC<Props> = ({
const historyDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const strategyRef = useRef(strategy);
const strategyIdRef = useRef(strategyId);
const timeframeRef = useRef(timeframe);
strategyRef.current = strategy;
strategyIdRef.current = strategyId;
timeframeRef.current = timeframe;
const timeframeOptions = useMemo(
() => mergeWidgetTimeframeOptions(strategy),
[strategy],
);
useEffect(() => {
if (!strategyId) {
@@ -71,6 +85,11 @@ const PaperAnalysisChart: React.FC<Props> = ({
return () => { cancelled = true; };
}, [strategyId]);
useEffect(() => {
if (!strategy) return;
setTimeframe(normalizeChartTimeframe(resolveStrategyPrimaryTimeframe(strategy)));
}, [strategyId, strategy?.id]);
const runSignalsForBars = useCallback(async (
bars: OHLCVBar[],
tf: string,
@@ -139,8 +158,7 @@ const PaperAnalysisChart: React.FC<Props> = ({
return;
}
let cancelled = false;
const tf = normalizeChartTimeframe(resolveStrategyPrimaryTimeframe(strategy));
setTimeframe(tf);
const tf = normalizeChartTimeframe(timeframe);
setError(null);
void (async () => {
@@ -162,7 +180,7 @@ const PaperAnalysisChart: React.FC<Props> = ({
cancelled = true;
++backtestGenRef.current;
};
}, [market, strategyId, strategy, toTimeSec, runSignalsForBars]);
}, [market, strategyId, strategy, timeframe, toTimeSec, runSignalsForBars]);
const handleToggleOverlay = useCallback((key: PaperOverlayToggleKey) => {
setOverlayVisibility(prev => ({ ...prev, [key]: !prev[key] }));
@@ -172,7 +190,7 @@ const PaperAnalysisChart: React.FC<Props> = ({
const strat = strategyRef.current;
const sid = strategyIdRef.current;
if (!strat || !sid) return;
const tf = normalizeChartTimeframe(resolveStrategyPrimaryTimeframe(strat));
const tf = normalizeChartTimeframe(timeframeRef.current);
if (historyDebounceRef.current) clearTimeout(historyDebounceRef.current);
historyDebounceRef.current = setTimeout(() => {
historyDebounceRef.current = null;
@@ -180,6 +198,10 @@ const PaperAnalysisChart: React.FC<Props> = ({
}, HISTORY_BACKTEST_DEBOUNCE_MS);
}, [runSignalsForBars]);
const handleTimeframeChange = useCallback((tf: Timeframe) => {
setTimeframe(tf);
}, []);
useEffect(() => () => {
if (historyDebounceRef.current) clearTimeout(historyDebounceRef.current);
}, []);
@@ -195,6 +217,7 @@ const PaperAnalysisChart: React.FC<Props> = ({
}
const statusBusy = running || historyLoading;
const chartTimeframe = normalizeChartTimeframe(timeframe);
return (
<div className="ptd-analysis-chart ptd-analysis-chart--backtest">
@@ -208,7 +231,7 @@ const PaperAnalysisChart: React.FC<Props> = ({
)}
<BacktestAnalysisChart
symbol={market}
timeframe={timeframe}
timeframe={chartTimeframe}
toTimeSec={toTimeSec}
barCount={BAR_COUNT}
signals={signals}
@@ -219,6 +242,8 @@ const PaperAnalysisChart: React.FC<Props> = ({
overlayVisibility={overlayVisibility}
onToggleOverlay={handleToggleOverlay}
showHoverToolbar={showHoverToolbar}
timeframeOptions={enableTimeframePicker ? timeframeOptions : undefined}
onTimeframeChange={enableTimeframePicker ? handleTimeframeChange : undefined}
/>
</div>
);