From 3fd9e3d8330ea2a05646ebc089da005cec31fca4 Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Fri, 12 Jun 2026 13:11:23 +0900 Subject: [PATCH] ..... --- src/main/kotlin/network/KisTradeService.kt | 2 +- src/main/kotlin/service/AutoTradingManager.kt | 14 +++--- src/main/kotlin/util/MarketUtil.kt | 47 ++++++++++--------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/network/KisTradeService.kt b/src/main/kotlin/network/KisTradeService.kt index 5a20b96..4142aaf 100644 --- a/src/main/kotlin/network/KisTradeService.kt +++ b/src/main/kotlin/network/KisTradeService.kt @@ -69,7 +69,7 @@ object KisTradeService { val body = response.body() // output의 opnd_yn (영업일 여부)가 'Y'이면 영업일, 'N'이면 휴장일 val isOpeningDay = body["output"]?.jsonArray?.firstOrNull()?.jsonObject?.get("opnd_yn")?.jsonPrimitive?.content == "Y" - Result.success(!isOpeningDay) + Result.success(isOpeningDay) } catch (e: Exception) { Result.failure(e) } diff --git a/src/main/kotlin/service/AutoTradingManager.kt b/src/main/kotlin/service/AutoTradingManager.kt index 67e2d77..006f2d0 100644 --- a/src/main/kotlin/service/AutoTradingManager.kt +++ b/src/main/kotlin/service/AutoTradingManager.kt @@ -118,7 +118,7 @@ object AutoTradingManager { val maxBudget = KisSession.config.getValues(ConfigIndex.MAX_BUDGET_INDEX) * gradeRate TradingLogStore.addLog(decision,"BUY",decision.summary()) - var hasCodes = currentBalance?.getHoldings()?.any { it.code.equals(decision.stockCode) && it.quantity.toInt() > 2} + var hasCodes = currentBalance?.getHoldings()?.any { it.code.equals(decision.stockCode) && it.quantity.toInt() > 2} ?: false if (hasCodes == true) { TradingLogStore.addNotice(decision.stockName,decision.stockCode,"물타기 시도 1주 매수") } @@ -242,7 +242,7 @@ object AutoTradingManager { if (hasCode && oldTarget != null) { var avgPrive = oldTarget.avgPrice.toDouble() var qty = oldTarget.quantity.toDouble() - basePrice = avgPrive * 1.1//((avgPrive * qty) + (decision.currentPrice * orderQty.toInt())).div(qty!!.toInt() + (orderQty.toInt())) + basePrice = avgPrive * 1.5//((avgPrive * qty) + (decision.currentPrice * orderQty.toInt())).div(qty!!.toInt() + (orderQty.toInt())) println("물타기 ${avgPrive}, ${qty} ${basePrice}") } } catch (e:Exception) {e.printStackTrace()} @@ -346,12 +346,15 @@ object AutoTradingManager { if (dbItem != null && execData != null && execData.isFilled) { if (dbItem.status == TradeStatus.PENDING_BUY) { // ✅ 1. 진짜 사온 가격 (실제 매수 체결가) - val actualBuyPrice = execData.price.toDoubleOrNull() ?: dbItem.targetPrice + var actualBuyPrice = execData.price.toDoubleOrNull() ?: dbItem.targetPrice // 💡 [수정] 매수 주문(orderNo)에 대해 '진짜 산 가격'을 기록해야 합니다. // 기존에는 여기에 finalTargetPrice를 넣으셨는데, 그러면 매수 단가가 오염됩니다. TradingReportManager.updateExecution(orderNo, actualBuyPrice, dbItem.quantity) - + var hasCodes = currentBalance?.getHoldings()?.any { it.code.equals(dbItem.code) && it.quantity.toInt() > 2 && dbItem.quantity == KisSession.tradeConfig.lowerAverageStockCount } ?: false + if (hasCodes) { + actualBuyPrice = actualBuyPrice * 1.1 + } val absoluteMinRate = KisSession.config.getValues(ConfigIndex.TAX_INDEX) + 0.05 val finalProfitRate = maxOf(dbItem.profitRate, absoluteMinRate) val finalTargetPrice = MarketUtil.roundToTickSize(actualBuyPrice * (1 + finalProfitRate / 100.0)) @@ -819,9 +822,8 @@ object AutoTradingManager { isSystemReadyToday = false shouldShowFullWindow = false stopDiscovery() // 발굴 루프 완전 폭파 (내일 8시 30분에 다시 켜짐) - } else if (now.isAfter(KisSession.startTime().minusMinutes(10)) && now.isBefore(KisSession.startTime()) && !isSystemReadyToday) { + } else if (now.isAfter(KisSession.startTime().minusMinutes(20)) && now.isBefore(KisSession.startTime()) && !shouldShowFullWindow) { if (MarketUtil.canTradeToday()) { - SystemSleepPreventer.wakeDisplay() shouldShowFullWindow = true println("✅ [System] 오늘은 영업일입니다. 시스템을 가동합니다.") tryRefreshToken() // 토큰 갱신 및 화면 표시 신호(shouldShowFullWindow = true) diff --git a/src/main/kotlin/util/MarketUtil.kt b/src/main/kotlin/util/MarketUtil.kt index 83ceee7..cd8fa9a 100644 --- a/src/main/kotlin/util/MarketUtil.kt +++ b/src/main/kotlin/util/MarketUtil.kt @@ -6,7 +6,7 @@ import java.time.ZoneId object MarketUtil { private var isHolidayCached: Boolean? = null // 하루 한 번만 체크하기 위한 캐시 - var holiDays = hashMapOf() + var canTradeDays = hashMapOf() suspend fun canTradeToday(): Boolean { val seoulZone = java.time.ZoneId.of("Asia/Seoul") val now = java.time.ZonedDateTime.now(seoulZone) @@ -16,28 +16,29 @@ object MarketUtil { val dayOfWeek = now.dayOfWeek.value if (dayOfWeek >= 6) return false // 1. 주말 체크 (토, 일) - 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()} - - - // 3. DB에 없으면 API 호출 - return try { - val result = KisTradeService.fetchIsHoliday(todayStr) - val isHoliday = result.getOrDefault(true) - - // 결과를 DB에 저장하여 다음 실행 시 재사용 - holiDays.put(todayStr, isHoliday) - - println("🌐 [API Call] 오늘($todayStr)의 휴장 여부를 새로 조회하여 DB에 저장했습니다.") - isHoliday - } catch (e: Exception) { - e.printStackTrace() - false - } + return true +// try { +// if (canTradeDays.contains(todayStr)) { +// println("📂 [DB Cache] 오늘($todayStr)의 휴장 여부를 DB에서 로드했습니다: ${if(canTradeDays.get(todayStr) == false) "휴장" else "영업일"}") +// return canTradeDays.get(todayStr) == true +// } +// } catch (e: Exception) {e.printStackTrace()} +// +// +// // 3. DB에 없으면 API 호출 +// return try { +// val result = KisTradeService.fetchIsHoliday(todayStr) +// val canTrade = result.getOrDefault(false) +// +// // 결과를 DB에 저장하여 다음 실행 시 재사용 +// canTradeDays.put(todayStr, canTrade) +// +// println("🌐 [API Call] 오늘($todayStr)의 휴장 여부를 새로 조회하여 DB에 저장했습니다. ${if(canTradeDays.get(todayStr) == false) "휴장" else "영업일"}" ) +// canTrade +// } catch (e: Exception) { +// e.printStackTrace() +// false +// } } fun isKoreanMarketOpen(): Boolean {