....
This commit is contained in:
parent
4bf055fa68
commit
da4ab01d5f
@ -5,9 +5,10 @@ import java.time.LocalDateTime
|
|||||||
const val feesAndTaxRate = 0.33
|
const val feesAndTaxRate = 0.33
|
||||||
const val minimumNetProfit = 0.35
|
const val minimumNetProfit = 0.35
|
||||||
const val buyWeight = 2.0
|
const val buyWeight = 2.0
|
||||||
val MAX_BUDGET = 40000.0
|
val MAX_BUDGET = 60000.0
|
||||||
val MAX_PRICE = 20000
|
val MAX_PRICE = 30000
|
||||||
val MIN_PRICE = 1500
|
val MIN_PRICE = 1000
|
||||||
|
val MIN_PURCHASE_SCORE = 65.0
|
||||||
data class AppConfig(
|
data class AppConfig(
|
||||||
// [DB 저장 데이터]
|
// [DB 저장 데이터]
|
||||||
// 실전 3종
|
// 실전 3종
|
||||||
|
|||||||
@ -83,7 +83,6 @@ object KisTradeService {
|
|||||||
val totalAmt = (domRes?.output2?.firstOrNull()?.tot_evlu_amt?.toLongOrNull() ?: 0L) +
|
val totalAmt = (domRes?.output2?.firstOrNull()?.tot_evlu_amt?.toLongOrNull() ?: 0L) +
|
||||||
(ovsRes?.output2?.firstOrNull()?.tot_evlu_amt?.toLongOrNull() ?: 0L)
|
(ovsRes?.output2?.firstOrNull()?.tot_evlu_amt?.toLongOrNull() ?: 0L)
|
||||||
val depositAmt = domRes?.output2?.firstOrNull()?.dnca_tot_amt?.toLongOrNull() ?: 0L
|
val depositAmt = domRes?.output2?.firstOrNull()?.dnca_tot_amt?.toLongOrNull() ?: 0L
|
||||||
println("fetchIntegratedBalance O")
|
|
||||||
Result.success(UnifiedBalance(
|
Result.success(UnifiedBalance(
|
||||||
totalAsset = String.format("%,d", totalAmt),
|
totalAsset = String.format("%,d", totalAmt),
|
||||||
totalProfitRate = domRes?.output2?.firstOrNull()?.evlu_pfls_rt ?: "0.0",
|
totalProfitRate = domRes?.output2?.firstOrNull()?.evlu_pfls_rt ?: "0.0",
|
||||||
|
|||||||
@ -133,8 +133,7 @@ class KisWebSocketManager {
|
|||||||
// AES 복호화 실행
|
// AES 복호화 실행
|
||||||
val decryptedData = AesCrypto.decrypt(parts[3], aesKey, aesIv)
|
val decryptedData = AesCrypto.decrypt(parts[3], aesKey, aesIv)
|
||||||
val dataRows = decryptedData.split("^")
|
val dataRows = decryptedData.split("^")
|
||||||
|
println("🔔 복호화된 체결 통보: ${if (dataRows[4] == "01") {"매도"} else {"매수"}} ${dataRows[8]} ${dataRows[9]}주 ${dataRows[13]} 체결")
|
||||||
println("🔔 복호화된 체결 통보: ${dataRows[8]} ${dataRows[9]}주 ${dataRows[13]} 체결")
|
|
||||||
|
|
||||||
// UI 콜백 호출 (종목코드, 체결량, 체결가, 주문번호, 체결여부)
|
// UI 콜백 호출 (종목코드, 체결량, 체결가, 주문번호, 체결여부)
|
||||||
onExecutionReceived?.invoke(
|
onExecutionReceived?.invoke(
|
||||||
|
|||||||
@ -117,7 +117,7 @@ object RagService {
|
|||||||
embeddingStore.add(embedding, segment)
|
embeddingStore.add(embedding, segment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("🔎 [Lucene] ${chunks.size}개의 청크로 인덱싱 완료")
|
// println("🔎 [Lucene] ${chunks.size}개의 청크로 인덱싱 완료")
|
||||||
}
|
}
|
||||||
|
|
||||||
object JsonSanitizer {
|
object JsonSanitizer {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ object AutoTradingManager {
|
|||||||
|
|
||||||
// 설정 상수
|
// 설정 상수
|
||||||
private const val MIN_RISE_RATE = 0.1
|
private const val MIN_RISE_RATE = 0.1
|
||||||
private const val MAX_RISE_RATE = 15.0
|
private const val MAX_RISE_RATE = 19.0
|
||||||
private const val CYCLE_TIMEOUT = 30 * 60 * 1000L // 한 사이클 최대 10분
|
private const val CYCLE_TIMEOUT = 30 * 60 * 1000L // 한 사이클 최대 10분
|
||||||
private const val WATCHDOG_CHECK_INTERVAL = 30 * 1000L // 30초마다 생존 확인
|
private const val WATCHDOG_CHECK_INTERVAL = 30 * 1000L // 30초마다 생존 확인
|
||||||
private const val STUCK_THRESHOLD = 5 * 60 * 1000L // 5분간 반응 없으면 'Stuck'으로 판단
|
private const val STUCK_THRESHOLD = 5 * 60 * 1000L // 5분간 반응 없으면 'Stuck'으로 판단
|
||||||
@ -88,10 +88,10 @@ object AutoTradingManager {
|
|||||||
// [프로세스 1] 장 마감 및 잔고 체크
|
// [프로세스 1] 장 마감 및 잔고 체크
|
||||||
val now = LocalTime.now(ZoneId.of("Asia/Seoul"))
|
val now = LocalTime.now(ZoneId.of("Asia/Seoul"))
|
||||||
//&& now.isBefore(LocalTime.of(15, 30))
|
//&& now.isBefore(LocalTime.of(15, 30))
|
||||||
// if (now.isAfter(LocalTime.of(15, 30)) ) {
|
if (now.isAfter(LocalTime.of(15, 0)) ) {
|
||||||
// executeClosingLiquidation(tradeService)
|
executeClosingLiquidation(tradeService)
|
||||||
// return@withTimeout
|
return@withTimeout
|
||||||
// }
|
}
|
||||||
|
|
||||||
val balance = tradeService.fetchIntegratedBalance().getOrNull()
|
val balance = tradeService.fetchIntegratedBalance().getOrNull()
|
||||||
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
||||||
@ -137,10 +137,10 @@ object AutoTradingManager {
|
|||||||
println("⏳ [Cycle Timeout] 사이클이 너무 길어져 초기화 후 재시작합니다.")
|
println("⏳ [Cycle Timeout] 사이클이 너무 길어져 초기화 후 재시작합니다.")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("⚠️ [Loop Error] ${e.message}")
|
println("⚠️ [Loop Error] ${e.message}")
|
||||||
delay(10000)
|
delay(5000)
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForNextCycle(3)
|
waitForNextCycle(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,7 +212,7 @@ object DynamicNewsScraper {
|
|||||||
|
|
||||||
failCountMap[domain] = (failCountMap[domain] ?: 0) + 1
|
failCountMap[domain] = (failCountMap[domain] ?: 0) + 1
|
||||||
// 불필요한 스택트레이스 출력을 줄이기 위해 메시지만 출력
|
// 불필요한 스택트레이스 출력을 줄이기 위해 메시지만 출력
|
||||||
println("❌ [Playwright] 실패 (${url.take(30)}...): ${e.localizedMessage}")
|
// println("❌ [Playwright] 실패 (${url.take(30)}...): ${e.localizedMessage}")
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,7 +254,7 @@ object SafeScraper {
|
|||||||
suspend fun scrapeParallel(corpInfo: CorpInfo, urls: List<NewsItem>) = coroutineScope {
|
suspend fun scrapeParallel(corpInfo: CorpInfo, urls: List<NewsItem>) = coroutineScope {
|
||||||
urls.forEach { item -> // map + awaitAll 대신 순차 처리가 현재 상황에선 더 안정적입니다.
|
urls.forEach { item -> // map + awaitAll 대신 순차 처리가 현재 상황에선 더 안정적입니다.
|
||||||
if (UrlCacheManager.isAlreadyProcessed(item.originallink)) {
|
if (UrlCacheManager.isAlreadyProcessed(item.originallink)) {
|
||||||
println("✅ [학습완료 데이터 스킵] ${item.originallink}")
|
// println("✅ [학습완료 데이터 스킵] ${item.originallink}")
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ object SafeScraper {
|
|||||||
try {
|
try {
|
||||||
withTimeout(25000L) { // 타임아웃 약간 증가
|
withTimeout(25000L) { // 타임아웃 약간 증가
|
||||||
val content = DynamicNewsScraper.fetchFullContent(item.originallink)
|
val content = DynamicNewsScraper.fetchFullContent(item.originallink)
|
||||||
if (content.isNotBlank()) {
|
if (content.isNotBlank() && content.length > 100) {
|
||||||
RagService.ingestWithChunking(
|
RagService.ingestWithChunking(
|
||||||
text = content,
|
text = content,
|
||||||
newsLink = item.originallink,
|
newsLink = item.originallink,
|
||||||
@ -272,7 +272,7 @@ object SafeScraper {
|
|||||||
corpCode = corpInfo.cCode,
|
corpCode = corpInfo.cCode,
|
||||||
stcokName = corpInfo.stockName
|
stcokName = corpInfo.stockName
|
||||||
)
|
)
|
||||||
println("✅ [학습완료] ${item.originallink}")
|
// println("✅ [학습완료] ${item.originallink}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import model.MAX_BUDGET
|
import model.MAX_BUDGET
|
||||||
|
import model.MIN_PURCHASE_SCORE
|
||||||
import model.buyWeight
|
import model.buyWeight
|
||||||
import model.feesAndTaxRate
|
import model.feesAndTaxRate
|
||||||
import model.minimumNetProfit
|
import model.minimumNetProfit
|
||||||
@ -185,11 +186,12 @@ fun IntegratedOrderSection(
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
val tickSize = MarketUtil.getTickSize(basePrice)
|
val tickSize = MarketUtil.getTickSize(basePrice)
|
||||||
val oneTickLowerPrice = basePrice - (tickSize * when(investmentGrade) {
|
val oneTickLowerPrice = basePrice - (tickSize * when(investmentGrade) {
|
||||||
InvestmentGrade.LEVEL_5_STRONG_RECOMMEND -> 0
|
InvestmentGrade.LEVEL_5_STRONG_RECOMMEND -> 1
|
||||||
InvestmentGrade.LEVEL_4_BALANCED_RECOMMEND -> 1
|
InvestmentGrade.LEVEL_4_BALANCED_RECOMMEND -> 2
|
||||||
InvestmentGrade.LEVEL_3_CAUTIOUS_RECOMMEND -> 1
|
InvestmentGrade.LEVEL_3_CAUTIOUS_RECOMMEND -> 3
|
||||||
InvestmentGrade.LEVEL_2_HIGH_RISK -> 2
|
InvestmentGrade.LEVEL_2_HIGH_RISK -> 3
|
||||||
InvestmentGrade.LEVEL_1_SPECULATIVE -> 3
|
InvestmentGrade.LEVEL_1_SPECULATIVE -> 4
|
||||||
|
else -> 4
|
||||||
})
|
})
|
||||||
|
|
||||||
// 2. 주문 가격 설정 (직접 입력값이 없으면 한 틱 낮은 가격 사용)
|
// 2. 주문 가격 설정 (직접 입력값이 없으면 한 틱 낮은 가격 사용)
|
||||||
@ -257,15 +259,10 @@ fun IntegratedOrderSection(
|
|||||||
"safe" to 0.4 // 중장기 점수 비중 강화
|
"safe" to 0.4 // 중장기 점수 비중 강화
|
||||||
)
|
)
|
||||||
|
|
||||||
// 2. 토탈 스코어 계산
|
|
||||||
val totalScore =
|
val totalScore =
|
||||||
(completeTradingDecision.shortPossible() * weights["short"]!!) +
|
(completeTradingDecision.shortPossible() * weights["short"]!!) +
|
||||||
(completeTradingDecision.profitPossible() * weights["profit"]!!) +
|
(completeTradingDecision.profitPossible() * weights["profit"]!!) +
|
||||||
(completeTradingDecision.safePossible() * weights["safe"]!!)
|
(completeTradingDecision.safePossible() * weights["safe"]!!)
|
||||||
|
|
||||||
// 3. 매수 결정 문턱값 (예: 70점 이상이면 매수 가능)
|
|
||||||
val MIN_PURCHASE_SCORE = 68.0
|
|
||||||
val HIGH_QUALITY_SCORE = 85.0 // 강력 추천 기준
|
|
||||||
println("""
|
println("""
|
||||||
corpName : ${completeTradingDecision.corpName}
|
corpName : ${completeTradingDecision.corpName}
|
||||||
confidence : ${completeTradingDecision.confidence + append}
|
confidence : ${completeTradingDecision.confidence + append}
|
||||||
|
|||||||
7
src/main/resources/logback.xml
Normal file
7
src/main/resources/logback.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<configuration>
|
||||||
|
<logger name="Exposed" level="OFF" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
Loading…
x
Reference in New Issue
Block a user