가상매매 수정
This commit is contained in:
+76
-18
@@ -4,8 +4,8 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.goldenchart.entity.GcStrategy;
|
||||
import com.goldenchart.repository.GcStrategyRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -19,15 +19,27 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* START / TIMEFRAME / AND|OR+TIMEFRAME 분기와 동일 규칙.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class StrategyConditionTimeframeService {
|
||||
|
||||
private final GcStrategyRepository strategyRepo;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final StrategyDslTimeframeNormalizer dslNormalizer;
|
||||
private final LiveStrategyEvaluator liveStrategyEvaluator;
|
||||
|
||||
private final ConcurrentHashMap<Long, Set<String>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
public StrategyConditionTimeframeService(
|
||||
GcStrategyRepository strategyRepo,
|
||||
ObjectMapper objectMapper,
|
||||
StrategyDslTimeframeNormalizer dslNormalizer,
|
||||
@Lazy LiveStrategyEvaluator liveStrategyEvaluator) {
|
||||
this.strategyRepo = strategyRepo;
|
||||
this.objectMapper = objectMapper;
|
||||
this.dslNormalizer = dslNormalizer;
|
||||
this.liveStrategyEvaluator = liveStrategyEvaluator;
|
||||
}
|
||||
|
||||
public Set<String> collectForStrategy(long strategyId) {
|
||||
return cache.computeIfAbsent(strategyId, this::loadFromDb);
|
||||
}
|
||||
@@ -53,33 +65,79 @@ public class StrategyConditionTimeframeService {
|
||||
Optional<GcStrategy> opt = strategyRepo.findById(strategyId);
|
||||
if (opt.isEmpty()) return Set.of("1m");
|
||||
GcStrategy strategy = opt.get();
|
||||
ensureDslRepaired(strategy);
|
||||
|
||||
Set<String> out = new LinkedHashSet<>();
|
||||
collectFromJson(strategy.getBuyConditionJson(), out);
|
||||
collectFromJson(strategy.getSellConditionJson(), out);
|
||||
return out.isEmpty() ? Set.of("1m") : out;
|
||||
collectFromJson(strategy.getBuyConditionJson(), out, strategy.getName());
|
||||
collectFromJson(strategy.getSellConditionJson(), out, strategy.getName());
|
||||
|
||||
if (out.isEmpty()) {
|
||||
String fromName = StrategyDslTimeframeNormalizer.inferFromStrategyName(strategy.getName());
|
||||
return Set.of(fromName != null ? fromName : "1m");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private void collectFromJson(String json, Set<String> out) {
|
||||
if (json == null || json.isBlank()) return;
|
||||
try {
|
||||
collectFromNode(objectMapper.readTree(json), out);
|
||||
} catch (Exception e) {
|
||||
log.warn("[StrategyTimeframes] JSON 파싱 실패: {}", e.getMessage());
|
||||
out.add("1m");
|
||||
/** TIMEFRAME 누락·잘못된 1m 래핑을 전략명·DSL 기준으로 DB 보정 */
|
||||
private void ensureDslRepaired(GcStrategy strategy) {
|
||||
boolean changed = false;
|
||||
String name = strategy.getName();
|
||||
|
||||
if (strategy.getBuyConditionJson() != null && !strategy.getBuyConditionJson().isBlank()) {
|
||||
String fixed = dslNormalizer.normalizeJson(strategy.getBuyConditionJson(), name);
|
||||
if (!fixed.equals(strategy.getBuyConditionJson())) {
|
||||
strategy.setBuyConditionJson(fixed);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (strategy.getSellConditionJson() != null && !strategy.getSellConditionJson().isBlank()) {
|
||||
String fixed = dslNormalizer.normalizeJson(strategy.getSellConditionJson(), name);
|
||||
if (!fixed.equals(strategy.getSellConditionJson())) {
|
||||
strategy.setSellConditionJson(fixed);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
strategyRepo.save(strategy);
|
||||
liveStrategyEvaluator.invalidateStrategy(strategy.getId());
|
||||
log.info("[StrategyTimeframes] DSL 분봉 보정 strategyId={} name={}",
|
||||
strategy.getId(), name);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectFromNode(JsonNode node, Set<String> out) {
|
||||
private void collectFromJson(String json, Set<String> out, String strategyName) {
|
||||
if (json == null || json.isBlank()) return;
|
||||
try {
|
||||
collectFromNode(objectMapper.readTree(json), out, strategyName);
|
||||
} catch (Exception e) {
|
||||
log.warn("[StrategyTimeframes] JSON 파싱 실패: {}", e.getMessage());
|
||||
addFallbackTimeframe(out, strategyName);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectFromNode(JsonNode node, Set<String> out, String strategyName) {
|
||||
if (node == null || node.isNull()) return;
|
||||
if (collectTimeframesFromNode(node, out)) return;
|
||||
|
||||
Set<String> explicit = StrategyDslTimeframeNormalizer.collectExplicitCandleTypes(node);
|
||||
if (!explicit.isEmpty()) {
|
||||
out.addAll(explicit);
|
||||
Set<String> meaningful = StrategyDslTimeframeNormalizer.collectMeaningfulCandleTypes(node);
|
||||
if (!meaningful.isEmpty()) {
|
||||
out.addAll(meaningful);
|
||||
return;
|
||||
}
|
||||
// TIMEFRAME·명시 분봉 없음 — 기본 1m
|
||||
out.add("1m");
|
||||
|
||||
String fromName = StrategyDslTimeframeNormalizer.inferFromStrategyName(strategyName);
|
||||
if (fromName != null) {
|
||||
out.add(fromName);
|
||||
return;
|
||||
}
|
||||
|
||||
addFallbackTimeframe(out, strategyName);
|
||||
}
|
||||
|
||||
private void addFallbackTimeframe(Set<String> out, String strategyName) {
|
||||
String fromName = StrategyDslTimeframeNormalizer.inferFromStrategyName(strategyName);
|
||||
out.add(fromName != null ? fromName : "1m");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user