debug: 백테스팅 실행 시 파라미터·시그널 생성 상세 로그 추가
인디케이터 파라미터 로드 현황, positionMode, 생성된 시그널 수를 INFO 레벨로 출력하여 서버에서 정확한 진단 가능하도록 한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -88,6 +88,14 @@ public class BacktestingService {
|
|||||||
}
|
}
|
||||||
// 요청에 포함된 파라미터가 있으면 DB 값 위에 덮어씀 (요청값 우선)
|
// 요청에 포함된 파라미터가 있으면 DB 값 위에 덮어씀 (요청값 우선)
|
||||||
Map<String, Map<String, Object>> params = mergeIndicatorParams(dbParams, req.getIndicatorParams());
|
Map<String, Map<String, Object>> params = mergeIndicatorParams(dbParams, req.getIndicatorParams());
|
||||||
|
log.info("[Backtest] 인디케이터 파라미터 로드 — deviceId={}, dbParams키={}, reqParams키={}, 최종키={}",
|
||||||
|
req.getDeviceId(),
|
||||||
|
dbParams.keySet(),
|
||||||
|
req.getIndicatorParams() != null ? req.getIndicatorParams().keySet() : "null",
|
||||||
|
params.keySet());
|
||||||
|
if (params.containsKey("Stochastic")) {
|
||||||
|
log.info("[Backtest] Stochastic 파라미터: {}", params.get("Stochastic"));
|
||||||
|
}
|
||||||
if (params.isEmpty()) {
|
if (params.isEmpty()) {
|
||||||
log.warn("[Backtest] 인디케이터 파라미터 없음 — deviceId={}, 지표 기본값 사용 가능성 있음", req.getDeviceId());
|
log.warn("[Backtest] 인디케이터 파라미터 없음 — deviceId={}, 지표 기본값 사용 가능성 있음", req.getDeviceId());
|
||||||
}
|
}
|
||||||
@@ -153,6 +161,8 @@ public class BacktestingService {
|
|||||||
// positionMode: LONG_ONLY(기본) | SIGNAL_ONLY(포지션 락 우회)
|
// positionMode: LONG_ONLY(기본) | SIGNAL_ONLY(포지션 락 우회)
|
||||||
String posMode = cfg.getPositionMode() != null ? cfg.getPositionMode() : "LONG_ONLY";
|
String posMode = cfg.getPositionMode() != null ? cfg.getPositionMode() : "LONG_ONLY";
|
||||||
boolean signalOnly = "SIGNAL_ONLY".equals(posMode);
|
boolean signalOnly = "SIGNAL_ONLY".equals(posMode);
|
||||||
|
log.info("[Backtest] 실행 시작 — strategyId={}, bars={}, timeframe={}, positionMode={}, signalOnly={}",
|
||||||
|
req.getStrategyId(), series.getBarCount(), req.getTimeframe(), posMode, signalOnly);
|
||||||
|
|
||||||
double initCap = cfg.getInitialCapital() != null ? cfg.getInitialCapital().doubleValue() : 10_000_000.0;
|
double initCap = cfg.getInitialCapital() != null ? cfg.getInitialCapital().doubleValue() : 10_000_000.0;
|
||||||
double tradeSizePct = cfg.getTradeSizeValue() != null ? cfg.getTradeSizeValue().doubleValue() / 100.0 : 1.0;
|
double tradeSizePct = cfg.getTradeSizeValue() != null ? cfg.getTradeSizeValue().doubleValue() / 100.0 : 1.0;
|
||||||
@@ -175,15 +185,19 @@ public class BacktestingService {
|
|||||||
|
|
||||||
// ── SIGNAL_ONLY 모드: 포지션·자금 상태 무관, 조건 충족 시마다 전체 시그널 생성 ──
|
// ── SIGNAL_ONLY 모드: 포지션·자금 상태 무관, 조건 충족 시마다 전체 시그널 생성 ──
|
||||||
if (signalOnly) {
|
if (signalOnly) {
|
||||||
if (entryRule.isSatisfied(i)) {
|
boolean entrySatisfied = entryRule.isSatisfied(i);
|
||||||
|
boolean exitSatisfied = exitRule.isSatisfied(i);
|
||||||
|
if (entrySatisfied) {
|
||||||
double effEntry = applySlippage(closePrice, cfg, true);
|
double effEntry = applySlippage(closePrice, cfg, true);
|
||||||
String buyType = "SHORT".equals(direction) ? "SHORT_ENTRY" : "BUY";
|
String buyType = "SHORT".equals(direction) ? "SHORT_ENTRY" : "BUY";
|
||||||
signals.add(buildFillSignal(time, buyType, effEntry, i, 1.0));
|
signals.add(buildFillSignal(time, buyType, effEntry, i, 1.0));
|
||||||
|
log.debug("[Backtest:SIGNAL_ONLY] BUY @ bar={} price={}", i, effEntry);
|
||||||
}
|
}
|
||||||
if (exitRule.isSatisfied(i)) {
|
if (exitSatisfied) {
|
||||||
double effExit = applySlippage(exitPrice, cfg, false);
|
double effExit = applySlippage(exitPrice, cfg, false);
|
||||||
String sellType = "SHORT".equals(direction) ? "SHORT_EXIT" : "SELL";
|
String sellType = "SHORT".equals(direction) ? "SHORT_EXIT" : "SELL";
|
||||||
signals.add(buildFillSignal(time, sellType, effExit, i, 1.0));
|
signals.add(buildFillSignal(time, sellType, effExit, i, 1.0));
|
||||||
|
log.debug("[Backtest:SIGNAL_ONLY] SELL @ bar={} price={}", i, effExit);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -248,6 +262,11 @@ public class BacktestingService {
|
|||||||
if (useLedger) ledger.markToMarket(closePrice);
|
if (useLedger) ledger.markToMarket(closePrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long buyCnt = signals.stream().filter(s -> "BUY".equals(s.type()) || "SHORT_ENTRY".equals(s.type())).count();
|
||||||
|
long sellCnt = signals.stream().filter(s -> "SELL".equals(s.type()) || "SHORT_EXIT".equals(s.type())).count();
|
||||||
|
log.info("[Backtest] 완료 — strategyId={}, bars={}, 생성시그널={}개 (매수={}, 매도={}), positionMode={}",
|
||||||
|
req.getStrategyId(), barCount, signals.size(), buyCnt, sellCnt, posMode);
|
||||||
|
|
||||||
double lastMarkPrice = barCount > 0
|
double lastMarkPrice = barCount > 0
|
||||||
? series.getBar(barCount - 1).getClosePrice().doubleValue() : 0.0;
|
? series.getBar(barCount - 1).getClosePrice().doubleValue() : 0.0;
|
||||||
double finalEquity = resolveFinalEquity(ledger, useLedger, cfg, initCap, equity, inPosition,
|
double finalEquity = resolveFinalEquity(ledger, useLedger, cfg, initCap, equity, inPosition,
|
||||||
|
|||||||
Reference in New Issue
Block a user