fix: 백테스트 시간봉·캔들 수 불일치로 시그널 누락 문제 해결
- 전략 DSL 시간봉(5m)과 실행 시간봉(3m) 불일치 시 자동 동기화 - 업비트 캔들 200봉 제한 → 페이지네이션으로 800봉까지 조회 - 백테스트 차트는 실행 타임프레임 기준으로 표시 (시그널·지표 정렬) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -119,8 +119,40 @@ public class HistoricalDataService {
|
||||
|
||||
// ── 업비트 REST 프록시 ────────────────────────────────────────────────────
|
||||
|
||||
private static final int UPBIT_PAGE_SIZE = 200;
|
||||
|
||||
/** 업비트 REST — count 초과 시 200봉 단위 페이지네이션 (백테스트 800봉 등) */
|
||||
private List<UpbitCandleRaw> fetchFromUpbit(String market, String candleType,
|
||||
String to, int count) {
|
||||
TreeMap<Long, UpbitCandleRaw> byTime = new TreeMap<>();
|
||||
String cursorTo = to;
|
||||
|
||||
while (byTime.size() < count) {
|
||||
int pageSize = Math.min(count - byTime.size(), UPBIT_PAGE_SIZE);
|
||||
List<UpbitCandleRaw> page = fetchFromUpbitOnce(market, candleType, cursorTo, pageSize);
|
||||
if (page.isEmpty()) break;
|
||||
|
||||
int before = byTime.size();
|
||||
for (UpbitCandleRaw bar : page) byTime.putIfAbsent(bar.time, bar);
|
||||
if (byTime.size() == before) break;
|
||||
|
||||
long oldest = byTime.firstKey();
|
||||
cursorTo = Instant.ofEpochSecond(oldest)
|
||||
.atZone(java.time.ZoneOffset.UTC)
|
||||
.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
|
||||
if (page.size() < pageSize) break;
|
||||
}
|
||||
|
||||
List<UpbitCandleRaw> merged = new ArrayList<>(byTime.values());
|
||||
if (merged.size() > count) {
|
||||
return merged.subList(merged.size() - count, merged.size());
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
private List<UpbitCandleRaw> fetchFromUpbitOnce(String market, String candleType,
|
||||
String to, int count) {
|
||||
String path = Ta4jStorage.CANDLE_TYPE_MAP.getOrDefault(candleType, "minutes/1");
|
||||
String url = upbitBaseUrl + "/v1/candles/" + path
|
||||
+ "?market=" + market
|
||||
@@ -142,11 +174,10 @@ public class HistoricalDataService {
|
||||
objectMapper.readValue(json, new TypeReference<>() {});
|
||||
|
||||
// 업비트 응답은 최신→과거 순 → 시간 오름차순으로 뒤집기
|
||||
List<UpbitCandleRaw> list = raw.stream()
|
||||
return raw.stream()
|
||||
.map(this::parseUpbitCandle)
|
||||
.sorted(Comparator.comparingLong(c -> c.time))
|
||||
.collect(Collectors.toList());
|
||||
return list;
|
||||
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
Reference in New Issue
Block a user