2026-01-10 18:16:50 +09:00
|
|
|
package util
|
|
|
|
|
|
2026-03-20 17:55:27 +09:00
|
|
|
import network.KisTradeService
|
2026-01-10 18:16:50 +09:00
|
|
|
import java.time.LocalTime
|
|
|
|
|
import java.time.ZoneId
|
|
|
|
|
|
|
|
|
|
object MarketUtil {
|
2026-03-20 17:55:27 +09:00
|
|
|
private var isHolidayCached: Boolean? = null // 하루 한 번만 체크하기 위한 캐시
|
2026-06-03 13:27:05 +09:00
|
|
|
var holiDays = hashMapOf<String, Boolean>()
|
2026-03-20 17:55:27 +09:00
|
|
|
suspend fun canTradeToday(): Boolean {
|
|
|
|
|
val seoulZone = java.time.ZoneId.of("Asia/Seoul")
|
|
|
|
|
val now = java.time.ZonedDateTime.now(seoulZone)
|
|
|
|
|
val todayStr = now.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd"))
|
|
|
|
|
|
|
|
|
|
// 1. 주말 체크
|
|
|
|
|
val dayOfWeek = now.dayOfWeek.value
|
|
|
|
|
if (dayOfWeek >= 6) return false
|
|
|
|
|
// 1. 주말 체크 (토, 일)
|
2026-06-03 13:27:05 +09:00
|
|
|
try {
|
|
|
|
|
if (holiDays.contains(todayStr)) {
|
|
|
|
|
println("📂 [DB Cache] 오늘($todayStr)의 휴장 여부를 DB에서 로드했습니다: ${if(holiDays.get(todayStr) == true) "휴장" else "영업일"}")
|
|
|
|
|
return holiDays.get(todayStr) == false
|
|
|
|
|
}
|
|
|
|
|
} catch (e: Exception) {e.printStackTrace()}
|
|
|
|
|
|
2026-03-20 17:55:27 +09:00
|
|
|
|
|
|
|
|
// 3. DB에 없으면 API 호출
|
|
|
|
|
return try {
|
|
|
|
|
val result = KisTradeService.fetchIsHoliday(todayStr)
|
|
|
|
|
val isHoliday = result.getOrDefault(true)
|
|
|
|
|
|
|
|
|
|
// 결과를 DB에 저장하여 다음 실행 시 재사용
|
2026-06-03 13:27:05 +09:00
|
|
|
holiDays.put(todayStr, isHoliday)
|
2026-03-20 17:55:27 +09:00
|
|
|
|
|
|
|
|
println("🌐 [API Call] 오늘($todayStr)의 휴장 여부를 새로 조회하여 DB에 저장했습니다.")
|
2026-06-04 10:42:54 +09:00
|
|
|
isHoliday
|
2026-03-20 17:55:27 +09:00
|
|
|
} catch (e: Exception) {
|
2026-06-03 13:27:05 +09:00
|
|
|
e.printStackTrace()
|
2026-03-20 17:55:27 +09:00
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-10 18:16:50 +09:00
|
|
|
fun isKoreanMarketOpen(): Boolean {
|
|
|
|
|
// 한국 시간대 기준 현재 시간 가져오기
|
|
|
|
|
val now = LocalTime.now(ZoneId.of("Asia/Seoul"))
|
|
|
|
|
val start = LocalTime.of(9, 0)
|
|
|
|
|
val end = LocalTime.of(15, 30)
|
|
|
|
|
|
|
|
|
|
// 주말 제외 로직은 필요시 추가 (일단 시간대 우선)
|
|
|
|
|
return now.isAfter(start) && now.isBefore(end)
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 14:52:09 +09:00
|
|
|
fun getTickSize(price: Double): Double {
|
|
|
|
|
return when {
|
|
|
|
|
price < 2000 -> 1.0
|
|
|
|
|
price < 5000 -> 5.0
|
|
|
|
|
price < 20000 -> 10.0
|
|
|
|
|
price < 50000 -> 50.0
|
|
|
|
|
price < 200000 -> 100.0
|
|
|
|
|
price < 500000 -> 500.0
|
|
|
|
|
else -> 1000.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-19 17:09:37 +09:00
|
|
|
fun roundToTickSize(price: Double): Double {
|
|
|
|
|
val tick = when {
|
|
|
|
|
price < 2000 -> 1.0
|
|
|
|
|
price < 5000 -> 5.0
|
|
|
|
|
price < 20000 -> 10.0
|
|
|
|
|
price < 50000 -> 50.0
|
|
|
|
|
price < 200000 -> 100.0
|
|
|
|
|
price < 500000 -> 500.0
|
|
|
|
|
else -> 1000.0
|
|
|
|
|
}
|
|
|
|
|
// 가장 가까운 호가 단위로 반올림
|
|
|
|
|
return Math.round(price / tick) * tick
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 13:14:11 +09:00
|
|
|
|
2026-01-10 18:16:50 +09:00
|
|
|
}
|