전략평가 오류 수정

This commit is contained in:
Macbook
2026-06-17 01:16:41 +09:00
parent f1ce499809
commit 7c3f3433e7
7 changed files with 210 additions and 27 deletions
@@ -263,7 +263,7 @@ public class LiveConditionStatusService {
StrategyDslToTa4jAdapter.RuleBuildContext ctx =
new StrategyDslToTa4jAdapter.RuleBuildContext(
series, params, visual, market, ta4jStorage, false, seriesOverrides);
series, params, visual, market, null, false, seriesOverrides);
Rule rule = adapter.toRule(wrapper, ctx);
boolean satisfied = rule.isSatisfied(index, null);
Double current = adapter.readConditionFieldValue(
@@ -315,6 +315,10 @@ public class LiveConditionStatusService {
if (normalized.equals(primaryTf)) {
return primarySeries;
}
// 차트봉 평가 — overrides 가 있으면 storage 와 혼합하지 않음
if (!overrides.isEmpty()) {
return primarySeries;
}
if (ta4jStorage.exists(market, normalized)) {
return ta4jStorage.getOrCreate(market, normalized);
}
@@ -333,7 +337,7 @@ public class LiveConditionStatusService {
StrategyDslToTa4jAdapter.RuleBuildContext ctx =
new StrategyDslToTa4jAdapter.RuleBuildContext(
primarySeries, params, visual, market, ta4jStorage, false, seriesOverrides);
primarySeries, params, visual, market, null, false, seriesOverrides);
Rule rule = adapter.toRule(dsl, ctx);
int index = OhlcvBarSeriesSupport.resolveBarIndex(primarySeries, barTimeSec);
return rule.isSatisfied(index, null);
@@ -739,7 +743,7 @@ public class LiveConditionStatusService {
return signals;
} catch (Exception e) {
log.warn("[LiveCondition:scan] fail market={} strategy={}: {}",
market, strategyId, e.getMessage());
market, strategyId, e.getMessage(), e);
return List.of();
}
}
@@ -123,6 +123,13 @@ final class OhlcvBarSeriesSupport {
if (node == null || node.isNull()) return;
String type = node.path("type").asText("");
if ("TIMEFRAME".equals(type)) {
JsonNode types = node.path("candleTypes");
if (types.isArray()) {
for (JsonNode t : types) {
String ct = t.asText("");
if (!ct.isBlank()) result.add(normalizeTf(ct));
}
}
String ct = node.path("candleType").asText("");
if (!ct.isBlank()) result.add(normalizeTf(ct));
}
@@ -523,8 +523,13 @@ public class StrategyDslTimeframeNormalizer {
out.add("__multi__");
return;
}
String ct = LiveStrategyTimeframeService.normalize(node.path("candleType").asText("1m"));
out.add(ct);
JsonNode types = node.path("candleTypes");
if (types.isArray() && !types.isEmpty()) {
out.add(LiveStrategyTimeframeService.normalize(types.get(0).asText("1m")));
} else {
String ct = LiveStrategyTimeframeService.normalize(node.path("candleType").asText("1m"));
out.add(ct);
}
}
JsonNode children = node.path("children");
if (children.isArray()) {
@@ -152,10 +152,14 @@ public class StrategyDslToTa4jAdapter {
BarSeries resolveSeries(String candleType) {
String ct = LiveStrategyTimeframeService.normalize(candleType);
// 백테스트 사전 집계 시리즈 우선 검색
// 백테스트·차트 scan — 사전 집계 시리즈 우선
if (seriesOverrides != null && seriesOverrides.containsKey(ct)) {
return seriesOverrides.get(ct);
}
// 차트봉 scan/eval — Ta4jStorage(실시간 1m 등)와 OHLCV 혼합 금지 (시그널 0·차트 불일치)
if (seriesOverrides != null && !seriesOverrides.isEmpty()) {
return primarySeries;
}
if (storage != null && market != null && !market.isBlank()
&& storage.exists(market, ct)) {
return storage.getOrCreate(market, ct);
@@ -252,7 +256,7 @@ public class StrategyDslToTa4jAdapter {
}
private Rule buildTimeframeRule(JsonNode node, RuleBuildContext ctx) {
String ct = node.path("candleType").asText("1m");
String ct = resolveTimeframeCandleType(node);
BarSeries branchSeries = ctx.resolveSeries(ct);
RuleBuildContext branchCtx = ctx.withPrimary(branchSeries);
List<Rule> rules = childRules(node, branchCtx);
@@ -263,6 +267,15 @@ public class StrategyDslToTa4jAdapter {
ctx.useConfirmedOnly(), ctx.isBacktest());
}
/** TIMEFRAME 노드 — candleTypes[0] 우선, 없으면 candleType (레거시 기본 1m) */
private static String resolveTimeframeCandleType(JsonNode node) {
JsonNode types = node.path("candleTypes");
if (types.isArray() && !types.isEmpty()) {
return LiveStrategyTimeframeService.normalize(types.get(0).asText("1m"));
}
return LiveStrategyTimeframeService.normalize(node.path("candleType").asText("1m"));
}
/**
* 다른 시간봉 시리즈로 빌드된 Rule.
*