...
This commit is contained in:
@@ -32,6 +32,7 @@ import network.FinancialStatement
|
||||
import network.KisAuthService
|
||||
import network.KisTradeService
|
||||
import network.KisWebSocketManager
|
||||
import network.StockUniverseLoader
|
||||
import util.MarketUtil
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
@@ -51,10 +52,10 @@ object AutoTradingManager {
|
||||
private val lastTickTime = AtomicLong(System.currentTimeMillis())
|
||||
private var watchdogJob: Job? = null
|
||||
|
||||
private const val CYCLE_TIMEOUT = 30 * 60 * 1000L // 한 사이클 최대 10분
|
||||
private const val CYCLE_TIMEOUT = 15 * 60 * 1000L // 한 사이클 최대 10분
|
||||
private const val WATCHDOG_CHECK_INTERVAL = 30 * 1000L // 30초마다 생존 확인
|
||||
private const val STUCK_THRESHOLD = 3 * 60 * 1000L // 5분간 반응 없으면 'Stuck'으로 판단
|
||||
private const val ONE_STOCK_ALYSIS_TIME = 90000L
|
||||
private const val STUCK_THRESHOLD = 7 * 60 * 1000L // 5분간 반응 없으면 'Stuck'으로 판단
|
||||
private const val ONE_STOCK_ALYSIS_TIME = 180000L
|
||||
fun isRunning(): Boolean = discoveryJob?.isActive == true
|
||||
private var remainingCandidates = mutableListOf<RankingStock>()
|
||||
// private val processedCodes = mutableSetOf<String>() // 중복 처리 방지용 (선택 사항)
|
||||
@@ -122,7 +123,7 @@ object AutoTradingManager {
|
||||
|
||||
} else if(totalScore >= (minScore * 0.85) && completeTradingDecision.confidence + append >= (MIN_CONFIDENCE * 0.85)) {
|
||||
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어 또는 신뢰도 미달 이나 약간의 오차로 재분석 대기열에 추가")
|
||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어[$totalScore] 또는 신뢰도[${completeTradingDecision.confidence}] 미달 이나 약간의 오차로 재분석 대기열에 추가")
|
||||
} else {
|
||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어(${String.format("%.1f[${minScore}]", totalScore)}) 또는 신뢰도 (${String.format("%.1f[${MIN_CONFIDENCE}]", completeTradingDecision.confidence)}) 미달")
|
||||
}
|
||||
@@ -432,12 +433,15 @@ object AutoTradingManager {
|
||||
val balance = tradeService.fetchIntegratedBalance().getOrNull()
|
||||
balance?.let { resumePendingSellOrders(tradeService, it) }
|
||||
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
||||
val myHoldings =
|
||||
balance?.holdings?.filter { it.quantity.toInt() > 0 }?.map { it.code }?.toSet()
|
||||
?: emptySet()
|
||||
val myHoldings = balance?.holdings?.filter { it.quantity.toInt() > 0 }?.map { it.code }?.toSet() ?: emptySet()
|
||||
val pendingStocks = DatabaseFactory.findAllMonitoringTrades().map { it.code }
|
||||
// [프로세스 2] 후보군 수집
|
||||
if (remainingCandidates.isEmpty()) {
|
||||
val stocks = StockUniverseLoader.loadUniverse()
|
||||
println("✅ 총 ${stocks.size}개의 종목을 로드했습니다.")
|
||||
stocks.forEach { (code, name) ->
|
||||
// println("📌 로드됨: [$code] $name")
|
||||
addToReanalysis(RankingStock(mksc_shrn_iscd = code, hts_kor_isnm = name))
|
||||
}
|
||||
val candidates: MutableList<RankingStock> = fetchCandidates(tradeService).apply {
|
||||
println("후보군 총 개수 : $size")
|
||||
}.filter {
|
||||
@@ -458,12 +462,14 @@ object AutoTradingManager {
|
||||
candidates.addAll(reanalysisList.asReversed())
|
||||
}
|
||||
reanalysisList.clear()
|
||||
remainingCandidates.addAll(candidates.filter { it.code !in myHoldings && it.code !in pendingStocks }
|
||||
.distinctBy { it.code })
|
||||
remainingCandidates.addAll(candidates.filter { it.code !in myHoldings && it.code !in pendingStocks && it.code !in executionCache.values.map { it.code } && it.code !in failList}
|
||||
.distinctBy { it.code }.shuffled())
|
||||
} else {
|
||||
println("미확인 데이터 ${remainingCandidates.size}")
|
||||
// remainingCandidates.removeIf { it.code in myHoldings || it.code in pendingStocks || it.code in executionCache.values.map { it.code } || it.code in failList}
|
||||
}
|
||||
|
||||
|
||||
var totalCount = remainingCandidates.size
|
||||
println("후보군 조건 충족 총 개수 : ${totalCount}")
|
||||
val iterator = remainingCandidates.iterator()
|
||||
@@ -553,10 +559,10 @@ object AutoTradingManager {
|
||||
if (count < 10) { // 최대 2회까지만 재시도하여 무한 루프 방지
|
||||
retryCountMap[stock.code] = count + 1
|
||||
reanalysisList.add(stock)
|
||||
println("📝 [Memory] ${stock.name} 관망 판정 -> 차기 루프 재분석 리스트 등록")
|
||||
// println("📝 [Memory] ${stock.name} 관망 판정 -> 차기 루프 재분석 리스트 등록")
|
||||
}
|
||||
}
|
||||
|
||||
val failList = arrayListOf<String>()
|
||||
private suspend fun processSingleStock(stock: RankingStock, myCash: Long, tradeService: KisTradeService, callback: TradingDecisionCallback) {
|
||||
try {
|
||||
val maxBudget = KisSession.config.getValues(ConfigIndex.MAX_BUDGET_INDEX)
|
||||
@@ -578,6 +584,7 @@ object AutoTradingManager {
|
||||
val dailyData = tradeService.fetchPeriodChartData(stock.code, "D", true).getOrNull() ?: return@withTimeout
|
||||
val today = dailyData.lastOrNull() ?: null
|
||||
if (today == null) {
|
||||
failList.add(stock.code)
|
||||
print("-> 금일 금액 조회 실패 | ")
|
||||
return@withTimeout
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user