분석레포트 타임라인 표시

This commit is contained in:
Macbook
2026-06-10 16:53:03 +09:00
parent 55b1c75226
commit bf5554d375
12 changed files with 2032 additions and 28 deletions
@@ -2,7 +2,7 @@
* 분석레포트 — 가상매매와 동일 3패널 (좌: 목록 · 중: 분석 · 우: 시그널)
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import type { Theme } from '../../types';
import type { Theme, Timeframe } from '../../types';
import {
loadBacktestResults,
loadPaperTrades,
@@ -28,6 +28,7 @@ import {
buildLiveReportModel,
} from '../../utils/backtestReportModel';
import { enrichStrategyNameMap, strategyNamesFromList } from '../../utils/strategyNameResolver';
import { candleTypeToTimeframe } from '../../utils/strategyToChartIndicators';
import '../../styles/backtestDashboard.css';
import '../../styles/analysisReportPage.css';
@@ -142,6 +143,42 @@ export function AnalysisReportPage({ theme = 'dark' }: Props) {
return null;
}, [sourceTab, selectedBacktest, selectedLive, ctx, strategyNamesById]);
const timelineFilter = useMemo(() => {
if (sourceTab === 'live' && selectedLive) {
return {
symbol: selectedLive.symbol,
strategyId: selectedLive.strategyId,
};
}
if (sourceTab === 'backtest' && selectedBacktest) {
return {
symbol: selectedBacktest.symbol,
strategyId: selectedBacktest.strategyId ?? null,
};
}
return undefined;
}, [sourceTab, selectedLive, selectedBacktest]);
const timelineFilterLabel = useMemo(() => {
if (sourceTab === 'live' && selectedLive) {
return `${selectedLive.symbol} · ${selectedLive.strategyLabel}`;
}
if (sourceTab === 'backtest' && selectedBacktest) {
return `${selectedBacktest.symbol} · ${selectedBacktest.strategyName}`;
}
return undefined;
}, [sourceTab, selectedLive, selectedBacktest]);
const timelineChartTimeframe = useMemo((): Timeframe => {
if (sourceTab === 'live' && selectedLive?.timeframe) {
return candleTypeToTimeframe(selectedLive.timeframe);
}
if (sourceTab === 'backtest' && selectedBacktest?.timeframe) {
return candleTypeToTimeframe(selectedBacktest.timeframe);
}
return '3m';
}, [sourceTab, selectedLive, selectedBacktest]);
const headerActions = (
<>
<button type="button" className="btd-btn btd-btn--ghost" onClick={() => void fetchAll()}></button>
@@ -193,7 +230,14 @@ export function AnalysisReportPage({ theme = 'dark' }: Props) {
}}
/>
)}
center={<AnalysisReportCenterPanel model={reportModel} />}
center={(
<AnalysisReportCenterPanel
model={reportModel}
timelineFilter={timelineFilter}
timelineFilterLabel={timelineFilterLabel}
chartTimeframe={timelineChartTimeframe}
/>
)}
right={<AnalysisReportSignalsPanel model={reportModel} />}
/>