...
This commit is contained in:
@@ -254,31 +254,61 @@ class TechnicalAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* 억울한 HOLD를 막아주는 유연한 과열 판별 로직
|
||||
* 억울한 HOLD를 막아주는 유연한 과열 판별 로직 (주가 및 변동성 기반 세분화)
|
||||
*/
|
||||
fun isOverheatedStock(): Boolean {
|
||||
if (daily.size < 20) return false
|
||||
val currentPrice = daily.last().stck_prpr.toDouble()
|
||||
|
||||
// 1. 일봉 20일선 이격도
|
||||
// 1. 기본 지표 계산
|
||||
val ma20Daily = daily.takeLast(20).map { it.stck_prpr.toDouble() }.average()
|
||||
val disparityDaily = (currentPrice / ma20Daily) * 100
|
||||
|
||||
// 2. 일봉 RSI (단순 이격도 외의 과열 여부 확인)
|
||||
val rsiDaily = calculateRSI(daily)
|
||||
|
||||
// 3. 초단기(최근 10분) 순간 급등 꼭지 확인 (min30 재활용)
|
||||
// 2. 가격대별(시가총액 및 호가단위 대용) 동적 임계값 세팅
|
||||
val maxDisparity: Double // 절대 진입 금지 (초과열)
|
||||
val warningDisparity: Double // 경고 수준 (보조지표 결합 시 차단)
|
||||
val microPumpThreshold: Double // 10분 내 단기 펌핑 기준
|
||||
|
||||
when {
|
||||
currentPrice >= 50000.0 -> {
|
||||
// [대형주/우량주] 무거워서 20일선 대비 15%만 떠도 역사적 과열
|
||||
maxDisparity = 115.0
|
||||
warningDisparity = 110.0
|
||||
microPumpThreshold = 103.0 // 10분 만에 3% 급등하면 꼭지
|
||||
}
|
||||
currentPrice in 5000.0..49999.0 -> {
|
||||
// [일반 중소형주] 표준적인 변동성
|
||||
maxDisparity = 125.0
|
||||
warningDisparity = 115.0
|
||||
microPumpThreshold = 105.0 // 10분 만에 5% 급등
|
||||
}
|
||||
else -> {
|
||||
// [소형주/동전주] 가벼워서 상한가 한 방에 130% 쉽게 도달
|
||||
maxDisparity = 135.0
|
||||
warningDisparity = 120.0
|
||||
microPumpThreshold = 107.0 // 10분 만에 7% 급등
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 종목 고유 변동성(ATR)을 통한 임계값 미세 보정 (Smart Adjustment)
|
||||
// 평소 하루에 2~3% 움직이는 얌전한 주식이 갑자기 튀면 임계값을 더 빡빡하게 죔
|
||||
val atrPct = (calculateATR(daily) / currentPrice) * 100.0
|
||||
val adjustedMaxDisparity = if (atrPct < 3.0) maxDisparity * 0.96 else maxDisparity
|
||||
val adjustedWarnDisparity = if (atrPct < 3.0) warningDisparity * 0.97 else warningDisparity
|
||||
|
||||
// 4. 초단기(최근 10분) 순간 급등 꼭지 확인 (min30 재활용)
|
||||
var isMicroOverheated = false
|
||||
if (min30.size >= 10) {
|
||||
val ma10Min = min30.takeLast(10).map { it.stck_prpr.toDouble() }.average()
|
||||
val disparityMin = (currentPrice / ma10Min) * 100
|
||||
isMicroOverheated = disparityMin > 105.0 // 10분 평균가 대비 순간적으로 5% 이상 폭등 시
|
||||
isMicroOverheated = disparityMin > microPumpThreshold
|
||||
}
|
||||
|
||||
// 단순히 이격도 115%라고 막는 것이 아니라 3가지 깐깐한 조건 중 하나라도 충족될 때만 과열 판정
|
||||
return disparityDaily > 130.0 || // (A) 역대급 폭등 상태
|
||||
(disparityDaily > 115.0 && rsiDaily > 75.0) || // (B) 급등 중이면서 일봉 과매수
|
||||
(disparityDaily > 115.0 && isMicroOverheated) // (C) 급등 중이면서 10분 내 순간 펌핑(꼭지)
|
||||
// 5. 최종 세분화 판정 로직
|
||||
return disparityDaily > adjustedMaxDisparity || // (A) 종목 체급 대비 역대급 폭등 상태
|
||||
(disparityDaily > adjustedWarnDisparity && rsiDaily > 75.0) || // (B) 체급별 경고 수준 + 일봉 과매수
|
||||
(disparityDaily > adjustedWarnDisparity && isMicroOverheated) // (C) 체급별 경고 수준 + 초단기 펌핑(꼭지)
|
||||
}
|
||||
|
||||
fun calculateScores(financialScore100: Int): InvestmentScores {
|
||||
|
||||
Reference in New Issue
Block a user