This commit is contained in:
lunaticbum 2026-06-02 14:40:33 +09:00
parent 9d43c04670
commit ada0d9d6fe
3 changed files with 16 additions and 21 deletions

View File

@ -242,7 +242,7 @@ object DatabaseFactory {
fun findAllMonitoringTrades(): List<AutoTradeItem> { fun findAllMonitoringTrades(): List<AutoTradeItem> {
return transaction(mainDb) { return transaction(mainDb) {
AutoTradeTable.select { AutoTradeTable.select {
AutoTradeTable.status neq "COMPLETED" AutoTradeTable.status notInList listOf(TradeStatus.COMPLETED, TradeStatus.EXPIRED)
}.map { mapToAutoTradeItem(it) } }.map { mapToAutoTradeItem(it) }
} }
} }

View File

@ -654,7 +654,7 @@ object KisTradeService {
pageCount++ pageCount++
trCont = "N" trCont = "N"
println("⏳ [연속 조회] 250ms 대기 후 다음 페이지 요청...") println("⏳ [연속 조회] 250ms 대기 후 다음 페이지 요청...")
delay(350) // API 과부하 방지 delay(400) // API 과부하 방지
} }
} while (trCont == "N") } while (trCont == "N")

View File

@ -1,7 +1,6 @@
package service package service
import AutoTradeItem import AutoTradeItem
import Defines.AUTOSELL
import Defines.BLACKLISTEDSTOCKCODES import Defines.BLACKLISTEDSTOCKCODES
import Defines.EMBEDDING_PORT import Defines.EMBEDDING_PORT
import Defines.LLM_PORT import Defines.LLM_PORT
@ -40,7 +39,6 @@ import network.KisWebSocketManager
import network.RagService import network.RagService
import network.RagService.isSafetyBeltStockCodes import network.RagService.isSafetyBeltStockCodes
import network.StockUniverseLoader import network.StockUniverseLoader
import report.SnapshotType
import report.TradingReportManager import report.TradingReportManager
import util.MarketUtil import util.MarketUtil
import java.time.LocalDate import java.time.LocalDate
@ -771,8 +769,9 @@ object AutoTradingManager {
} }
withTimeout(CYCLE_TIMEOUT) { withTimeout(CYCLE_TIMEOUT) {
println("⏱️ [Cycle Start] ${LocalTime.now()}") println("⏱️ [Cycle Start] ${LocalTime.now()}")
if (now.isAfter(KisSession.endTime())) { val activeTrades = DatabaseFactory.findAllMonitoringTrades()
executeClosingLiquidation(KisTradeService) if (now.isAfter(LocalTime.of(15, 30)) && activeTrades.isNotEmpty()) {
executeClosingLiquidation(activeTrades)
} else { } else {
executeMarketLoop() executeMarketLoop()
} }
@ -818,7 +817,7 @@ object AutoTradingManager {
} }
} }
var loadedTops = mutableListOf<Pair<String, String>>() var loadedTops = mutableListOf<Pair<String, String>>()
var defaultStockCount = 200 var defaultStockCount = 150
fun poll100Stocks(): List<Pair<String, String>> { fun poll100Stocks(): List<Pair<String, String>> {
loadedTops.shuffle() loadedTops.shuffle()
val count = minOf(loadedTops.size, defaultStockCount) val count = minOf(loadedTops.size, defaultStockCount)
@ -946,9 +945,13 @@ object AutoTradingManager {
if( if(
it.quantity.toInt() > KisSession.tradeConfig.lowerAverageTargetCount && it.quantity.toInt() > KisSession.tradeConfig.lowerAverageTargetCount &&
it.profitRate.toDouble() < (KisSession.tradeConfig.lowerAverageMaxRate * -1) && it.profitRate.toDouble() < (KisSession.tradeConfig.lowerAverageMaxRate * -1) &&
it.profitRate.toDouble() > (KisSession.tradeConfig.lowerAverageMinRate * -1) ) it.profitRate.toDouble() > (KisSession.tradeConfig.lowerAverageMinRate * -1) &&
it.code !in pendingStocks &&
it.code !in executionCache.values.map { it.code } &&
it.code !in failList &&
it.code !in isSafetyBeltStockCodes)
{ {
candidates.add(RankingStock(mksc_shrn_iscd = it.code, hts_kor_isnm = it.name)) remainingCandidates.add(RankingStock(mksc_shrn_iscd = it.code, hts_kor_isnm = it.name))
} }
} }
} }
@ -982,7 +985,7 @@ object AutoTradingManager {
iterator.remove() iterator.remove()
} }
println("남은 후보군 개수 : ${totalCount}") println("남은 후보군 개수 : ${totalCount}")
delay(100) delay(500)
} }
} }
sellSchedule() sellSchedule()
@ -1089,7 +1092,7 @@ object AutoTradingManager {
val currentPrice = today.stck_prpr.toDouble() val currentPrice = today.stck_prpr.toDouble()
if ((myCash > 10L && currentPrice > myCash) || currentPrice > maxBudget || currentPrice > maxPrice || currentPrice < minPrice) { if ((myCash > 10L && currentPrice > myCash) || currentPrice > maxBudget || currentPrice > maxPrice || currentPrice < minPrice) {
print("-> 가격 정책으로 제외 [1주:${currentPrice}, 자산:${myCash}, 최소 기준:${minPrice}, 최대 기준:${maxPrice}] | ") print("-> [${stock.name}] 가격 정책으로 제외 [1주:${currentPrice}, 자산:${myCash}, 최소 기준:${minPrice}, 최대 기준:${maxPrice}] | ")
return@withTimeout return@withTimeout
} }
@ -1174,18 +1177,10 @@ object AutoTradingManager {
} }
private suspend fun executeClosingLiquidation(tradeService: KisTradeService) { private suspend fun executeClosingLiquidation(activeTrades: List<AutoTradeItem>) {
val activeTrades = DatabaseFactory.findAllMonitoringTrades()
val balanceResult = tradeService.fetchIntegratedBalance().getOrNull()
val realHoldings = balanceResult?.getHoldings()?.associateBy { it.code } ?: emptyMap()
activeTrades.forEach { trade -> activeTrades.forEach { trade ->
try { try {
if (!realHoldings.containsKey(trade.code)) { DatabaseFactory.updateStatusAndOrderNo(trade.id!!, TradeStatus.EXPIRED)
DatabaseFactory.updateStatusAndOrderNo(trade.id!!, TradeStatus.EXPIRED)
return@forEach
}
// 마감 정리 로직 (필요 시 주석 해제하여 사용)
println("📢 [마감 정리 체크] ${trade.name}") println("📢 [마감 정리 체크] ${trade.name}")
} catch (e: Exception) { } catch (e: Exception) {
println("⚠️ [마감 에러] ${trade.name}: ${e.message}") println("⚠️ [마감 에러] ${trade.name}: ${e.message}")