n봉 존재 조건 수정
This commit is contained in:
@@ -412,9 +412,12 @@ public class StrategyDslToTa4jAdapter {
|
||||
int slopePeriod = cond.path("slopePeriod").asInt(3);
|
||||
int holdDays = cond.path("holdDays").asInt(3);
|
||||
int lookbackPeriod = cond.path("lookbackPeriod").asInt(20);
|
||||
int candleRange = cond.path("candleRange").asInt(1);
|
||||
String candleRangeMode = resolveCandleRangeMode(cond, candleRange);
|
||||
|
||||
if (needsCrossTimeframeComposite(cond, ctx)) {
|
||||
return buildCrossTimeframeCompositeRule(cond, ctx);
|
||||
Rule composite = buildCrossTimeframeCompositeRule(cond, ctx);
|
||||
return applyCandleRangeWindow(composite, candleRangeMode, candleRange);
|
||||
}
|
||||
|
||||
PriceExtremeNorm px = normalizePriceExtremeCondition(cond);
|
||||
@@ -496,10 +499,11 @@ public class StrategyDslToTa4jAdapter {
|
||||
yield new BooleanRule(false);
|
||||
}
|
||||
};
|
||||
Rule ranged = applyCandleRangeWindow(core, candleRangeMode, candleRange);
|
||||
if (px != null) {
|
||||
return nanSafeCompareRule(core, left, right);
|
||||
return nanSafeCompareRule(ranged, left, right);
|
||||
}
|
||||
return core;
|
||||
return ranged;
|
||||
} catch (Exception e) {
|
||||
log.warn("[Adapter] 조건 빌드 실패 ind={} cond={}: {}", indType, condType, e.getMessage());
|
||||
return new BooleanRule(false);
|
||||
@@ -1041,6 +1045,71 @@ public class StrategyDslToTa4jAdapter {
|
||||
};
|
||||
}
|
||||
|
||||
/** live-conditions·알림 UI — 캔들 범위 접두어 */
|
||||
public static String candleRangeConditionPrefix(JsonNode cond) {
|
||||
if (cond == null || cond.isNull()) return "";
|
||||
int candleRange = cond.path("candleRange").asInt(1);
|
||||
String mode = cond.path("candleRangeMode").asText("");
|
||||
if (mode.isBlank()) mode = candleRange <= 1 ? "CURRENT" : "EXISTS_IN";
|
||||
if ("CURRENT".equals(mode)) return "";
|
||||
int n = Math.max(2, candleRange);
|
||||
return switch (mode) {
|
||||
case "EXISTS_IN" -> "최근 " + n + "봉 내 ";
|
||||
case "NOT_EXISTS_IN" -> "최근 " + n + "봉 내 없음 · ";
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
/** candleRangeMode 미설정 시 candleRange>1 → EXISTS_IN (구버전 호환) */
|
||||
private String resolveCandleRangeMode(JsonNode cond, int candleRange) {
|
||||
String mode = cond.path("candleRangeMode").asText("");
|
||||
if (!mode.isBlank()) return mode;
|
||||
return candleRange <= 1 ? "CURRENT" : "EXISTS_IN";
|
||||
}
|
||||
|
||||
/** 최근 N봉(현재 봉 포함) 윈도우에 inner 규칙 적용 */
|
||||
private Rule applyCandleRangeWindow(Rule core, String mode, int candleRange) {
|
||||
if ("CURRENT".equals(mode)) return core;
|
||||
int n = Math.max(2, candleRange);
|
||||
return switch (mode) {
|
||||
case "EXISTS_IN" -> buildExistsInWindowRule(core, n);
|
||||
case "NOT_EXISTS_IN" -> buildNotExistsInWindowRule(core, n);
|
||||
default -> core;
|
||||
};
|
||||
}
|
||||
|
||||
/** 최근 N봉 중 어느 한 봉이라도 inner 가 true */
|
||||
private Rule buildExistsInWindowRule(Rule inner, int n) {
|
||||
if (n <= 1) return inner;
|
||||
return new Rule() {
|
||||
@Override
|
||||
public boolean isSatisfied(int index, TradingRecord record) {
|
||||
int start = index - n + 1;
|
||||
for (int i = start; i <= index; i++) {
|
||||
if (i < 0) continue;
|
||||
if (inner.isSatisfied(i, record)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 최근 N봉 중 inner 가 true 인 봉이 하나도 없음 */
|
||||
private Rule buildNotExistsInWindowRule(Rule inner, int n) {
|
||||
if (n <= 1) return new NotRule(inner);
|
||||
return new Rule() {
|
||||
@Override
|
||||
public boolean isSatisfied(int index, TradingRecord record) {
|
||||
int start = index - n + 1;
|
||||
for (int i = start; i <= index; i++) {
|
||||
if (i < 0) continue;
|
||||
if (inner.isSatisfied(i, record)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ── TRIX 헬퍼 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private Indicator<Num> resolvePriceSource(BarSeries s, Map<String, Object> p) {
|
||||
|
||||
Reference in New Issue
Block a user