This commit is contained in:
2026-06-26 10:17:03 +09:00
parent 81ce9b1539
commit 7474558136
2 changed files with 87 additions and 12 deletions
+61 -1
View File
@@ -480,7 +480,7 @@ $standardizedScores
}
val reboundRate = if (bottomPrice > 0) ((currentClose - bottomPrice) / bottomPrice * 100) else 0.0
if (reboundRate >= 3.0) { // 3% 이상 반등 시 사이클 종료 및 기록
if (reboundRate >= minDropToDetect) { // 3% 이상 반등 시 사이클 종료 및 기록
reboundTerms.add(i - bottomIndex)
dropRates.add(abs((bottomPrice - peakPrice) / peakPrice * 100))
reboundAmplitudes.add(reboundRate) // 🌟 상승폭 기록
@@ -614,7 +614,67 @@ $standardizedScores
return VolatilityForecast(realisticHigh, realisticLow, extremeHigh, extremeLow)
}
/**
* [신규] 종목의 현재 하락 진행 상태와 통계적 예상 바닥(Bottom)을 계산합니다.
*/
fun predictDropBottom(
candles: List<CandleData>,
reboundStats: ReboundStats,
volatility: VolatilityForecast
): DropPrediction? {
// 데이터가 부족하거나, 유의미한 과거 반등 패턴이 없으면 예측 불가
if (candles.size < 20 || !reboundStats.isValid) return null
// 1. 최근 20일 내 단기 고점 파악 (현재 진행 중인 하락 파동의 시작점)
val recentCandles = candles.takeLast(20)
var recentPeakPrice = 0.0
for (i in recentCandles.indices.reversed()) {
val highPrice = recentCandles[i].stck_hgpr.toDouble()
if (highPrice > recentPeakPrice) {
recentPeakPrice = highPrice
}
}
if (recentPeakPrice == 0.0) return null
val currentPrice = candles.last().stck_prpr.toDouble()
// 2. 현재까지의 하락률 계산
val currentDropRate = (recentPeakPrice - currentPrice) / recentPeakPrice * 100.0 // 양수로 표현 (예: 4.5% 하락)
// 3. 1차 예상 바닥가 (과거 평균 하락폭 적용)
// 예: 고점이 10,000원이고 과거 평균 10% 빠졌다면, 예상 바닥은 9,000원
val expectedBottomPrice = recentPeakPrice * (1.0 - (reboundStats.avgDropRate / 100.0))
// 4. 추가 하락 여력 계산 (얼마나 더 빠질 수 있는가?)
val remainingDropRate = reboundStats.avgDropRate - currentDropRate
// 5. 바닥권 진입 판별 (예상 바닥가의 +2% 이내로 들어왔거나, 통계적 마지노선(extremeLow) 근처일 때)
val isBottomZone = currentPrice <= (expectedBottomPrice * 1.02) || currentPrice <= (volatility.extremeLow * 1.02)
return DropPrediction(
recentPeakPrice = recentPeakPrice,
expectedBottomPrice = expectedBottomPrice,
extremeSupportPrice = volatility.extremeLow,
currentDropRate = -currentDropRate, // 음수로 표기 (예: -4.5%)
remainingDropRate = -remainingDropRate, // 음수면 더 빠질 공간이 남았다는 뜻
isBottomZone = isBottomZone
)
}
}
data class DropPrediction(
val recentPeakPrice: Double, // 최근 단기 고점
val expectedBottomPrice: Double, // 과거 평균 하락률(avgDropRate)을 적용한 1차 예상 바닥가
val extremeSupportPrice: Double, // 2표준편차(extremeLow) 기반의 통계적 2차 마지노선
val currentDropRate: Double, // 단기 고점 대비 현재까지 하락한 비율 (%)
val remainingDropRate: Double, // 1차 예상 바닥까지 남은 추가 하락 여력 (%) - 양수면 더 빠질 공간이 있다는 뜻
val isBottomZone: Boolean // 현재 가격이 바닥권(예상 바닥가의 상하 2% 이내)에 진입했는지 여부
)
data class VolatilityForecast(
val realisticHigh: Double, // 1표준편차 상단 (현실적 목표가, 68% 확률 내)
val realisticLow: Double, // 1표준편차 하단 (현실적 지지선)