From 7d03cc78b1d9b8d319571a2558f05748d25f7347 Mon Sep 17 00:00:00 2001 From: lunaticbum Date: Thu, 9 Apr 2026 17:03:52 +0900 Subject: [PATCH] ... --- src/main/kotlin/Main.kt | 2 +- src/main/kotlin/model/StockModels.kt | 7 ++++++- src/main/kotlin/network/KisTradeService.kt | 10 +++++----- src/main/kotlin/service/AutoTradingManager.kt | 20 ++++++++++++++----- src/main/kotlin/ui/SettingsScreen.kt | 2 +- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 172b038..e08d9e3 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -179,7 +179,7 @@ fun main() = application { println("❌ [명령어 에러] ${command.joinToString(" ")} 실행 중 에러: ${e.message}") } } - + /** * Mac OS 전용: '확인되지 않은 개발자' 보안(Gatekeeper) 해제 및 실행 권한 부여 * @param targetPath 권한을 풀 파일 또는 폴더의 절대 경로 diff --git a/src/main/kotlin/model/StockModels.kt b/src/main/kotlin/model/StockModels.kt index 246157c..8cc9136 100644 --- a/src/main/kotlin/model/StockModels.kt +++ b/src/main/kotlin/model/StockModels.kt @@ -24,6 +24,7 @@ data class StockHolding( val evlu_pfls_rt: String = "0.0", // 평가손익률 val evlu_amt: String = "0" , // 평가금액 val ord_psbl_qty : String = "0", + val thdt_buyqty : String = "0", ) @Serializable @@ -151,8 +152,12 @@ data class UnifiedStockHolding( val evalAmount: String, // 평가금액 val isDomestic: Boolean, // 국내/해외 구분 val availOrderCount : String, + val thdtBuyQty: String, -) +){ + // 당일 매수 여부 판별 (금일 매수 수량이 0보다 크면 당일 진입 종목) + val isTodayEntry: Boolean get() = thdtBuyQty.toInt() > 0 +} @Serializable data class UnifiedBalance( diff --git a/src/main/kotlin/network/KisTradeService.kt b/src/main/kotlin/network/KisTradeService.kt index 47561ab..b1a24d1 100644 --- a/src/main/kotlin/network/KisTradeService.kt +++ b/src/main/kotlin/network/KisTradeService.kt @@ -95,7 +95,7 @@ object KisTradeService { code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty, avgPrice = it.pchs_avg_pric, currentPrice = it.prpr, profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = true, - availOrderCount = it.ord_psbl_qty + availOrderCount = it.ord_psbl_qty, thdtBuyQty = it.thdt_buyqty ).apply { if (it.hldg_qty.toLong() > 0) { // println("보유 종목 : ${it.prdt_name} , 수량 : ${it.hldg_qty}") @@ -109,7 +109,7 @@ object KisTradeService { code = it.pdno, name = it.prdt_name, quantity = it.hldg_qty, avgPrice = it.pchs_avg_pric, currentPrice = it.prpr, profitRate = it.evlu_pfls_rt, evalAmount = it.evlu_amt, isDomestic = false, - availOrderCount = it.ord_psbl_qty + availOrderCount = it.ord_psbl_qty, thdtBuyQty = it.thdt_buyqty )) } @@ -558,7 +558,7 @@ object KisTradeService { val cano = pureAccount.take(8) val acntPrdtCd = pureAccount.takeLast(2) - println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo}") + println("🚀 [잔고조회 시작] 계좌: ${config.realAccountNo} $markgetCode") try { do { @@ -585,12 +585,12 @@ object KisTradeService { } if (!response.status.isSuccess()) { - println("❌ [Step $pageCount] HTTP 에러 발생: ${response.status}") + println("❌ [Step $pageCount] $markgetCode HTTP 에러 발생: ${response.status}") return Result.failure(Exception("HTTP Error: ${response.status}")) } val body = response.body() - println("✅ [Step $pageCount] 수신 완료 - 종목 수: ${body.output1.size}") + println("✅ [Step $pageCount] $markgetCode 수신 완료 - 종목 수: ${body.output1.size}") allHoldings.addAll(body.output1) if (totalBalance == null) totalBalance = body diff --git a/src/main/kotlin/service/AutoTradingManager.kt b/src/main/kotlin/service/AutoTradingManager.kt index f4b8437..67a0830 100644 --- a/src/main/kotlin/service/AutoTradingManager.kt +++ b/src/main/kotlin/service/AutoTradingManager.kt @@ -359,8 +359,14 @@ object AutoTradingManager { "거랙 차단 대상 : ${holding.currentPrice}[${holding.quantity}주] 보유, 수익률(${holding.profitRate.toDouble()})" ) } else { - println("sellingAfterMarketOnePrice") - if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) { + val targetProfitLimit = if (holding.isTodayEntry) { + // 당일 매수 종목: 짧은 익절 (예: 1.0% 이상이면 즉시 매도) + KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)+ KisSession.config.getValues(ConfigIndex.TAX_INDEX) + } else { + // 오래 보유한 종목: 기존 설정값 준수 (예: 3.0% 등) + KisSession.config.SELL_PROFIT + } + if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > targetProfitLimit) { var targetPrice = holding.currentPrice.toDouble() TradingLogStore.addAfterMarketLog( holding.name, @@ -376,7 +382,7 @@ object AutoTradingManager { orderDivision = if (marketCode.equals("Y")) "07" else "", marketCode = if (marketCode.equals("Y")) "KRX" else "NXT" ).onSuccess { newOrderNo -> - println("✅ [재주문 완료] ${holding.name}: $newOrderNo") + println("✅ [${if(marketCode.equals("Y"))"시간외 단일가" else "대체거래소"} 주문 완료] ${holding.name}: $newOrderNo") TradingLogStore.addSellLog( "${holding.name}[${holding.code}]", targetPrice.toString(), @@ -760,7 +766,7 @@ object AutoTradingManager { lastForceCheckMinute = currentMinute // 실행 완료 기록 } } - else if((now.hour == 8 || now.hour == 16 || now.hour == 17) && (currentMinute % 10 == 3)) { + else if((now.hour == 8 || now.hour == 16 || now.hour == 17) && (currentMinute % 10 == 1) || (currentMinute % 10 == 6)) { if (lastForceCheckMinute != currentMinute) { TradingLogStore.addAnalyzer( " - ", @@ -768,7 +774,11 @@ object AutoTradingManager { "⏰ [강제 스케줄 실행] 오후 ${now.hour}시 ${currentMinute}분 - 보유주식 시간외 단일가 또는 대체마켓 체크를 시작합니다.", true ) - listOf("Y","X").forEach { code -> + var list = mutableListOf("x") + if (now.hour != 8) { + list.add("y") + } + list.forEach { code -> KisTradeService.fetchIntegratedBalance(code).getOrNull()?.let { sellingAfterMarketOnePrice(KisTradeService, it, code) } diff --git a/src/main/kotlin/ui/SettingsScreen.kt b/src/main/kotlin/ui/SettingsScreen.kt index aa04e0f..b6d7e38 100644 --- a/src/main/kotlin/ui/SettingsScreen.kt +++ b/src/main/kotlin/ui/SettingsScreen.kt @@ -88,7 +88,7 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) { while (true) { val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul")) // 08:30 ~ 15:30 사이이고, 키값이 최소한 하나라도 존재할 때 자동 실행 - if (now.isAfter(java.time.LocalTime.of(8, 30)) && now.isBefore(java.time.LocalTime.of(15, 30))) { + if (now.isAfter(java.time.LocalTime.of(7, 40)) && now.isBefore(java.time.LocalTime.of(18, 0))) { if (config.realAppKey.isNotEmpty() && config.vtsAppKey.isNotEmpty() && config.embedModelPath.isNotEmpty() && config.modelPath.isNotEmpty()) { SystemSleepPreventer.wakeDisplay() // 모니터 켜기 statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."