...
This commit is contained in:
@@ -353,7 +353,7 @@ class TechnicalAnalyzer {
|
|||||||
|
|
||||||
// 🌟 3. 3개 중 2개 이상 만족 시 반등 임박(Approaching)으로 판단
|
// 🌟 3. 3개 중 2개 이상 만족 시 반등 임박(Approaching)으로 판단
|
||||||
val passedConditions = listOf(isPriceDropped, isPastMinTime, isWithinMaxTime).count { it }
|
val passedConditions = listOf(isPriceDropped, isPastMinTime, isWithinMaxTime).count { it }
|
||||||
|
//A. 진입 하락률 기준checkReboundApproaching 3개 중 2개 만족 시 통과 가격 하락 조건(isPriceDropped)을 필수 조건(AND)으로 고정
|
||||||
return passedConditions >= 2
|
return passedConditions >= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,7 +670,8 @@ $standardizedScores
|
|||||||
val remainingDropRate = reboundStats.avgDropRate - currentDropRate
|
val remainingDropRate = reboundStats.avgDropRate - currentDropRate
|
||||||
|
|
||||||
// 바닥권 인정 마진 (ATR 기반)
|
// 바닥권 인정 마진 (ATR 기반)
|
||||||
val bottomMargin = currentAtr * 0.7
|
//B. 바닥권 판정 마진predictDropBottom currentAtr * 0.7 여유 마진 마진을 축소(currentAtr * 0.3)하여 예상 바닥에 더 근접해야 인정
|
||||||
|
val bottomMargin = currentAtr * 0.5
|
||||||
|
|
||||||
// 저점 평균(smoothedBottom)도 마지노선 계산에 추가 가중치로 섞어줌으로써 저점에 더 밀착시킴
|
// 저점 평균(smoothedBottom)도 마지노선 계산에 추가 가중치로 섞어줌으로써 저점에 더 밀착시킴
|
||||||
val adjustedExtremeLow = (volatility.extremeLow + smoothedBottom) / 2.0
|
val adjustedExtremeLow = (volatility.extremeLow + smoothedBottom) / 2.0
|
||||||
|
|||||||
@@ -360,4 +360,9 @@ object KisSession {
|
|||||||
fun isAvailBuyTime(now: LocalTime) : Boolean {
|
fun isAvailBuyTime(now: LocalTime) : Boolean {
|
||||||
return now.isBefore(endBuyTime()) && now.isAfter(startBuyTime())
|
return now.isBefore(endBuyTime()) && now.isAfter(startBuyTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isMarketOpenTime(now: LocalTime) : Boolean {
|
||||||
|
return now.isBefore(LocalTime.of(15,30)) && now.isAfter(LocalTime.of(9,0))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -242,7 +242,7 @@ object AutoTradingManager {
|
|||||||
TradingLogStore.addNotice("SYSTEM", "LIMIT", "최대 보유 종목 도달로 신규 매수 일시 중단")
|
TradingLogStore.addNotice("SYSTEM", "LIMIT", "최대 보유 종목 도달로 신규 매수 일시 중단")
|
||||||
addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
addToReanalysis(RankingStock(mksc_shrn_iscd = stockCode,hts_kor_isnm = stockName))
|
||||||
TradingLogStore.addWatchLog(decision,"WATCH","매수 실패 : 최대 보유 종목 도달로 신규 매수 일시 중단 => 재분석 대기열에 추가")
|
TradingLogStore.addWatchLog(decision,"WATCH","매수 실패 : 최대 보유 종목 도달로 신규 매수 일시 중단 => 재분석 대기열에 추가")
|
||||||
} else if (KisSession.isAvailBuyTime(LocalTime.now())){
|
} else if (KisSession.isAvailBuyTime(LocalTime.now()) || hasCode){
|
||||||
println("basePrice : $basePrice, oneTickLowerPrice : $oneTickLowerPrice, finalPrice : $finalPrice hasStocks : ${stockCode.contains(stockCode)}" )
|
println("basePrice : $basePrice, oneTickLowerPrice : $oneTickLowerPrice, finalPrice : $finalPrice hasStocks : ${stockCode.contains(stockCode)}" )
|
||||||
var realOrderQty = orderQty
|
var realOrderQty = orderQty
|
||||||
KisTradeService.postOrder(stockCode, realOrderQty, finalPrice.toLong().toString(), isBuy = true)
|
KisTradeService.postOrder(stockCode, realOrderQty, finalPrice.toLong().toString(), isBuy = true)
|
||||||
@@ -1028,7 +1028,7 @@ object AutoTradingManager {
|
|||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
totalCount--
|
totalCount--
|
||||||
val stock = iterator.next()
|
val stock = iterator.next()
|
||||||
if (KisSession.isAvailBuyTime(now)) {
|
if (KisSession.isMarketOpenTime(now)) {
|
||||||
if (BLACKLISTEDSTOCKCODES.contains(stock.code)) {
|
if (BLACKLISTEDSTOCKCODES.contains(stock.code)) {
|
||||||
println("❌ 차단 처리된 주식 : ${stock.name}")
|
println("❌ 차단 처리된 주식 : ${stock.name}")
|
||||||
} else {
|
} else {
|
||||||
@@ -1181,8 +1181,8 @@ object AutoTradingManager {
|
|||||||
val tempAnalyzer = TechnicalAnalyzer().apply { this.daily = dailyData }
|
val tempAnalyzer = TechnicalAnalyzer().apply { this.daily = dailyData }
|
||||||
|
|
||||||
// 1. 변동성 기반 수익률 검증 (2% 이상 열려있는가?)
|
// 1. 변동성 기반 수익률 검증 (2% 이상 열려있는가?)
|
||||||
println("(dailyData.size * 0.8).toInt() ${(dailyData.size * 0.8).toInt()}")
|
println("(dailyData.size * 0.8).toInt() ${(dailyData.size * 0.3).toInt()}")
|
||||||
val volatility = tempAnalyzer.calculateVolatilityForecast(dailyData, (dailyData.size * 0.8).toInt())
|
val volatility = tempAnalyzer.calculateVolatilityForecast(dailyData, 20)
|
||||||
val expectedProfitRate = ((volatility.realisticHigh - currentPrice) / currentPrice) * 100.0
|
val expectedProfitRate = ((volatility.realisticHigh - currentPrice) / currentPrice) * 100.0
|
||||||
|
|
||||||
// 2. 일봉 기준 반등 주기 통계 추출 (일주일 내 승부 가능한가?)
|
// 2. 일봉 기준 반등 주기 통계 추출 (일주일 내 승부 가능한가?)
|
||||||
@@ -1212,7 +1212,7 @@ object AutoTradingManager {
|
|||||||
|
|
||||||
if (dropPrediction != null) {
|
if (dropPrediction != null) {
|
||||||
// 💡 [방어 로직 1] 아직 바닥까지 한참 남았다면 지하실 방지
|
// 💡 [방어 로직 1] 아직 바닥까지 한참 남았다면 지하실 방지
|
||||||
if (dropPrediction.remainingDropRate < -2.0 && !dropPrediction.isBottomZone) {
|
if (dropPrediction.remainingDropRate < -1.0 && !dropPrediction.isBottomZone) {
|
||||||
print("-> [${stock.name}] 지하실 주의 (현재 ${"%.1f".format(dropPrediction.currentDropRate)}% 하락, 추가 하락 위험) | ")
|
print("-> [${stock.name}] 지하실 주의 (현재 ${"%.1f".format(dropPrediction.currentDropRate)}% 하락, 추가 하락 위험) | ")
|
||||||
return@withTimeout
|
return@withTimeout
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user