...
This commit is contained in:
@@ -852,8 +852,8 @@ object FinancialAnalyzer {
|
||||
val isDebtSafe = fs.debtRatio < 200.0 // 부채비율 200% 미만
|
||||
val isLiquiditySafe = fs.quickRatio > 80.0 // 당좌비율 80% 이상
|
||||
val isNotDeficit = fs.isNetIncomePositive // 당기순이익은 일단 흑자여야 함
|
||||
|
||||
return isDebtSafe && isLiquiditySafe && isNotDeficit
|
||||
val isNotCrashing = fs.netIncomeGrowth > -40.0
|
||||
return isDebtSafe && isLiquiditySafe && isNotDeficit && isNotCrashing
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -876,10 +876,12 @@ object FinancialAnalyzer {
|
||||
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 (!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("최소 기준 충족")
|
||||
@@ -1009,23 +1011,47 @@ class TechnicalAnalyzer {
|
||||
): InvestmentScores {
|
||||
|
||||
// 1. 초단기 (분봉 + 에너지 지표 위주)
|
||||
val ultra = (calculateMFI(min30, 14) * 0.4 +
|
||||
var ultra = (calculateMFI(min30, 14) * 0.4 +
|
||||
calculateStochastic(min30) * 0.3 +
|
||||
(if(calculateChange(min30.takeLast(10)) > 0) 30 else 0)).toInt()
|
||||
|
||||
// 2. 단기 (일봉 추세 + OBV 에너지)
|
||||
val short = (calculateRSI(daily) * 0.3 +
|
||||
var short = (calculateRSI(daily) * 0.3 +
|
||||
(if(calculateOBV(daily) > 0) 40 else 10) +
|
||||
(if(calculateChange(daily.takeLast(3)) > 0) 30 else 0)).toInt()
|
||||
|
||||
// 3. 중기 (주봉 + 재무 점수 혼합)
|
||||
val mid = (if(calculateChange(weekly) > 0) 40 else 10) +
|
||||
var mid = (if(calculateChange(weekly) > 0) 40 else 10) +
|
||||
(financialScore * 0.6).toInt()
|
||||
|
||||
// 4. 장기 (월봉 + 섹터/기업 펀더멘털)
|
||||
val long = (if(calculateChange(monthly) > 0) 50 else 0) +
|
||||
var long = (if(calculateChange(monthly) > 0) 50 else 0) +
|
||||
(financialScore * 0.5).toInt()
|
||||
|
||||
// 1. 일봉 이격도 과열 체크 (20일 이평선 기준)
|
||||
if (daily.size >= 20) {
|
||||
val ma20Daily = daily.takeLast(20).map { it.stck_prpr.toDouble() }.average()
|
||||
val currentPrice = daily.last().stck_prpr.toDouble()
|
||||
val disparityDaily = (currentPrice / ma20Daily) * 100
|
||||
|
||||
if (disparityDaily > 115.0) { // 20일선보다 15% 이상 떠 있으면 감점 시작
|
||||
val penalty = ((disparityDaily - 115.0) * 1).toInt() // 초과분 1%당 2점 감점
|
||||
short -= penalty
|
||||
ultra -= (penalty / 2) // 초단기에도 영향
|
||||
println("⚠️ [과열 감점] 일봉 이격도(${String.format("%.1f", disparityDaily)}%): -${penalty}점")
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 주봉 급등 체크 (최근 3주간의 상승폭)
|
||||
if (weekly.size >= 3) {
|
||||
val weeklyChange = calculateChange(weekly.takeLast(3))
|
||||
if (weeklyChange > 30.0) { // 3주간 30% 이상 급등 시
|
||||
mid -= 15
|
||||
short -= 7
|
||||
println("⚠️ [과열 감점] 주봉 급등(${String.format("%.1f", weeklyChange)}%): -15점")
|
||||
}
|
||||
}
|
||||
|
||||
return InvestmentScores(
|
||||
ultraShort = ultra.coerceIn(0, 100),
|
||||
shortTerm = short.coerceIn(0, 100),
|
||||
@@ -1296,8 +1322,15 @@ class ScalpingAnalyzer {
|
||||
val volSurge = volRatioNow > VOL_SURGE_THRESHOLD
|
||||
val bbGood = bbPos > BB_LOWER_POS && bbPos < BB_UPPER_POS
|
||||
val maBull = currentClose > sma10Now && sma10Now > sma20Now
|
||||
val buySignal = maBull && rsiBull && volSurge && bbGood && isBreakout
|
||||
// val buySignal = maBull && rsiBull && volSurge && bbGood
|
||||
// val buySignal = maBull && rsiBull && volSurge && bbGood && isBreakout
|
||||
val ma5Daily = if (candles.size >= 5) candles.takeLast(5).map { it.close.toDouble() }.average() else currentClose
|
||||
val dailyDisparity = (currentClose / ma5Daily) * 100
|
||||
|
||||
// 과열 기준 정의
|
||||
val isOverheated = dailyDisparity > 110.0 // 일봉 5일선 대비 10% 이상 이격 시 과열로 간주
|
||||
|
||||
// 매수 신호 조건에 과열 방지 추가
|
||||
val buySignal = maBull && rsiBull && volSurge && bbGood && isBreakout && !isOverheated
|
||||
|
||||
|
||||
val score = (if (maBull) 25 else 0) +
|
||||
|
||||
Reference in New Issue
Block a user