전략 시간봉 오류 수정

This commit is contained in:
Macbook
2026-05-28 02:01:36 +09:00
parent 01218b99c9
commit 5f9b20d907
9 changed files with 362 additions and 82 deletions
@@ -10,6 +10,7 @@ import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -159,6 +160,45 @@ class StrategyConditionTimeframeServiceTest {
assertFalse(service.usesTimeframe(5L, "1m"));
}
@Test
void collectForStrategy_staleStartUsesConditionTimeframeForAnyTf() {
for (String tf : List.of("3m", "5m", "15m", "1h")) {
GcStrategy strategy = new GcStrategy();
strategy.setId(10L);
strategy.setName("tf test " + tf);
strategy.setBuyConditionJson("""
{
"type": "TIMEFRAME",
"candleType": "1m",
"candleTypes": ["1m", "%s"],
"children": [{
"type": "CONDITION",
"condition": {
"indicatorType": "RSI",
"leftCandleType": "%s",
"rightCandleType": "%s"
}
}]
}
""".formatted(tf, tf, tf));
strategy.setSellConditionJson(null);
when(strategyRepo.findById(10L)).thenReturn(Optional.of(strategy));
when(dslNormalizer.alignSellStartTimeframeToBuy(org.mockito.ArgumentMatchers.any(), org.mockito.ArgumentMatchers.any()))
.thenAnswer(inv -> inv.getArgument(1));
when(dslNormalizer.normalizeJson(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.any()))
.thenAnswer(inv -> {
String json = inv.getArgument(0);
String name = inv.getArgument(1);
return new StrategyDslTimeframeNormalizer(objectMapper).normalizeJson(json, name);
});
Set<String> tfs = service.collectForStrategy(10L);
assertEquals(Set.of(tf), tfs, "expected only " + tf);
assertFalse(service.usesTimeframe(10L, "1m"), "1m should not be used for " + tf);
service.invalidate(10L);
}
}
@Test
void collectForStrategy_stale1m5mArrayUses5mOnlyWhenConditionsSay5m() {
GcStrategy strategy = new GcStrategy();
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
@@ -75,6 +76,26 @@ class StrategyDslTimeframeNormalizerTest {
assertEquals("5m", root.path("candleType").asText());
}
@Test
void resolveStartCandleTypes_meaningfulOverridesStaleStart1m() throws Exception {
String json = """
{
"type": "TIMEFRAME",
"candleType": "1m",
"children": [{
"type": "CONDITION",
"condition": {
"indicatorType": "CCI",
"leftCandleType": "5m",
"rightCandleType": "5m"
}
}]
}
""";
JsonNode root = objectMapper.readTree(json);
assertEquals(Set.of("5m"), StrategyDslTimeframeNormalizer.resolveStartCandleTypes(root));
}
@Test
void resolveStartCandleTypes_dropsStale1mPair() throws Exception {
String json = """
@@ -95,6 +116,51 @@ class StrategyDslTimeframeNormalizerTest {
assertEquals(Set.of("5m"), StrategyDslTimeframeNormalizer.resolveStartCandleTypes(root));
}
@Test
void resolveStartCandleTypes_resolves3mAnd15mAnd1h() throws Exception {
for (String tf : List.of("3m", "15m", "1h")) {
String json = """
{
"type": "TIMEFRAME",
"candleType": "1m",
"children": [{
"type": "CONDITION",
"condition": {
"indicatorType": "RSI",
"leftCandleType": "%s",
"rightCandleType": "%s"
}
}]
}
""".formatted(tf, tf);
JsonNode root = objectMapper.readTree(json);
assertEquals(Set.of(tf), StrategyDslTimeframeNormalizer.resolveStartCandleTypes(root),
"expected " + tf);
}
}
@Test
void normalize_alignsStaleStartToConditionTimeframe() throws Exception {
String json = """
{
"type": "TIMEFRAME",
"candleType": "1m",
"candleTypes": ["1m", "15m"],
"children": [{
"type": "CONDITION",
"condition": {
"indicatorType": "CCI",
"leftCandleType": "15m"
}
}]
}
""";
JsonNode root = objectMapper.readTree(normalizer.normalizeJson(json, "test"));
assertEquals(1, root.path("candleTypes").size());
assertEquals("15m", root.path("candleTypes").get(0).asText());
assertEquals("15m", root.path("candleType").asText());
}
@Test
void normalize_preservesMultiCandleTypesOnSave() throws Exception {
String json = """