직접입력값 평가오류 수정
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package com.goldenchart.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
class IndicatorHlineResolverTest {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
@Test
|
||||
void k55_alwaysResolvesTo55_notNearestHline() throws Exception {
|
||||
var cond = MAPPER.readTree("""
|
||||
{"thresholdOverride": false, "targetValue": null}
|
||||
""");
|
||||
Map<String, Map<String, Object>> visual = Map.of(
|
||||
"RSI", Map.of("hlines", java.util.List.of(
|
||||
Map.of("label", "과열선", "price", 70),
|
||||
Map.of("label", "중앙선", "price", 50),
|
||||
Map.of("label", "침체선", "price", 30))));
|
||||
|
||||
Double val = IndicatorHlineResolver.resolveThresholdField(
|
||||
cond, "K_55", "RSI", visual);
|
||||
assertEquals(55.0, val, 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void k55_withTargetValue_prefersTargetValue() throws Exception {
|
||||
var cond = MAPPER.readTree("""
|
||||
{"thresholdOverride": true, "targetValue": 55}
|
||||
""");
|
||||
Double val = IndicatorHlineResolver.resolveThresholdField(
|
||||
cond, "K_55", "RSI", Map.of());
|
||||
assertEquals(55.0, val, 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hlMid_usesVisualNotKSemantics() throws Exception {
|
||||
var cond = MAPPER.readTree("""
|
||||
{"thresholdOverride": false}
|
||||
""");
|
||||
Map<String, Map<String, Object>> visual = Map.of(
|
||||
"RSI", Map.of("hlines", java.util.List.of(
|
||||
Map.of("label", "중앙선", "price", 48))));
|
||||
|
||||
Double val = IndicatorHlineResolver.resolveThresholdField(
|
||||
cond, "HL_MID", "RSI", visual);
|
||||
assertEquals(48.0, val, 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void blankField_returnsNull() {
|
||||
assertNull(IndicatorHlineResolver.resolveThresholdField(
|
||||
null, "", "RSI", Map.of()));
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,71 @@ class RsiThresholdCrossSignalTest {
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rsiCrossUp_k55_producesSignals() throws Exception {
|
||||
List<Integer> hits50 = scanHits("""
|
||||
{
|
||||
"indicatorType": "RSI",
|
||||
"conditionType": "CROSS_UP",
|
||||
"leftField": "RSI_VALUE_9",
|
||||
"rightField": "K_50",
|
||||
"period": 9,
|
||||
"valuePeriodOverride": true,
|
||||
"thresholdOverride": true,
|
||||
"targetValue": 50,
|
||||
"candleRange": 1
|
||||
}
|
||||
""", Map.of("RSI", Map.of("length", 9)), Map.of());
|
||||
List<Integer> hits55 = scanHits("""
|
||||
{
|
||||
"indicatorType": "RSI",
|
||||
"conditionType": "CROSS_UP",
|
||||
"leftField": "RSI_VALUE_9",
|
||||
"rightField": "K_55",
|
||||
"period": 9,
|
||||
"valuePeriodOverride": true,
|
||||
"thresholdOverride": true,
|
||||
"targetValue": 55,
|
||||
"candleRange": 1
|
||||
}
|
||||
""", Map.of("RSI", Map.of("length", 9)), Map.of());
|
||||
org.junit.jupiter.api.Assertions.assertFalse(hits55.isEmpty(),
|
||||
"K_55 should produce CROSS_UP signals on oscillating series");
|
||||
org.junit.jupiter.api.Assertions.assertTrue(hits55.size() <= hits50.size(),
|
||||
"K_55 (higher threshold) should have <= hits than K_50");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rsiCrossUp_k55_withoutTargetValue_usesFieldNumber() throws Exception {
|
||||
List<Integer> hitsWithTarget = scanHits("""
|
||||
{
|
||||
"indicatorType": "RSI",
|
||||
"conditionType": "CROSS_UP",
|
||||
"leftField": "RSI_VALUE_9",
|
||||
"rightField": "K_55",
|
||||
"period": 9,
|
||||
"valuePeriodOverride": true,
|
||||
"thresholdOverride": true,
|
||||
"targetValue": 55,
|
||||
"candleRange": 1
|
||||
}
|
||||
""", Map.of("RSI", Map.of("length", 9)), Map.of());
|
||||
List<Integer> hitsFieldOnly = scanHits("""
|
||||
{
|
||||
"indicatorType": "RSI",
|
||||
"conditionType": "CROSS_UP",
|
||||
"leftField": "RSI_VALUE_9",
|
||||
"rightField": "K_55",
|
||||
"period": 9,
|
||||
"valuePeriodOverride": true,
|
||||
"thresholdOverride": false,
|
||||
"candleRange": 1
|
||||
}
|
||||
""", Map.of("RSI", Map.of("length", 9)), Map.of());
|
||||
assertEquals(hitsWithTarget, hitsFieldOnly,
|
||||
"K_55 field should resolve to 55 even without targetValue");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rsiCrossUp_hlMid_equalsK50WithoutOverride() throws Exception {
|
||||
assertSignalHitsEqual(
|
||||
|
||||
+49
-7
@@ -5,14 +5,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class StrategyConditionThresholdNormalizerTest {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
@Test
|
||||
void normalizesK50OverrideToHlMid() throws Exception {
|
||||
void preservesK50DirectInput() throws Exception {
|
||||
JsonNode root = MAPPER.readTree("""
|
||||
{
|
||||
"type": "CONDITION",
|
||||
@@ -29,11 +29,53 @@ class StrategyConditionThresholdNormalizerTest {
|
||||
}
|
||||
""");
|
||||
|
||||
JsonNode normalized = StrategyConditionThresholdNormalizer.normalizeTree(root);
|
||||
JsonNode cond = normalized.path("condition");
|
||||
JsonNode cond = StrategyConditionThresholdNormalizer.normalizeTree(root).path("condition");
|
||||
|
||||
assertEquals("HL_MID", cond.path("rightField").asText());
|
||||
assertFalse(cond.path("thresholdOverride").asBoolean(true));
|
||||
assertFalse(cond.has("targetValue"));
|
||||
assertEquals("K_50", cond.path("rightField").asText());
|
||||
assertTrue(cond.path("thresholdOverride").asBoolean(false));
|
||||
assertEquals(50.0, cond.path("targetValue").asDouble(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preservesK55DirectInput() throws Exception {
|
||||
JsonNode root = MAPPER.readTree("""
|
||||
{
|
||||
"type": "CONDITION",
|
||||
"condition": {
|
||||
"indicatorType": "RSI",
|
||||
"conditionType": "CROSS_UP",
|
||||
"leftField": "RSI_VALUE",
|
||||
"rightField": "K_55",
|
||||
"thresholdOverride": true,
|
||||
"targetValue": 55
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
JsonNode cond = StrategyConditionThresholdNormalizer.normalizeTree(root).path("condition");
|
||||
|
||||
assertEquals("K_55", cond.path("rightField").asText());
|
||||
assertTrue(cond.path("thresholdOverride").asBoolean(false));
|
||||
assertEquals(55.0, cond.path("targetValue").asDouble(), 0.0001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void fillsTargetValueFromKFieldWhenMissing() throws Exception {
|
||||
JsonNode root = MAPPER.readTree("""
|
||||
{
|
||||
"type": "CONDITION",
|
||||
"condition": {
|
||||
"indicatorType": "RSI",
|
||||
"rightField": "K_55",
|
||||
"thresholdOverride": false
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
JsonNode cond = StrategyConditionThresholdNormalizer.normalizeTree(root).path("condition");
|
||||
|
||||
assertEquals("K_55", cond.path("rightField").asText());
|
||||
assertTrue(cond.path("thresholdOverride").asBoolean(false));
|
||||
assertEquals(55.0, cond.path("targetValue").asDouble(), 0.0001);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user