fix: 백테스트 시간봉·캔들 수 불일치로 시그널 누락 문제 해결
- 전략 DSL 시간봉(5m)과 실행 시간봉(3m) 불일치 시 자동 동기화 - 업비트 캔들 200봉 제한 → 페이지네이션으로 800봉까지 조회 - 백테스트 차트는 실행 타임프레임 기준으로 표시 (시그널·지표 정렬) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,9 @@ import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { ReactFlowProvider } from '@xyflow/react';
|
||||
import DraggableModalFrame from './DraggableModalFrame';
|
||||
import type { Theme } from '../types/index';
|
||||
import { hasRegisteredUser, loadStrategies, loadStrategy, saveStrategy, deleteStrategy, type StrategyDto as ApiStrategyDto } from '../utils/backendApi';
|
||||
import { hasRegisteredUser, loadStrategies, loadStrategy, saveStrategy, deleteStrategy, runBacktest, loadBacktestSettings, loadIndicatorSettings, API_BASE, type StrategyDto as ApiStrategyDto } from '../utils/backendApi';
|
||||
import { timeframeToCandleType } from '../utils/chartCandleType';
|
||||
import { resolveStrategyPrimaryTimeframe } from '../utils/strategyToChartIndicators';
|
||||
import { syncStrategyTimeframesFromLayoutIfNeeded } from '../utils/strategyTimeframeSync';
|
||||
import type { LogicNode } from '../utils/strategyTypes';
|
||||
import {
|
||||
@@ -86,8 +88,6 @@ import { readStoredSize, storeSize, usePanelResize } from './strategyEditor/useP
|
||||
import StrategyDescriptionModal from './strategyEditor/StrategyDescriptionModal';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { MarketSearchPanel } from './MarketSearchPanel';
|
||||
import { runBacktest, loadBacktestSettings, loadIndicatorSettings, API_BASE } from '../utils/backendApi';
|
||||
import { timeframeToCandleType } from '../utils/chartCandleType';
|
||||
import { getKoreanName } from '../utils/marketNameCache';
|
||||
import type { Timeframe } from '../types';
|
||||
import '../styles/strategyEditor.css';
|
||||
@@ -207,6 +207,17 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
const [qbMarketOpen, setQbMarketOpen] = useState(false);
|
||||
const [qbMarketQ, setQbMarketQ] = useState('');
|
||||
const qbMarketBtnRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
// 전략 선택/조건 변경 시 DSL 기준 시간봉으로 빠른 실행 TF 동기화
|
||||
useEffect(() => {
|
||||
if (selectedId == null) return;
|
||||
const tf = resolveStrategyPrimaryTimeframe({
|
||||
buyCondition: buyCondition,
|
||||
sellCondition: sellCondition,
|
||||
} as ApiStrategyDto);
|
||||
setQbTimeframe(prev => (prev === tf ? prev : tf));
|
||||
}, [selectedId, buyCondition, sellCondition]);
|
||||
|
||||
const [leftWidth, setLeftWidth] = useState(() => readStoredSize('se-left-width', LEFT_PANEL_DEFAULT));
|
||||
const [terminalHeight, setTerminalHeight] = useState(() => readStoredSize('se-terminal-height', TERMINAL_DEFAULT));
|
||||
const leftWidthRef = useRef(leftWidth);
|
||||
@@ -981,12 +992,16 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
setQbError(null);
|
||||
try {
|
||||
const selectedStrategy = strategies.find(s => s.id === selectedId);
|
||||
const execTimeframe = resolveStrategyPrimaryTimeframe({
|
||||
buyCondition: buyCondition,
|
||||
sellCondition: sellCondition,
|
||||
} as ApiStrategyDto);
|
||||
const [settings, indicatorParams, barsRes] = await Promise.all([
|
||||
loadBacktestSettings(),
|
||||
loadIndicatorSettings(),
|
||||
fetch(`${API_BASE}/candles/history?${new URLSearchParams({
|
||||
market: qbMarket,
|
||||
type: timeframeToCandleType(qbTimeframe),
|
||||
type: timeframeToCandleType(execTimeframe),
|
||||
count: '800',
|
||||
})}`),
|
||||
]);
|
||||
@@ -1000,7 +1015,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
const result = await runBacktest({
|
||||
strategyId: selectedId,
|
||||
bars,
|
||||
timeframe: qbTimeframe,
|
||||
timeframe: execTimeframe,
|
||||
settings,
|
||||
indicatorParams,
|
||||
symbol: qbMarket,
|
||||
@@ -1016,7 +1031,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
} finally {
|
||||
setQbLoading(false);
|
||||
}
|
||||
}, [selectedId, strategies, qbMarket, qbTimeframe, onNavigateToBacktest]);
|
||||
}, [selectedId, strategies, qbMarket, buyCondition, sellCondition, onNavigateToBacktest]);
|
||||
|
||||
const operators = [
|
||||
{ type: 'operator' as const, value: 'AND', label: 'AND', color: 'logic-and' },
|
||||
|
||||
Reference in New Issue
Block a user