전략편집기 복합지표 기능 반영
This commit is contained in:
@@ -158,6 +158,9 @@ public class StrategyDslToTa4jAdapter {
|
||||
String condType = cond.path("conditionType").asText("GT");
|
||||
String leftField = cond.path("leftField").asText("NONE");
|
||||
String rightField = cond.path("rightField").asText("NONE");
|
||||
int condPeriod = cond.path("period").asInt(-1);
|
||||
int leftPeriod = cond.path("leftPeriod").asInt(-1);
|
||||
int rightPeriod = cond.path("rightPeriod").asInt(-1);
|
||||
int slopePeriod = cond.path("slopePeriod").asInt(3);
|
||||
int holdDays = cond.path("holdDays").asInt(3);
|
||||
|
||||
@@ -168,8 +171,8 @@ public class StrategyDslToTa4jAdapter {
|
||||
: Map.of();
|
||||
|
||||
try {
|
||||
Indicator<Num> left = resolveField(leftField, indType, indParams, series);
|
||||
Indicator<Num> right = resolveField(rightField, indType, indParams, series);
|
||||
Indicator<Num> left = resolveField(leftField, indType, indParams, series, condPeriod, leftPeriod);
|
||||
Indicator<Num> right = resolveField(rightField, indType, indParams, series, condPeriod, rightPeriod);
|
||||
|
||||
return switch (condType) {
|
||||
case "GT" -> new OverIndicatorRule(left, right);
|
||||
@@ -225,7 +228,8 @@ public class StrategyDslToTa4jAdapter {
|
||||
// ── 필드 Resolver ─────────────────────────────────────────────────────────
|
||||
|
||||
private Indicator<Num> resolveField(String field, String indType,
|
||||
Map<String, Object> p, BarSeries s) {
|
||||
Map<String, Object> p, BarSeries s,
|
||||
int condPeriod, int sidePeriod) {
|
||||
if (field == null || field.isBlank() || field.equals("NONE")) {
|
||||
return new ConstantIndicator<>(s, s.numFactory().numOf(0));
|
||||
}
|
||||
@@ -240,7 +244,7 @@ public class StrategyDslToTa4jAdapter {
|
||||
if (!Double.isNaN(constant)) {
|
||||
yield new ConstantIndicator<>(s, s.numFactory().numOf(constant));
|
||||
}
|
||||
yield resolveIndicatorField(field, indType, p, s);
|
||||
yield resolveIndicatorField(field, indType, p, s, condPeriod, sidePeriod);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -266,15 +270,25 @@ public class StrategyDslToTa4jAdapter {
|
||||
}
|
||||
|
||||
private Indicator<Num> resolveIndicatorField(String field, String indType,
|
||||
Map<String, Object> p, BarSeries s) {
|
||||
Map<String, Object> p, BarSeries s,
|
||||
int condPeriod, int sidePeriod) {
|
||||
ClosePriceIndicator close = new ClosePriceIndicator(s);
|
||||
int periodOverride = sidePeriod > 0 ? sidePeriod : (condPeriod > 0 ? condPeriod : -1);
|
||||
|
||||
// CCI — 프론트엔드 indicatorRegistry 기본값 20 과 통일
|
||||
// CCI — 기간 접미사(CCI_VALUE_13) 또는 기본 CCI_VALUE
|
||||
if (field.startsWith("CCI_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "CCI_VALUE_", intP(p, "length", 13));
|
||||
return new CCIIndicator(s, period);
|
||||
}
|
||||
if (field.equals("CCI_VALUE") || indType.equals("CCI"))
|
||||
return new CCIIndicator(s, intP(p, "length", 13));
|
||||
// RSI — 표준 기본값 14
|
||||
return new CCIIndicator(s, periodOverride > 0 ? periodOverride : intP(p, "length", 13));
|
||||
// RSI — 기간 접미사(RSI_VALUE_9) 또는 기본 RSI_VALUE
|
||||
if (field.startsWith("RSI_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "RSI_VALUE_", intP(p, "length", 14));
|
||||
return new RSIIndicator(close, period);
|
||||
}
|
||||
if (field.equals("RSI_VALUE"))
|
||||
return new RSIIndicator(close, intP(p, "length", 14));
|
||||
return new RSIIndicator(close, periodOverride > 0 ? periodOverride : intP(p, "length", 14));
|
||||
// MACD
|
||||
if (field.equals("MACD_LINE")) {
|
||||
return new MACDIndicator(close, intP(p, "fastLength", 12), intP(p, "slowLength", 26));
|
||||
@@ -289,6 +303,10 @@ public class StrategyDslToTa4jAdapter {
|
||||
return NumericIndicator.of(macd).minus(new EMAIndicator(macd, intP(p, "signalLength", 9)));
|
||||
}
|
||||
// ADX / DMI
|
||||
if (field.startsWith("ADX_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "ADX_VALUE_", intP(p, "adxSmoothing", 14));
|
||||
return new ADXIndicator(s, intP(p, "diLength", 14), period);
|
||||
}
|
||||
if (field.equals("ADX_VALUE"))
|
||||
return new ADXIndicator(s, intP(p, "diLength", 14), intP(p, "adxSmoothing", 14));
|
||||
if (field.equals("PDI") || field.equals("PLUS_DI")) {
|
||||
@@ -316,6 +334,12 @@ public class StrategyDslToTa4jAdapter {
|
||||
return new SMAIndicator(slowK, dSmooth);
|
||||
}
|
||||
// TRIX — ln(종가) → 3×EMA → Δ×10000 (업비트)
|
||||
if (field.startsWith("TRIX_VALUE_")) {
|
||||
int len = parseTrailingInt(field, "TRIX_VALUE_", intP(p, "length", 12));
|
||||
EMAIndicator e3 = tripleLogEma(close, len);
|
||||
PreviousValueIndicator prev3 = new PreviousValueIndicator(e3);
|
||||
return NumericIndicator.of(e3).minus(prev3).multipliedBy(10_000);
|
||||
}
|
||||
if (field.equals("TRIX_VALUE")) {
|
||||
int len = intP(p, "length", 12);
|
||||
EMAIndicator e3 = tripleLogEma(close, len);
|
||||
@@ -342,6 +366,10 @@ public class StrategyDslToTa4jAdapter {
|
||||
};
|
||||
}
|
||||
// VR
|
||||
if (field.startsWith("VR_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "VR_VALUE_", intP(p, "length", 10));
|
||||
return vrIndicator(s, period);
|
||||
}
|
||||
if (field.equals("VR_VALUE") || indType.equals("VR"))
|
||||
return vrIndicator(s, intP(p, "length", 10));
|
||||
// 이격도 DISPARITY5 → period 5
|
||||
@@ -349,12 +377,24 @@ public class StrategyDslToTa4jAdapter {
|
||||
int period = parseTrailingInt(field, "DISPARITY", 20);
|
||||
return disparityIndicator(s, period, p);
|
||||
}
|
||||
if (field.startsWith("PSY_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "PSY_VALUE_", intP(p, "length", 12));
|
||||
return newPsychIndicator(s, period, false);
|
||||
}
|
||||
if (field.equals("PSY_VALUE") || field.equals("NEW_PSY_VALUE")
|
||||
|| indType.equals("PSYCHOLOGICAL") || indType.equals("NEW_PSYCHOLOGICAL"))
|
||||
return newPsychIndicator(s, intP(p, "length", 12), false);
|
||||
if (field.startsWith("INVEST_PSY_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "INVEST_PSY_VALUE_", intP(p, "length", 10));
|
||||
return newPsychIndicator(s, period, true);
|
||||
}
|
||||
if (field.equals("INVEST_PSY_VALUE") || indType.equals("INVEST_PSYCHOLOGICAL"))
|
||||
return newPsychIndicator(s, intP(p, "length", 10), true);
|
||||
// Williams %R
|
||||
if (field.startsWith("WILLIAMS_R_VALUE_")) {
|
||||
int period = parseTrailingInt(field, "WILLIAMS_R_VALUE_", intP(p, "length", 14));
|
||||
return new WilliamsRIndicator(s, period);
|
||||
}
|
||||
if (field.equals("WILLIAMS_R_VALUE")) return new WilliamsRIndicator(s, intP(p, "length", 14));
|
||||
// Donchian Channel — DC_UPPER_20 / DC_LOWER_10 등 기간 접미사
|
||||
if (field.startsWith("DC_UPPER_")) {
|
||||
|
||||
Reference in New Issue
Block a user