전략평가 오류 수정

This commit is contained in:
Macbook
2026-06-16 00:36:00 +09:00
parent 133e3d0413
commit e93164deda
6 changed files with 191 additions and 27 deletions
@@ -27,6 +27,7 @@ import { getKoreanName } from '../utils/marketNameCache';
import { useIndicatorSettings } from '../hooks/useIndicatorSettings';
import {
mergeEvalGetParams,
buildEvalParamsFromStrategy,
type EvalIndicatorParams,
} from '../utils/strategyEvaluationParams';
import {
@@ -216,12 +217,13 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
setEvalLoading(true);
setEvalError(null);
try {
const indicatorParams = buildEvalParamsFromStrategy(selectedStrategy, getEvalParams);
const snap = await fetchEvaluationSnapshotAtBar(
market,
selectedStrategyId,
selectedStrategy,
selectedBarTimeSec,
appliedIndicatorParams,
indicatorParams,
bars,
chartTimeframe,
);
@@ -245,7 +247,7 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
selectedBarIndex,
bars,
chartTimeframe,
appliedIndicatorParams,
getEvalParams,
]);
useEffect(() => {
@@ -14,7 +14,7 @@ import { getIndicatorDef } from '../../utils/indicatorRegistry';
import { DEFAULT_DISPLAY_TIMEZONE } from '../../utils/timezone';
import { getKoreanName } from '../../utils/marketNameCache';
import type { BacktestSignal, StrategyDto } from '../../utils/backendApi';
import { loadBacktestSettings, runBacktest } from '../../utils/backendApi';
import { fetchLiveConditionScanSignals } from '../../utils/backendApi';
import {
BACKTEST_DISPLAY_BAR_COUNT,
fetchBacktestCandleBundle,
@@ -173,7 +173,7 @@ const StrategyEvaluationChart: React.FC<Props> = ({
mgr.setBacktestMarkers(signalsRef.current, true);
}, [strategy]);
const runBacktestForBars = useCallback(async (barData: OHLCVBar[]) => {
const runSignalScanForBars = useCallback(async (barData: OHLCVBar[]) => {
if (!strategy?.id || barData.length < 10) {
setSignals([]);
managerRef.current?.clearBacktestMarkers();
@@ -184,10 +184,10 @@ const StrategyEvaluationChart: React.FC<Props> = ({
setBacktestRunning(true);
setBacktestError(null);
try {
const btSettings = await loadBacktestSettings();
const res = await runBacktest({
strategyId: strategy.id,
bars: barData.map(b => ({
const res = await fetchLiveConditionScanSignals(
market,
strategy.id,
barData.map(b => ({
time: b.time,
open: b.open,
high: b.high,
@@ -196,24 +196,11 @@ const StrategyEvaluationChart: React.FC<Props> = ({
volume: b.volume,
})),
timeframe,
symbol: market,
strategyName: strategy.name,
settings: {
...btSettings,
// 전략 평가 차트 — 조건 충족 시작 봉마다 매수/매도 마커 (포지션 락 무시)
positionMode: 'SIGNAL_ONLY',
},
indicatorParams,
evaluationBarCount: evaluationBarCountRef.current,
});
evaluationBarCountRef.current,
);
if (gen !== backtestGenRef.current) return;
if (!res) {
setSignals([]);
setBacktestError('시그널 계산에 실패했습니다.');
managerRef.current?.clearBacktestMarkers();
return;
}
setSignals(res.signals);
setSignals(res);
applyMarkers();
} catch (e) {
if (gen !== backtestGenRef.current) return;
@@ -236,9 +223,9 @@ const StrategyEvaluationChart: React.FC<Props> = ({
}
return;
}
void runBacktestForBars(bars);
void runSignalScanForBars(bars);
return () => { ++backtestGenRef.current; };
}, [strategy?.id, market, timeframe, paramsRevision, bars, loading, runBacktestForBars]);
}, [strategy?.id, market, timeframe, paramsRevision, bars, loading, runSignalScanForBars]);
useEffect(() => {
applyMarkers();
@@ -459,7 +446,7 @@ const StrategyEvaluationChart: React.FC<Props> = ({
</span>
)}
{strategy && signals.length > 0 && !backtestRunning && (
<span className="seval-chart-signal-count" title="백테스트 매매 시그널">
<span className="seval-chart-signal-count" title="조건 충족 매매 시그널">
{signals.length}
</span>
)}
+39
View File
@@ -1619,6 +1619,45 @@ export async function fetchLiveConditionStatus(
});
}
/** 전략 평가 — 차트 마커용 시그널 스캔 (live-conditions 와 동일 Rule) */
export async function fetchLiveConditionScanSignals(
market: string,
strategyId: number,
chartBars: Array<{
time: number;
open: number;
high: number;
low: number;
close: number;
volume: number;
}>,
chartTimeframe: string,
indicatorParams?: Record<string, Record<string, unknown>> | null,
evaluationBarCount?: number | null,
): Promise<BacktestSignal[]> {
if (chartBars.length === 0 || !chartTimeframe) return [];
const list = await request<BacktestSignal[]>('/strategy/live-conditions/scan-signals', {
method: 'POST',
cache: 'no-store',
body: JSON.stringify({
market,
strategyId,
indicatorParams: indicatorParams ?? undefined,
bars: chartBars.map(b => ({
time: b.time,
open: b.open,
high: b.high,
low: b.low,
close: b.close,
volume: b.volume,
})),
timeframe: chartTimeframe,
evaluationBarCount: evaluationBarCount ?? undefined,
}),
});
return list ?? [];
}
/** 전략 DSL에 포함된 평가 시간봉 목록 (실시간 체크·STOMP 구독용) */
export async function loadStrategyTimeframes(strategyId: number): Promise<string[]> {
if (!hasRegisteredUser()) return ['1m'];