Files
goldenChart/backend/src/main/java/com/goldenchart/service/LiveStrategyTimeframeService.java
T
2026-05-27 23:36:48 +09:00

86 lines
3.2 KiB
Java

package com.goldenchart.service;
import com.goldenchart.entity.GcAppSettings;
import com.goldenchart.entity.GcLiveStrategySettings;
import com.goldenchart.repository.GcLiveStrategySettingsRepository;
import com.goldenchart.storage.Ta4jStorage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.Optional;
import java.util.Set;
/**
* 종목별 전략 평가 분봉 — DB gc_live_strategy_settings.candle_type.
*/
@Service
@RequiredArgsConstructor
public class LiveStrategyTimeframeService {
private static final Set<String> ALLOWED = Ta4jStorage.CANDLE_TYPE_MAP.keySet();
private final GcLiveStrategySettingsRepository repo;
private final AppSettingsService appSettingsService;
@Transactional(readOnly = true)
public String resolveCandleType(String market, Long userId, String deviceId) {
Optional<GcLiveStrategySettings> row = find(userId, deviceId, market);
if (row.isPresent() && row.get().getCandleType() != null) {
return normalize(row.get().getCandleType());
}
GcAppSettings app = appSettingsService.getEntity(userId, deviceId);
String tf = app.getDefaultTimeframe();
if (tf != null) {
String mapped = mapChartTfToCandleType(tf);
if (mapped != null) return mapped;
}
return "1m";
}
/**
* 워커 스레드 등 user/device 컨텍스트 없을 때 — 해당 마켓 활성 설정의 candle_type.
*/
@Transactional(readOnly = true)
public String resolveCandleTypeForMarket(String market) {
return repo.findActiveByMarket(market).stream()
.filter(s -> s.getCandleType() != null && !s.getCandleType().isBlank())
.max(Comparator.comparing(
GcLiveStrategySettings::getUpdatedAt,
Comparator.nullsLast(Comparator.naturalOrder())))
.map(GcLiveStrategySettings::getCandleType)
.map(LiveStrategyTimeframeService::normalize)
.orElse("1m");
}
public static String normalize(String candleType) {
if (candleType == null || candleType.isBlank()) return "1m";
String c = candleType.trim().toLowerCase();
if ("1d".equals(c)) return "1d";
if ("1w".equals(c)) return "1w";
if ("1h".equals(c)) return "1h";
if ("4h".equals(c)) return "4h";
if (ALLOWED.contains(c)) return c;
return "1m";
}
private static String mapChartTfToCandleType(String chartTf) {
return switch (chartTf) {
case "1m", "3m", "5m", "10m", "15m", "30m" -> chartTf;
case "1h", "4h" -> chartTf;
case "1D" -> "1d";
case "1W" -> "1w";
case "1M" -> "1d";
default -> null;
};
}
private Optional<GcLiveStrategySettings> find(Long userId, String deviceId, String market) {
if (userId != null) return repo.findByUserIdAndMarket(userId, market);
if (deviceId != null && !deviceId.isBlank())
return repo.findByDeviceIdAndMarket(deviceId, market);
return Optional.empty();
}
}