...
This commit is contained in:
@@ -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표준편차 하단 (현실적 지지선)
|
||||
|
||||
Reference in New Issue
Block a user