...
This commit is contained in:
@@ -254,31 +254,61 @@ class TechnicalAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 억울한 HOLD를 막아주는 유연한 과열 판별 로직
|
* 억울한 HOLD를 막아주는 유연한 과열 판별 로직 (주가 및 변동성 기반 세분화)
|
||||||
*/
|
*/
|
||||||
fun isOverheatedStock(): Boolean {
|
fun isOverheatedStock(): Boolean {
|
||||||
if (daily.size < 20) return false
|
if (daily.size < 20) return false
|
||||||
val currentPrice = daily.last().stck_prpr.toDouble()
|
val currentPrice = daily.last().stck_prpr.toDouble()
|
||||||
|
|
||||||
// 1. 일봉 20일선 이격도
|
// 1. 기본 지표 계산
|
||||||
val ma20Daily = daily.takeLast(20).map { it.stck_prpr.toDouble() }.average()
|
val ma20Daily = daily.takeLast(20).map { it.stck_prpr.toDouble() }.average()
|
||||||
val disparityDaily = (currentPrice / ma20Daily) * 100
|
val disparityDaily = (currentPrice / ma20Daily) * 100
|
||||||
|
|
||||||
// 2. 일봉 RSI (단순 이격도 외의 과열 여부 확인)
|
|
||||||
val rsiDaily = calculateRSI(daily)
|
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
|
var isMicroOverheated = false
|
||||||
if (min30.size >= 10) {
|
if (min30.size >= 10) {
|
||||||
val ma10Min = min30.takeLast(10).map { it.stck_prpr.toDouble() }.average()
|
val ma10Min = min30.takeLast(10).map { it.stck_prpr.toDouble() }.average()
|
||||||
val disparityMin = (currentPrice / ma10Min) * 100
|
val disparityMin = (currentPrice / ma10Min) * 100
|
||||||
isMicroOverheated = disparityMin > 105.0 // 10분 평균가 대비 순간적으로 5% 이상 폭등 시
|
isMicroOverheated = disparityMin > microPumpThreshold
|
||||||
}
|
}
|
||||||
|
|
||||||
// 단순히 이격도 115%라고 막는 것이 아니라 3가지 깐깐한 조건 중 하나라도 충족될 때만 과열 판정
|
// 5. 최종 세분화 판정 로직
|
||||||
return disparityDaily > 130.0 || // (A) 역대급 폭등 상태
|
return disparityDaily > adjustedMaxDisparity || // (A) 종목 체급 대비 역대급 폭등 상태
|
||||||
(disparityDaily > 115.0 && rsiDaily > 75.0) || // (B) 급등 중이면서 일봉 과매수
|
(disparityDaily > adjustedWarnDisparity && rsiDaily > 75.0) || // (B) 체급별 경고 수준 + 일봉 과매수
|
||||||
(disparityDaily > 115.0 && isMicroOverheated) // (C) 급등 중이면서 10분 내 순간 펌핑(꼭지)
|
(disparityDaily > adjustedWarnDisparity && isMicroOverheated) // (C) 체급별 경고 수준 + 초단기 펌핑(꼭지)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateScores(financialScore100: Int): InvestmentScores {
|
fun calculateScores(financialScore100: Int): InvestmentScores {
|
||||||
|
|||||||
Reference in New Issue
Block a user