...
This commit is contained in:
@@ -61,10 +61,10 @@ object AutoTradingManager {
|
||||
private val lastTickTime = AtomicLong(System.currentTimeMillis())
|
||||
private var watchdogJob: Job? = null
|
||||
|
||||
private const val CYCLE_TIMEOUT = 15 * 60 * 1000L // 한 사이클 최대 10분
|
||||
private const val WATCHDOG_CHECK_INTERVAL = 30 * 1000L // 30초마다 생존 확인
|
||||
private const val STUCK_THRESHOLD = 7 * 60 * 1000L // 5분간 반응 없으면 'Stuck'으로 판단
|
||||
private const val ONE_STOCK_ALYSIS_TIME = 180000L
|
||||
var CYCLE_TIMEOUT = KisSession.tradeConfig.CYCLE_TIMEOUT
|
||||
var WATCHDOG_CHECK_INTERVAL = KisSession.tradeConfig.WATCHDOG_CHECK_INTERVAL
|
||||
var STUCK_THRESHOLD = KisSession.tradeConfig.STUCK_THRESHOLD
|
||||
var ONE_STOCK_ALYSIS_TIME = KisSession.tradeConfig.ONE_STOCK_ALYSIS_TIME
|
||||
fun isRunning(): Boolean = discoveryJob?.isActive == true
|
||||
private var remainingCandidates = mutableListOf<RankingStock>()
|
||||
// private val processedCodes = mutableSetOf<String>() // 중복 처리 방지용 (선택 사항)
|
||||
@@ -216,7 +216,7 @@ object AutoTradingManager {
|
||||
println("🚫 [안전 장치 작동] 현재 포지션이 가득 찼습니다. (최대 ${myOredsAndBalanceCodes.size}/${maxStocks}종목). 신규 매수를 일시 중단하고 매도에 집중합니다.")
|
||||
TradingLogStore.addNotice("SYSTEM", "LIMIT", "최대 보유 종목 도달로 신규 매수 일시 중단")
|
||||
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
||||
TradingLogStore.addLog(decision,"WATCH","매수 실패 : 최대 보유 종목 도달로 신규 매수 일시 중단 => 재분석 대기열에 추가")
|
||||
TradingLogStore.addWatchLog(decision,"WATCH","매수 실패 : 최대 보유 종목 도달로 신규 매수 일시 중단 => 재분석 대기열에 추가")
|
||||
} else {
|
||||
println("basePrice : $basePrice, oneTickLowerPrice : $oneTickLowerPrice, finalPrice : $finalPrice")
|
||||
|
||||
@@ -266,7 +266,7 @@ object AutoTradingManager {
|
||||
|
||||
if (it.message?.contains("주문가능금액을 초과") == true) {
|
||||
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
||||
TradingLogStore.addLog(decision,"WATCH","${it.message ?: " 매수 실패"} => 재분석 대기열에 추가")
|
||||
TradingLogStore.addWatchLog(decision,"WATCH","${it.message ?: " 매수 실패"} => 재분석 대기열에 추가")
|
||||
} else {
|
||||
TradingLogStore.addLog(decision,"BUY",it.message ?: "매수 실패")
|
||||
}
|
||||
@@ -559,7 +559,9 @@ object AutoTradingManager {
|
||||
private suspend fun analyzeDeepLossHoldingsAfterMarket(holding: UnifiedStockHolding, isForce : Boolean = false) { // 💡 [신규 추가] 수익률이 크게 마이너스인 종목(-5.0% 이하) 심층 가이드 분석
|
||||
val now = LocalTime.now()
|
||||
val currentMinute = now.minute
|
||||
if ((!isForce && (now.hour == 8 || now.hour == 16 || now.hour == 17)) || (isForce && (currentMinute % 5 == 0))) {
|
||||
if ((holding.availOrderCount.toInt()
|
||||
?: 0) > 0 && ((!isForce && (now.hour == 8 || now.hour == 16 || now.hour == 17)) || (isForce && (currentMinute % 5 == 0)))
|
||||
) {
|
||||
val profit = holding.profitRate.toDouble()
|
||||
val lossThreshold = -5.0 // 가이드를 작동시킬 손실 기준선 (필요시 ConfigIndex 로 빼셔도 좋습니다)
|
||||
if (profit <= lossThreshold) {
|
||||
@@ -762,14 +764,14 @@ object AutoTradingManager {
|
||||
suspend fun checkBalance(isMorning: Boolean = true) {
|
||||
if (isMorning) {
|
||||
currentBalance = KisTradeService.fetchIntegratedBalance().getOrNull()
|
||||
currentBalance?.let { currentBalance ->
|
||||
if (LocalTime.now().isBefore(LocalTime.of(18,1))) {
|
||||
TradingReportManager.recordAssetSnapshot(
|
||||
if (LocalTime.now().isAfter(LocalTime.of(18, 0))
|
||||
) SnapshotType.END else SnapshotType.MIDDLE, currentBalance, ""
|
||||
)
|
||||
}
|
||||
}
|
||||
// currentBalance?.let { currentBalance ->
|
||||
// if (LocalTime.now().isBefore(LocalTime.of(18,1))) {
|
||||
// TradingReportManager.recordAssetSnapshot(
|
||||
// if (LocalTime.now().isAfter(LocalTime.of(18, 0))
|
||||
// ) SnapshotType.END else SnapshotType.MIDDLE, currentBalance, ""
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
if (KisSession.config.take_profit) currentBalance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||
if (KisSession.tradeConfig.auto_cancel_pending_buy) { checkAndCancelPendingBuyOrders() }
|
||||
@@ -801,7 +803,7 @@ object AutoTradingManager {
|
||||
val priceGap = Math.abs(currentPrice - orderedPrice) / orderedPrice
|
||||
println("checkAndCancelPendingBuyOrders order $order ${elapsedMillis / 1000L}초 ${priceGap}% 차이")
|
||||
if (priceGap >= KisSession.tradeConfig.auto_cancel_pending_rate) {
|
||||
TradingLogStore.addNotice(order.prdt_name,order.pdno,"[주문 취소] ${order.prdt_name} (${order.pdno}) - 시간경과 및 가격괴리(${String.format("%.2f", priceGap * 100)}%)로 취소 시도")
|
||||
TradingLogStore.addNotice(order.prdt_name,order.pdno,"[주문 취소] ${order.prdt_name} (${order.pdno}) - 시간경과 및 가격괴리(${String.format("%.2f", priceGap)}%)로 취소 시도")
|
||||
KisTradeService.cancelOrder(
|
||||
order.ord_no, // 원주문번호
|
||||
order.pdno
|
||||
@@ -853,7 +855,7 @@ object AutoTradingManager {
|
||||
}.filter {
|
||||
val rate = it.prdy_ctrt.toDouble()
|
||||
val corpInfo = DartCodeManager.getCorpCode(it.code)
|
||||
val isOk = (rate > 0 && rate < 15) || (rate < 0 && rate > -15)
|
||||
val isOk = (rate > 0 && rate < KisSession.tradeConfig.plusFilter) || (rate < 0 && rate > (KisSession.tradeConfig.minusFilter * -1))
|
||||
if (corpInfo?.cName.isNullOrEmpty()) {
|
||||
false
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user