전략조건 상세설명 기능 추가
This commit is contained in:
@@ -30,7 +30,7 @@ public class LiveStrategySettingsService {
|
||||
private final AppSettingsService appSettingsService;
|
||||
private final DynamicSubscriptionManager subscriptionManager;
|
||||
private final LiveStrategyEvaluator liveStrategyEvaluator;
|
||||
private final LiveStrategyTimeframeService timeframeService;
|
||||
private final StrategyConditionTimeframeService conditionTimeframes;
|
||||
|
||||
// ── 조회 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -42,7 +42,9 @@ public class LiveStrategySettingsService {
|
||||
? toDto(entity.get())
|
||||
: defaultDtoFromApp(market, app);
|
||||
// 실시간 체크 마스터 스위치·전략 ID는 앱 전역 설정(gc_app_settings) 기준
|
||||
return mergeGlobalTemplate(dto, app, market);
|
||||
dto = mergeGlobalTemplate(dto, app, market);
|
||||
enrichStrategyTimeframes(dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@@ -52,21 +54,17 @@ public class LiveStrategySettingsService {
|
||||
return List.of();
|
||||
}
|
||||
List<String> watchlist = listWatchlistSymbols(userId, deviceId);
|
||||
Long strategyId = app.getLiveStrategyId();
|
||||
List<String> strategyCandleTypes = conditionTimeframes.collectForStrategyList(strategyId);
|
||||
return watchlist.stream()
|
||||
.map(m -> {
|
||||
Optional<GcLiveStrategySettings> row = findEntity(userId, deviceId, m);
|
||||
String ct = row.map(GcLiveStrategySettings::getCandleType)
|
||||
.map(LiveStrategyTimeframeService::normalize)
|
||||
.orElseGet(() -> timeframeService.resolveCandleType(m, userId, deviceId));
|
||||
return LiveStrategySettingsDto.builder()
|
||||
.map(m -> LiveStrategySettingsDto.builder()
|
||||
.market(m)
|
||||
.strategyId(app.getLiveStrategyId())
|
||||
.strategyId(strategyId)
|
||||
.liveCheck(true)
|
||||
.executionType(app.getLiveExecutionType())
|
||||
.positionMode(app.getLivePositionMode())
|
||||
.candleType(ct)
|
||||
.build();
|
||||
})
|
||||
.strategyCandleTypes(strategyCandleTypes)
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -77,18 +75,12 @@ public class LiveStrategySettingsService {
|
||||
GcAppSettings app = appSettingsService.getEntity(userId, deviceId);
|
||||
LiveStrategySettingsDto template = findEntity(userId, deviceId, market)
|
||||
.map(e -> mergeGlobalTemplate(toDto(e), app, market))
|
||||
.orElseGet(() -> {
|
||||
LiveStrategySettingsDto dto = defaultDtoFromApp(market, app);
|
||||
String inherited = resolveSharedCandleType(userId, deviceId);
|
||||
if (inherited != null) {
|
||||
dto.setCandleType(inherited);
|
||||
}
|
||||
return mergeGlobalTemplate(dto, app, market);
|
||||
});
|
||||
.orElseGet(() -> mergeGlobalTemplate(defaultDtoFromApp(market, app), app, market));
|
||||
template.setLiveCheck(true);
|
||||
enrichStrategyTimeframes(template);
|
||||
upsertEntity(userId, deviceId, template);
|
||||
pinIfReady(market, template);
|
||||
log.debug("[LiveStrategy] watchlist add → enabled {} candleType={}", market, template.getCandleType());
|
||||
log.debug("[LiveStrategy] watchlist add → enabled {}", market);
|
||||
}
|
||||
|
||||
/** 관심종목 해제 시 — 해당 종목 전략 체크 비활성화 */
|
||||
@@ -121,7 +113,6 @@ public class LiveStrategySettingsService {
|
||||
.liveCheck(true)
|
||||
.executionType(template.getExecutionType())
|
||||
.positionMode(template.getPositionMode())
|
||||
.candleType(template.getCandleType() != null ? template.getCandleType() : "1m")
|
||||
.build();
|
||||
results.add(upsertEntity(userId, deviceId, one));
|
||||
}
|
||||
@@ -148,9 +139,7 @@ public class LiveStrategySettingsService {
|
||||
if (dto.getPositionMode() != null) {
|
||||
out.setPositionMode(dto.getPositionMode());
|
||||
}
|
||||
if (dto.getCandleType() != null) {
|
||||
out.setCandleType(LiveStrategyTimeframeService.normalize(dto.getCandleType()));
|
||||
}
|
||||
enrichStrategyTimeframes(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -170,9 +159,6 @@ public class LiveStrategySettingsService {
|
||||
GcAppSettings app = appSettingsService.getEntity(userId, deviceId);
|
||||
boolean active = Boolean.TRUE.equals(app.getLiveStrategyCheck())
|
||||
&& app.getLiveStrategyId() != null;
|
||||
String candleType = template != null && template.getCandleType() != null
|
||||
? LiveStrategyTimeframeService.normalize(template.getCandleType())
|
||||
: resolveSharedCandleType(userId, deviceId);
|
||||
for (String symbol : listWatchlistSymbols(userId, deviceId)) {
|
||||
LiveStrategySettingsDto row = findEntity(userId, deviceId, symbol)
|
||||
.map(e -> mergeGlobalTemplate(toDto(e), app, symbol))
|
||||
@@ -183,9 +169,7 @@ public class LiveStrategySettingsService {
|
||||
? app.getLiveExecutionType() : row.getExecutionType());
|
||||
row.setPositionMode(app.getLivePositionMode() != null
|
||||
? app.getLivePositionMode() : row.getPositionMode());
|
||||
if (candleType != null) {
|
||||
row.setCandleType(candleType);
|
||||
}
|
||||
enrichStrategyTimeframes(row);
|
||||
LiveStrategySettingsDto saved = upsertEntity(userId, deviceId, row);
|
||||
if (active) {
|
||||
pinIfReady(symbol, saved);
|
||||
@@ -193,15 +177,21 @@ public class LiveStrategySettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
/** 관심종목 중 이미 저장된 평가 분봉 (전역 템플릿 동기화용) */
|
||||
private String resolveSharedCandleType(Long userId, String deviceId) {
|
||||
for (String symbol : listWatchlistSymbols(userId, deviceId)) {
|
||||
Optional<GcLiveStrategySettings> row = findEntity(userId, deviceId, symbol);
|
||||
if (row.isPresent() && row.get().getCandleType() != null) {
|
||||
return LiveStrategyTimeframeService.normalize(row.get().getCandleType());
|
||||
private void enrichStrategyTimeframes(LiveStrategySettingsDto dto) {
|
||||
if (dto.getStrategyId() != null) {
|
||||
dto.setStrategyCandleTypes(
|
||||
conditionTimeframes.collectForStrategyList(dto.getStrategyId()));
|
||||
}
|
||||
}
|
||||
|
||||
private void pinAllStrategyTimeframes(String market, Long strategyId) {
|
||||
if (strategyId == null) return;
|
||||
subscriptionManager.ensureMarketPinned(market, "1m");
|
||||
for (String ct : conditionTimeframes.collectForStrategy(strategyId)) {
|
||||
if (!"1m".equals(ct)) {
|
||||
subscriptionManager.ensureMarketPinned(market, ct);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LiveStrategySettingsDto upsertEntity(Long userId, String deviceId,
|
||||
@@ -222,8 +212,6 @@ public class LiveStrategySettingsService {
|
||||
"REALTIME_TICK".equals(dto.getExecutionType()) ? "REALTIME_TICK" : "CANDLE_CLOSE");
|
||||
entity.setPositionMode(
|
||||
"SIGNAL_ONLY".equals(dto.getPositionMode()) ? "SIGNAL_ONLY" : "LONG_ONLY");
|
||||
entity.setCandleType(LiveStrategyTimeframeService.normalize(
|
||||
dto.getCandleType() != null ? dto.getCandleType() : "1m"));
|
||||
|
||||
repo.save(entity);
|
||||
liveStrategyEvaluator.invalidateCache(market);
|
||||
@@ -232,12 +220,7 @@ public class LiveStrategySettingsService {
|
||||
|
||||
private void pinIfReady(String market, LiveStrategySettingsDto dto) {
|
||||
if (Boolean.TRUE.equals(dto.isLiveCheck()) && dto.getStrategyId() != null) {
|
||||
String ct = LiveStrategyTimeframeService.normalize(
|
||||
dto.getCandleType() != null ? dto.getCandleType() : "1m");
|
||||
subscriptionManager.ensureMarketPinned(market, "1m");
|
||||
if (!"1m".equals(ct)) {
|
||||
subscriptionManager.ensureMarketPinned(market, ct);
|
||||
}
|
||||
pinAllStrategyTimeframes(market, dto.getStrategyId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,14 +260,15 @@ public class LiveStrategySettingsService {
|
||||
}
|
||||
|
||||
private LiveStrategySettingsDto toDto(GcLiveStrategySettings e) {
|
||||
return LiveStrategySettingsDto.builder()
|
||||
LiveStrategySettingsDto dto = LiveStrategySettingsDto.builder()
|
||||
.market(e.getMarket())
|
||||
.strategyId(e.getStrategyId())
|
||||
.liveCheck(Boolean.TRUE.equals(e.getIsLiveCheck()))
|
||||
.executionType(e.getExecutionType())
|
||||
.positionMode(e.getPositionMode() != null ? e.getPositionMode() : "LONG_ONLY")
|
||||
.candleType(e.getCandleType() != null ? e.getCandleType() : "1m")
|
||||
.build();
|
||||
enrichStrategyTimeframes(dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
/** 앱 전역 실시간 체크 ON/OFF·전략 ID를 DTO에 반영 (종목별 행과 분리) */
|
||||
@@ -309,17 +293,6 @@ public class LiveStrategySettingsService {
|
||||
.liveCheck(Boolean.TRUE.equals(app.getLiveStrategyCheck()))
|
||||
.executionType(app.getLiveExecutionType() != null ? app.getLiveExecutionType() : "CANDLE_CLOSE")
|
||||
.positionMode(app.getLivePositionMode() != null ? app.getLivePositionMode() : "LONG_ONLY")
|
||||
.candleType(LiveStrategyTimeframeService.normalize(
|
||||
app.getDefaultTimeframe() != null
|
||||
? mapAppTf(app.getDefaultTimeframe()) : "1m"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static String mapAppTf(String tf) {
|
||||
return switch (tf) {
|
||||
case "1m", "3m", "5m", "15m", "30m", "1h", "4h" -> tf;
|
||||
case "1D" -> "1d";
|
||||
default -> "1m";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user