ai 분석 수정
This commit is contained in:
@@ -53,7 +53,7 @@ import StrategyEvaluationAiVerifyPanel from './strategyEvaluation/StrategyEvalua
|
||||
import {
|
||||
buildStrategyEvaluationAiVerifyContext,
|
||||
requestStrategyEvaluationAiVerify,
|
||||
summarizeVerifyContext,
|
||||
buildAiPanelSelectionSummary,
|
||||
} from '../utils/strategyEvaluationAiVerify';
|
||||
import type { StrategyEvaluationAiVerifyResponse } from '../utils/backendApi';
|
||||
|
||||
@@ -106,7 +106,6 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
const [aiVerifyError, setAiVerifyError] = useState<string | null>(null);
|
||||
const [aiVerifyResult, setAiVerifyResult] = useState<StrategyEvaluationAiVerifyResponse | null>(null);
|
||||
const [aiVerifyContext, setAiVerifyContext] = useState<import('../utils/strategyEvaluationAiVerify').StrategyEvaluationAiVerifyContext | null>(null);
|
||||
const [aiVerifySummary, setAiVerifySummary] = useState<string | null>(null);
|
||||
const aiVerifyGenRef = useRef(0);
|
||||
const rightTabRef = useRef<RightTab>('signal');
|
||||
const aiVerifyPollAbortRef = useRef<AbortController | null>(null);
|
||||
@@ -298,6 +297,19 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
[backtestSignals, selectedBarTimeSec, selectedBarIndex],
|
||||
);
|
||||
|
||||
const aiPanelSelectionSummary = useMemo(
|
||||
() => buildAiPanelSelectionSummary({
|
||||
market,
|
||||
timeframe: chartTimeframe,
|
||||
bars,
|
||||
selectedBarIndex,
|
||||
snapshot,
|
||||
barSignalHighlight,
|
||||
strategyName: selectedStrategy?.name ?? null,
|
||||
}),
|
||||
[market, chartTimeframe, bars, selectedBarIndex, snapshot, barSignalHighlight, selectedStrategy?.name],
|
||||
);
|
||||
|
||||
const handleSignalsChange = useCallback((signals: BacktestSignal[]) => {
|
||||
setBacktestSignals(signals);
|
||||
}, []);
|
||||
@@ -439,7 +451,6 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
indicatorParams,
|
||||
evaluationBarCount: Math.min(BACKTEST_DISPLAY_BAR_COUNT, bars.length),
|
||||
});
|
||||
setAiVerifySummary(summarizeVerifyContext(context));
|
||||
setAiVerifyContext(context);
|
||||
|
||||
const result = await requestStrategyEvaluationAiVerify(context, {
|
||||
@@ -863,7 +874,7 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
<StrategyEvaluationAiVerifyPanel
|
||||
loading={aiVerifyRunning}
|
||||
error={aiVerifyError}
|
||||
contextSummary={aiVerifySummary}
|
||||
selectionSummary={aiPanelSelectionSummary}
|
||||
verifyContext={aiVerifyContext}
|
||||
result={aiVerifyResult}
|
||||
runDisabled={aiVerifyDisabled}
|
||||
|
||||
@@ -207,7 +207,8 @@ const FixPointsPanel: React.FC<{ bundle: AiVerifyFixPointsBundle }> = ({ bundle
|
||||
export interface StrategyEvaluationAiVerifyPanelProps {
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
contextSummary: string | null;
|
||||
/** 차트 선택 봉·평가 요약 (실시간) */
|
||||
selectionSummary: string | null;
|
||||
verifyContext: StrategyEvaluationAiVerifyContext | null;
|
||||
result: StrategyEvaluationAiVerifyResponse | null;
|
||||
runDisabled?: boolean;
|
||||
@@ -217,7 +218,7 @@ export interface StrategyEvaluationAiVerifyPanelProps {
|
||||
const StrategyEvaluationAiVerifyPanel: React.FC<StrategyEvaluationAiVerifyPanelProps> = ({
|
||||
loading,
|
||||
error,
|
||||
contextSummary,
|
||||
selectionSummary,
|
||||
verifyContext,
|
||||
result,
|
||||
runDisabled = false,
|
||||
@@ -238,18 +239,15 @@ const StrategyEvaluationAiVerifyPanel: React.FC<StrategyEvaluationAiVerifyPanelP
|
||||
}
|
||||
}, [result?.analysis]);
|
||||
|
||||
const hasContent = loading || error || result;
|
||||
|
||||
return (
|
||||
<div className="seval-ai-verify-panel">
|
||||
<header className="seval-ai-verify-panel-head">
|
||||
<div className="seval-ai-verify-panel-head-main">
|
||||
{contextSummary && (
|
||||
<p className="seval-ai-verify-summary">{contextSummary}</p>
|
||||
)}
|
||||
{!contextSummary && !hasContent && (
|
||||
{selectionSummary ? (
|
||||
<pre className="seval-ai-verify-panel-selection">{selectionSummary}</pre>
|
||||
) : (
|
||||
<p className="seval-ai-verify-panel-empty-hint">
|
||||
차트 툴바의 AI 검증 버튼 또는 아래 실행으로 선택 봉 기준 LLM 분석을 시작합니다.
|
||||
차트에서 봉을 선택하면 해당 캔들 정보가 표시됩니다.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -265,7 +263,7 @@ const StrategyEvaluationAiVerifyPanel: React.FC<StrategyEvaluationAiVerifyPanelP
|
||||
분석 중…
|
||||
</>
|
||||
) : (
|
||||
result ? '다시 분석' : '분석 실행'
|
||||
'AI 분석'
|
||||
)}
|
||||
</button>
|
||||
</header>
|
||||
|
||||
@@ -1203,6 +1203,16 @@
|
||||
color: var(--se-text-muted, #8b949e);
|
||||
}
|
||||
|
||||
.seval-ai-verify-panel-selection {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: 0.72rem;
|
||||
line-height: 1.5;
|
||||
color: var(--se-text-muted, #8b949e);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.seval-ai-verify-panel-run-btn {
|
||||
flex-shrink: 0;
|
||||
display: inline-flex;
|
||||
|
||||
@@ -379,6 +379,58 @@ export function summarizeVerifyContext(ctx: StrategyEvaluationAiVerifyContext):
|
||||
].join(' · ');
|
||||
}
|
||||
|
||||
/** AI 분석 탭 — 차트에서 선택한 봉 정보 (분석 실행 전·후 공통) */
|
||||
export function buildAiPanelSelectionSummary(opts: {
|
||||
market: string;
|
||||
timeframe: string;
|
||||
bars: OHLCVBar[];
|
||||
selectedBarIndex: number;
|
||||
snapshot?: VirtualIndicatorSnapshot;
|
||||
barSignalHighlight: BarSignalHighlight;
|
||||
strategyName?: string | null;
|
||||
}): string | null {
|
||||
const bar = opts.bars[opts.selectedBarIndex];
|
||||
if (!bar) return null;
|
||||
|
||||
const timeLabel = new Date(bar.time * 1000).toLocaleString('ko-KR');
|
||||
const lines: string[] = [];
|
||||
|
||||
if (opts.strategyName) {
|
||||
lines.push(`전략: ${opts.strategyName}`);
|
||||
}
|
||||
lines.push(`${opts.market} · ${opts.timeframe}`);
|
||||
lines.push(`선택 봉 index=${opts.selectedBarIndex} · ${timeLabel}`);
|
||||
lines.push(`O=${bar.open} H=${bar.high} L=${bar.low} C=${bar.close}`);
|
||||
|
||||
const { snapshot } = opts;
|
||||
if (snapshot) {
|
||||
const evalParts: string[] = [];
|
||||
if (snapshot.overallEntryMet != null) {
|
||||
evalParts.push(`매수 ${snapshot.overallEntryMet ? '충족' : '미충족'}`);
|
||||
}
|
||||
if (snapshot.overallExitMet != null) {
|
||||
evalParts.push(`매도 ${snapshot.overallExitMet ? '충족' : '미충족'}`);
|
||||
}
|
||||
if (snapshot.matchRate != null) {
|
||||
evalParts.push(`일치율 ${snapshot.matchRate}%`);
|
||||
}
|
||||
if (evalParts.length > 0) {
|
||||
lines.push(evalParts.join(' · '));
|
||||
}
|
||||
} else {
|
||||
lines.push('봉 평가 준비 중…');
|
||||
}
|
||||
|
||||
const { buy, sell } = opts.barSignalHighlight;
|
||||
if (buy || sell) {
|
||||
lines.push(`차트 시그널: ${[buy && 'BUY', sell && 'SELL'].filter(Boolean).join(', ')}`);
|
||||
} else {
|
||||
lines.push('선택 봉 차트 시그널 없음');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/** Cursor AI에 붙여넣을 수정 포인트 항목 */
|
||||
export interface AiVerifyFixPoint {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user