백엔드 전략 조건 평가 버그 3건 수정

1. evaluateOverallRule: 5m 전략 평가 시 1m 고정 시리즈 사용 버그 수정
   - DSL에서 주 시간봉(TIMEFRAME 노드 candleType)을 추출하여 해당 시리즈 사용
   - 없으면 1m 폴백 유지

2. buildConditionRule: kLength 등 지표 파라미터를 조건 노드 params에서 우선 읽도록 수정
   - 조건 DSL의 params 필드가 있으면 전역 indicator settings보다 우선 적용
   - 서버 DB에 indicator settings 없어도 전략 저장 당시 값 사용 가능

3. LiveConditionController: deviceId 헤더를 indicatorSettingsService에 전달
   - x-device-id 헤더를 읽어 device 단위 지표 설정 조회 지원

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-06-11 08:28:05 +09:00
parent b21d40333c
commit 090752f42c
3 changed files with 89 additions and 7 deletions
@@ -427,9 +427,14 @@ public class StrategyDslToTa4jAdapter {
// DSL 타입(STOCHASTIC 등) → DB 레지스트리 키(Stochastic 등) 변환 후 파라미터 조회
String registryKey = toRegistryKey(indType);
Map<String, Object> indParams = params != null
Map<String, Object> globalParams = params != null
? params.getOrDefault(registryKey, Map.of())
: Map.of();
// 조건 노드에 직접 저장된 params가 있으면 전역 설정보다 우선 적용
// 예) {"kLength": 12, "smooth": 3} → 전역 Stochastic 설정(kLength=14)을 덮어씀
Map<String, Object> condNodeParams = extractConditionNodeParams(cond);
Map<String, Object> indParams = condNodeParams.isEmpty() ? globalParams
: mergeParams(globalParams, condNodeParams);
try {
Indicator<Num> left = resolveField(leftField, indType, indParams, series, condPeriod, leftPeriod, cond, ctx);
@@ -1217,12 +1222,50 @@ public class StrategyDslToTa4jAdapter {
private int intP(Map<String, Object> p, String k, int def) {
if (p == null) return def;
Object v = p.get(k);
return v == null ? def : ((Number) v).intValue();
if (v == null) return def;
if (v instanceof Number n) return n.intValue();
try { return Integer.parseInt(v.toString()); } catch (NumberFormatException e) { return def; }
}
private double dblP(Map<String, Object> p, String k, double def) {
if (p == null) return def;
Object v = p.get(k);
return v == null ? def : ((Number) v).doubleValue();
if (v == null) return def;
if (v instanceof Number n) return n.doubleValue();
try { return Double.parseDouble(v.toString()); } catch (NumberFormatException e) { return def; }
}
/**
* 조건 노드 JSON에서 직접 저장된 파라미터를 추출한다.
* 전략 편집기가 저장한 조건별 override params (예: {"kLength": 12}).
* 없거나 객체가 아니면 빈 맵 반환.
*/
@SuppressWarnings("unchecked")
private Map<String, Object> extractConditionNodeParams(JsonNode cond) {
if (cond == null || cond.isNull()) return Map.of();
JsonNode paramsNode = cond.path("params");
if (paramsNode.isMissingNode() || paramsNode.isNull() || !paramsNode.isObject()) {
return Map.of();
}
try {
Map<String, Object> result = new java.util.LinkedHashMap<>();
paramsNode.fields().forEachRemaining(e -> {
com.fasterxml.jackson.databind.JsonNode v = e.getValue();
if (v.isNumber()) result.put(e.getKey(), v.numberValue());
else if (v.isTextual()) result.put(e.getKey(), v.textValue());
else if (v.isBoolean()) result.put(e.getKey(), v.booleanValue());
});
return result;
} catch (Exception ex) {
return Map.of();
}
}
/** globalParams 위에 overrides를 덮어쓴 새 맵 반환 */
private Map<String, Object> mergeParams(Map<String, Object> global,
Map<String, Object> overrides) {
Map<String, Object> merged = new java.util.LinkedHashMap<>(global);
merged.putAll(overrides);
return merged;
}
}