atrade/src/main/kotlin/analyzer/FinancialAnalyzer.kt
2026-04-08 14:18:09 +09:00

115 lines
5.7 KiB
Kotlin

package analyzer
import kotlin.compareTo
object FinancialAnalyzer {
/**
* [매수 고려] 우량 기업 요건 확인
* 모든 조건 충족 시 적극적인 분석(AI/차트) 단계로 진입합니다.
*/
fun isSafetyBeltMet(fs: FinancialStatement): Boolean {
// 1. 유동성 위기 체크 (이건 유지하는 것이 좋습니다)
val isDebtSafe = fs.debtRatio < 300.0 // 200% -> 300%로 완화
val isLiquiditySafe = fs.quickRatio > 60.0 // 80% -> 60%로 완화 (급전이 필요한 수준만 차단)
// 2. 턴어라운드 허용 (적자여도 개선 중이면 통과)
val isTurningAround = !fs.isNetIncomePositive && fs.operatingProfitGrowth > 50.0
val isNotFatalDeficit = fs.isNetIncomePositive || isTurningAround
// 3. 상장폐지 요건 중심 필터
val isNotCapitalImpaired = fs.capitalImpairmentRate < 50.0 // 자본잠식 50% 이상 차단
val isNotLossExploding = fs.lossToSalesRatio < 150.0 // 매출보다 손실이 너무 크면 차단
// 최종: 정말 위험한 경우가 아니면 분석 단계(AI/뉴스)로 보냄
return isDebtSafe && isLiquiditySafe && isNotFatalDeficit && isNotCapitalImpaired
}
fun toString(fs : FinancialStatement): String {
var buffer = StringBuffer()
val isDebtSafe = fs.debtRatio < 200.0 // 부채비율 200% 미만
val isLiquiditySafe = fs.quickRatio > 80.0 // 당좌비율 80% 이상
val isNotDeficit = fs.isNetIncomePositive // 당기순이익은 일단 흑자여야 함
val isNotCrashing = fs.netIncomeGrowth > -40.0
if ((isDebtSafe && isLiquiditySafe && isNotDeficit) == false) {
if (!isDebtSafe)buffer.appendLine( "부채비율 200% 이상")
if (!isLiquiditySafe)buffer.appendLine( "당좌비율 80% 미만")
if (!isNotDeficit)buffer.appendLine( "당기순이익 적자")
if (!isNotCrashing) { buffer.appendLine("당기순이익 급감(${String.format("%.1f", fs.netIncomeGrowth)}%)") }
buffer.appendLine("최소 기준 미달")
} else {
buffer.appendLine("최소 기준 충족")
}
val highProfitability = fs.roe >= 10.0 // ROE 10% 이상
val strongGrowth = fs.netIncomeGrowth >= 15.0 // 이익 성장률 15% 이상
val verySafeDebt = fs.debtRatio <= 100.0 // 부채비율 100% 이하 (안전)
val goodLiquidity = fs.quickRatio >= 120.0 // 당좌비율 120% 이상 (여유)
val businessHealthy = fs.isOperatingProfitPositive // 본업(영업이익)이 흑자
if ((highProfitability && strongGrowth && verySafeDebt && goodLiquidity && businessHealthy) == false) {
if(!highProfitability) buffer.appendLine( "ROE 10% 미만")
if(!strongGrowth) buffer.appendLine( "이익 성장률 15% 미만")
if(!verySafeDebt) buffer.appendLine( "부채비율 100% 이상 (안전성 미달)")
if(!goodLiquidity) buffer.appendLine( "당좌비율 120% 이하 (여유 없음)")
if(!businessHealthy) buffer.appendLine( "본업(영업이익)이 적자")
buffer.appendLine("재무 건전성 및 성장성 미달")
} else {
buffer.appendLine("재무 건전성 및 성장성 충족")
}
return buffer.toString()
}
fun isBuyConsiderationMet(fs: FinancialStatement): Boolean {
val highProfitability = fs.roe >= 10.0 // ROE 10% 이상
val strongGrowth = fs.netIncomeGrowth >= 15.0 // 이익 성장률 15% 이상
val verySafeDebt = fs.debtRatio <= 100.0 // 부채비율 100% 이하 (안전)
val goodLiquidity = fs.quickRatio >= 120.0 // 당좌비율 120% 이상 (여유)
val businessHealthy = fs.isOperatingProfitPositive // 본업(영업이익)이 흑자
return highProfitability && strongGrowth && verySafeDebt && goodLiquidity && businessHealthy
}
fun calculateScore(fs: FinancialStatement): Int {
var score = 50.0 // 중립 시작
// 1. 수익성 및 성장 추세 (Max 50)
score += when {
fs.isOperatingProfitPositive && fs.operatingProfitGrowth > 20.0 -> 30.0 // 우량 성장
fs.isOperatingProfitPositive && fs.operatingProfitGrowth < -30.0 -> -20.0 // 쇠퇴 위험
!fs.isOperatingProfitPositive && fs.operatingProfitGrowth > 50.0 -> 20.0 // 턴어라운드 신호
!fs.isOperatingProfitPositive && fs.operatingProfitGrowth < -20.0 -> -30.0 // 적자 심화
else -> 0.0
}
// 2. 수익 효율 ROE (Max 30)
score += (fs.roe.coerceIn(-20.0, 20.0) * 1.5)
// 3. 안정성 (Max 20)
if (fs.debtRatio <= 100.0) score += 20.0
else if (fs.debtRatio <= 150.0) score += 10.0
// 4. 감점 페널티 (위험 징후 시 최대 -50)
if (fs.capitalImpairmentRate > 20.0) score -= 30.0
if (fs.debtAccelerationRate > 100.0) score -= 20.0
return score.coerceIn(0.0, 100.0).toInt()
}
/**
* 상황별 상태 메시지 정교화
*/
fun getInvestmentStatus(fs: FinancialStatement): String {
return when {
fs.isOperatingProfitPositive && fs.operatingProfitGrowth > 10.0 -> "🚀 [성장중] 실적 개선세 뚜렷"
!fs.isOperatingProfitPositive && fs.operatingProfitGrowth > 40.0 -> "☀️ [회복중] 적자폭 급감, 턴어라운드 가시화"
fs.isOperatingProfitPositive && fs.operatingProfitGrowth < -40.0 -> "⚠️ [쇠퇴중] 이익 급감, 적자전환 유의"
else -> "🚨 [부실] 재무 구조 악화 지속"
}
}
}