분석결과 레포트 수정
This commit is contained in:
@@ -4,10 +4,11 @@
|
||||
* BacktestDashboard — 카드 기반 대시보드 (재사용 가능)
|
||||
* BacktestResultModal — 드래그 팝업으로 Dashboard를 감싸는 래퍼
|
||||
*/
|
||||
import React from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import type { BacktestAnalysis, BacktestSignal, BacktestStats } from '../utils/backendApi';
|
||||
import { useDraggablePanel } from '../hooks/useDraggablePanel';
|
||||
import { repairUtf8Mojibake } from '../utils/textEncoding';
|
||||
import type { EvaluationAllocationReport } from './backtest/BacktestAnalysisReportModal';
|
||||
import {
|
||||
pct,
|
||||
pctAbs,
|
||||
@@ -58,6 +59,9 @@ export interface BacktestDashboardProps {
|
||||
reportMode?: boolean;
|
||||
/** false — 거래 시그널 섹션 숨김 (별도 패널에 표시) */
|
||||
hideSignals?: boolean;
|
||||
/** 전략평가 — 일괄/분할 매수 방식별 분석 */
|
||||
evaluationAllocations?: EvaluationAllocationReport[];
|
||||
reportSignalFilterNote?: string;
|
||||
}
|
||||
|
||||
// ── 시그널 타입 ───────────────────────────────────────────────────────────
|
||||
@@ -70,8 +74,17 @@ export function BacktestDashboard({
|
||||
analysis, signals, strategyName, symbol, timeframe, barCount, createdAt,
|
||||
reportMode = false,
|
||||
hideSignals = false,
|
||||
evaluationAllocations,
|
||||
reportSignalFilterNote,
|
||||
}: BacktestDashboardProps) {
|
||||
const a = analysis;
|
||||
const [allocMode, setAllocMode] = useState<'full' | 'split'>('split');
|
||||
|
||||
const displayAnalysis = useMemo(() => {
|
||||
if (!evaluationAllocations?.length) return analysis;
|
||||
return evaluationAllocations.find(e => e.mode === allocMode)?.analysis ?? analysis;
|
||||
}, [analysis, evaluationAllocations, allocMode]);
|
||||
|
||||
const a = displayAnalysis;
|
||||
if (!a) {
|
||||
return (
|
||||
<div className="brd-empty-state">
|
||||
@@ -120,6 +133,49 @@ export function BacktestDashboard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{evaluationAllocations && evaluationAllocations.length >= 2 && (
|
||||
<div className="brd-row">
|
||||
<div className="brd-card brd-card--full">
|
||||
<SectionTitle icon="📋" title="매수 방식별 수익률 비교" />
|
||||
{reportSignalFilterNote && (
|
||||
<p className="brd-eval-filter-note">{reportSignalFilterNote}</p>
|
||||
)}
|
||||
<div className="brd-alloc-tabs">
|
||||
{evaluationAllocations.map(item => (
|
||||
<button
|
||||
key={item.mode}
|
||||
type="button"
|
||||
className={`brd-alloc-tab${allocMode === item.mode ? ' brd-alloc-tab--active' : ''}`}
|
||||
onClick={() => setAllocMode(item.mode)}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="brd-alloc-compare">
|
||||
{evaluationAllocations.map(item => (
|
||||
<div
|
||||
key={item.mode}
|
||||
className={`brd-alloc-card${allocMode === item.mode ? ' brd-alloc-card--active' : ''}`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setAllocMode(item.mode)}
|
||||
onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') setAllocMode(item.mode); }}
|
||||
>
|
||||
<div className="brd-alloc-card-label">{item.label}</div>
|
||||
<div className={`brd-alloc-card-return ${colorCls(item.analysis.totalReturnPct)}`}>
|
||||
{pct(item.analysis.totalReturnPct)}
|
||||
</div>
|
||||
<div className="brd-alloc-card-sub">
|
||||
최종 {wonFmt(item.analysis.finalEquity)} · 승률 {pctAbs(item.analysis.winRate)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Row 1: KPI 카드 6개 ── */}
|
||||
<div className="brd-row">
|
||||
<div className="brd-kpi-grid">
|
||||
|
||||
@@ -48,7 +48,7 @@ import { resolveBarSignalHighlight } from '../utils/strategyEvaluationBarSignals
|
||||
import type { OHLCVBar } from '../types';
|
||||
import BacktestAnalysisReportModal from './backtest/BacktestAnalysisReportModal';
|
||||
import type { BacktestAnalysisReportModel } from './backtest/BacktestAnalysisReportModal';
|
||||
import { buildChartBacktestReportModel } from '../utils/backtestReportModel';
|
||||
import { buildStrategyEvaluationReportModel } from '../utils/strategyEvaluationReport';
|
||||
import { BACKTEST_DISPLAY_BAR_COUNT } from '../utils/backtestWarmup';
|
||||
import StrategyEvaluationAiVerifyPanel from './strategyEvaluation/StrategyEvaluationAiVerifyPanel';
|
||||
import StrategyEvaluationChartSettingsTab from './strategyEvaluation/StrategyEvaluationChartSettingsTab';
|
||||
@@ -604,7 +604,7 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
timeframe: chartTimeframe,
|
||||
symbol: market,
|
||||
strategyName: selectedStrategy.name,
|
||||
settings: btSettings,
|
||||
settings: { ...btSettings, positionMode: 'SIGNAL_ONLY' },
|
||||
indicatorParams,
|
||||
evaluationBarCount,
|
||||
});
|
||||
@@ -614,14 +614,16 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = buildChartBacktestReportModel({
|
||||
analysis: res.analysis ?? null,
|
||||
stats: res.stats ?? null,
|
||||
const initialCapital = btSettings.initialCapital ?? res.analysis?.initialCapital ?? 10_000_000;
|
||||
const model = buildStrategyEvaluationReportModel({
|
||||
signals: res.signals,
|
||||
initialCapital,
|
||||
strategyName: selectedStrategy.name ?? strategyLabel,
|
||||
symbol: market.replace(/^KRW-/, ''),
|
||||
timeframe: chartTimeframe,
|
||||
barCount: bars.length,
|
||||
firstBarClose: bars[0]?.close,
|
||||
lastBarClose: bars[bars.length - 1]?.close,
|
||||
});
|
||||
if (!model) {
|
||||
window.alert('분석 데이터를 생성할 수 없습니다.');
|
||||
|
||||
@@ -8,6 +8,14 @@ import { BacktestDashboard } from '../BacktestResultModal';
|
||||
import { printReportDocument } from '../../utils/printReportDocument';
|
||||
import '../../styles/backtestReportPrint.css';
|
||||
|
||||
export type EvaluationAllocationMode = 'full' | 'split';
|
||||
|
||||
export interface EvaluationAllocationReport {
|
||||
mode: EvaluationAllocationMode;
|
||||
label: string;
|
||||
analysis: BacktestAnalysis;
|
||||
}
|
||||
|
||||
export interface BacktestAnalysisReportModel {
|
||||
analysis: BacktestAnalysis;
|
||||
signals: BacktestSignal[];
|
||||
@@ -18,6 +26,9 @@ export interface BacktestAnalysisReportModel {
|
||||
barCount: number;
|
||||
createdAt?: string;
|
||||
reportKind: 'backtest' | 'live';
|
||||
/** 전략평가 — 일괄/분할 매수 방식별 분석 */
|
||||
evaluationAllocations?: EvaluationAllocationReport[];
|
||||
reportSignalFilterNote?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@@ -135,6 +146,8 @@ export default function BacktestAnalysisReportModal({ open, onClose, model }: Pr
|
||||
barCount={model.barCount}
|
||||
createdAt={model.createdAt}
|
||||
reportMode
|
||||
evaluationAllocations={model.evaluationAllocations}
|
||||
reportSignalFilterNote={model.reportSignalFilterNote}
|
||||
/>
|
||||
<footer className="btd-report-print-footer">
|
||||
<p>본 레포트는 GoldenChart 백테스팅·투자분석 결과이며 투자 권유가 아닙니다.</p>
|
||||
|
||||
Reference in New Issue
Block a user