diff --git a/src/main/kotlin/model/AppConfig.kt b/src/main/kotlin/model/AppConfig.kt index 4b18125..c8497fa 100644 --- a/src/main/kotlin/model/AppConfig.kt +++ b/src/main/kotlin/model/AppConfig.kt @@ -264,6 +264,9 @@ class TradeConfig { var autoSellOrderMin : Double = -15.0 var autoSellOrderMax : Double = -29.0 var autoSellOrderAppend : Int = 3 + var minExpectedProfitRate: Double = 2.0 // 필터링 기준 최소 기대 수익률 (%) + var maxExpectedReboundDays: Double = 10.0 // 필터링 기준 최대 허용 반등 주기 (일) + var minExpectedReboundDays: Double = 1.5 } diff --git a/src/main/kotlin/service/AutoTradingManager.kt b/src/main/kotlin/service/AutoTradingManager.kt index 952d5f3..cd28f40 100644 --- a/src/main/kotlin/service/AutoTradingManager.kt +++ b/src/main/kotlin/service/AutoTradingManager.kt @@ -1169,19 +1169,20 @@ object AutoTradingManager { ) val isSteadyUptrend = tempAnalyzer.checkSteadyUptrend(dailyData) + // 🌟 [수정] 조건 통합 (OR 조건) - val isProfitable = expectedProfitRate >= 2.0 || dailyStats.avgReboundAmplitude >= 2.0 + val isProfitable = expectedProfitRate >= KisSession.tradeConfig.minExpectedProfitRate || dailyStats.avgReboundAmplitude >= KisSession.tradeConfig.minExpectedProfitRate // 반등 주기에 도달했거나(Mean Reversion), 안정적으로 뻗어나가는 우상향 종목(Trend Following)이면 통과 - val isValidEntryTiming = (dailyStats.isValid && isApproaching && dailyStats.avgReboundPeriod <= 10.0 && dailyStats.avgReboundPeriod >= 1.5) || isSteadyUptrend + val isValidEntryTiming = (dailyStats.isValid && isApproaching && dailyStats.avgReboundPeriod <= KisSession.tradeConfig.maxExpectedReboundDays && dailyStats.avgReboundPeriod >= KisSession.tradeConfig.minExpectedReboundDays) || isSteadyUptrend if (!isProfitable || !isValidEntryTiming) { - print("-> [${stock.name}] 조건 미달 필터링 (예측수익: ${"%.1f".format(expectedProfitRate)}%, 주기: ${"%.1f".format(dailyStats.avgReboundPeriod)}일, 진입권: $isApproaching) | ") + print("-> [${stock.name}] 조건 미달 필터링 (예측수익: ${"%.1f".format(expectedProfitRate)}%, 주기: ${"%.1f".format(dailyStats.avgReboundPeriod)}일, 진입권: $isValidEntryTiming) | ") return@withTimeout // 조건에 맞지 않으면 주봉/월봉 API 호출 및 LLM 분석 없이 즉시 다음 종목으로 넘어감 } - println("🔍 [분석 진입] ${stock.name} (${LocalTime.now()})") + println("🔍 [분석 진입] ${stock.name} (${LocalTime.now()}) (예측수익: ${"%.1f".format(expectedProfitRate)}%, 주기: ${"%.1f".format(dailyStats.avgReboundPeriod)}일, 진입권: $isValidEntryTiming)") if (!isSafetyBeltStockCodes.contains(stock.code)) { val analyzer = coroutineScope { val min30 = async { tradeService.fetchChartData(stock.code, true).getOrDefault(emptyList()) } diff --git a/src/main/kotlin/ui/TradingDecisionLog.kt b/src/main/kotlin/ui/TradingDecisionLog.kt index 90997c7..bb1708a 100644 --- a/src/main/kotlin/ui/TradingDecisionLog.kt +++ b/src/main/kotlin/ui/TradingDecisionLog.kt @@ -681,6 +681,40 @@ fun TradingDecisionLog() { helperText = "위의 수치 만큼 호가 위로 주문함." ) } + + Row(horizontalArrangement = Arrangement.SpaceEvenly) { + SettingInputField( + modifier = Modifier.weight(1.0f, true), + label = "예상 수익율", + initialValue = (tradeConfig.minExpectedProfitRate).toString(), + onSave = { + tradeConfig.minExpectedProfitRate = it.toDouble() + KisSession.saveTradeConfig() + }, + helperText = "현제가 기준 예상 수익율이 더커야 삼" + ) + SettingInputField( + modifier = Modifier.weight(1.0f, true), + label = "예상 매도 기준일", + initialValue = (tradeConfig.maxExpectedReboundDays).toString(), + onSave = { + tradeConfig.maxExpectedReboundDays = it.toDouble() + KisSession.saveTradeConfig() + }, + helperText = "이정도 일수 전에는 팔릴거라 예상" + ) + SettingInputField( + modifier = Modifier.weight(1.0f, true), + label = "주식 널뛰기 기준(예상 매도 기준일)", + initialValue = (tradeConfig.minExpectedReboundDays).toString(), + onSave = { + tradeConfig.minExpectedReboundDays = it.toDouble() + KisSession.saveTradeConfig() + }, + helperText = "너무 작으면 초단타,널뛰기, 이 보다 커야 분석함" + ) + } + } } }