...
This commit is contained in:
@@ -41,7 +41,7 @@ object KisTradeService {
|
||||
// [수정] 모든 로그(Headers + Body)를 찍도록 설정
|
||||
install(Logging) {
|
||||
logger = Logger.DEFAULT
|
||||
level = LogLevel.BODY
|
||||
level = LogLevel.NONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,12 @@ object KisTradeService {
|
||||
|
||||
val totalAmt = (domRes?.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
|
||||
|
||||
Result.success(UnifiedBalance(
|
||||
totalAsset = String.format("%,d", totalAmt),
|
||||
totalProfitRate = domRes?.output2?.firstOrNull()?.evlu_pfls_rt ?: "0.0",
|
||||
deposit = String.format("%,d", depositAmt),
|
||||
holdings = combinedHoldings
|
||||
))
|
||||
} catch (e: Exception) { Result.failure(e) }
|
||||
@@ -220,7 +222,7 @@ object KisTradeService {
|
||||
|
||||
val body = response.body<JsonObject>()
|
||||
val output2 = body["output2"]?.jsonArray
|
||||
println("output2 ${output2}")
|
||||
// println("output2 ${output2}")
|
||||
val candles = output2?.map { element ->
|
||||
val obj = element.jsonObject
|
||||
CandleData(
|
||||
@@ -394,7 +396,7 @@ object KisTradeService {
|
||||
val cano = pureAccount.take(8)
|
||||
val acntPrdtCd = pureAccount.takeLast(2)
|
||||
return try {
|
||||
println("orgNo")
|
||||
// println("orgNo")
|
||||
val response = client.post("$baseUrl/uapi/domestic-stock/v1/trading/order-rvsecncl") {
|
||||
header("authorization", "Bearer ${config.tradeToken}")
|
||||
header("appkey", if (config.isSimulation) config.vtsAppKey else config.realAppKey)
|
||||
|
||||
@@ -29,7 +29,7 @@ object NewsService {
|
||||
}
|
||||
install(Logging) {
|
||||
logger = Logger.DEFAULT
|
||||
level = LogLevel.ALL
|
||||
level = LogLevel.NONE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ object RagService {
|
||||
|
||||
|
||||
fun active() {
|
||||
println("[Cache] Active")
|
||||
// println("[Cache] Active")
|
||||
if (UrlCacheManager.isInitialized()) return
|
||||
println("[Cache] initialize")
|
||||
// println("[Cache] initialize")
|
||||
UrlCacheManager.initialize(embeddingStore, embeddingModel)
|
||||
}
|
||||
|
||||
@@ -130,32 +130,39 @@ object RagService {
|
||||
suspend fun processStock(stockName: String,stockCode: String,result : TradingDecisionCallback) {
|
||||
// 1. 10분간의 데이터 가져오기 (API 호출)
|
||||
coroutineScope {
|
||||
var tradingDecision : TradingDecision = TradingDecision()
|
||||
tradingDecision.stockCode = stockCode
|
||||
var corpInfo = DartCodeManager.getCorpCode(stockCode)
|
||||
corpInfo?.stockName = stockName
|
||||
corpInfo?.let { NewsService.fetchAndIngestNews(it) }
|
||||
try {
|
||||
|
||||
val financialDataDeferred = async { NewsService.fetchFinancialGrowth(corpInfo?.cCode ?: "") }
|
||||
|
||||
tradingDecision.financialData = financialDataDeferred.await()
|
||||
result(tradingDecision,false)
|
||||
var tradingDecision: TradingDecision = TradingDecision()
|
||||
tradingDecision.stockCode = stockCode
|
||||
var corpInfo = DartCodeManager.getCorpCode(stockCode)
|
||||
corpInfo?.stockName = stockName
|
||||
tradingDecision.stockName = stockName
|
||||
tradingDecision.corpName = corpInfo?.cName ?: ""
|
||||
corpInfo?.let { NewsService.fetchAndIngestNews(it) }
|
||||
|
||||
tradingDecision.techSummary = TechnicalAnalyzer.generateComprehensiveReport()
|
||||
result(tradingDecision,false)
|
||||
val financialDataDeferred = async { NewsService.fetchFinancialGrowth(corpInfo?.cCode ?: "") }
|
||||
|
||||
val question = "${corpInfo?.cName} $stockName[$stockCode]의 향후 실적 전망과 관련된 핵심 뉴스"
|
||||
val questionEmbedding = embeddingModel.embed(question).content()
|
||||
val searchResult = embeddingStore.search(
|
||||
EmbeddingSearchRequest.builder()
|
||||
.queryEmbedding(questionEmbedding)
|
||||
.maxResults(3)
|
||||
.build()
|
||||
)
|
||||
tradingDecision.newsContext = searchResult.matches().joinToString("\n") { it.embedded().text() }
|
||||
result(tradingDecision,false)
|
||||
result(decideTrading(stockCode, tradingDecision),true)
|
||||
tradingDecision.financialData = financialDataDeferred.await()
|
||||
result(tradingDecision, false)
|
||||
|
||||
tradingDecision.techSummary = TechnicalAnalyzer.generateComprehensiveReport()
|
||||
result(tradingDecision, false)
|
||||
|
||||
val question = "${corpInfo?.cName} $stockName[$stockCode]의 향후 실적 전망과 관련된 핵심 뉴스"
|
||||
val questionEmbedding = embeddingModel.embed(question).content()
|
||||
val searchResult = embeddingStore.search(
|
||||
EmbeddingSearchRequest.builder()
|
||||
.queryEmbedding(questionEmbedding)
|
||||
.maxResults(3)
|
||||
.build()
|
||||
)
|
||||
tradingDecision.newsContext = searchResult.matches().joinToString("\n") { it.embedded().text() }
|
||||
result(tradingDecision, false)
|
||||
result(decideTrading(stockCode, tradingDecision), true)
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +227,7 @@ object RagService {
|
||||
""".trimIndent()
|
||||
|
||||
val response = chatModel.chat(UserMessage.from(finalPrompt))
|
||||
println(response)
|
||||
// println(response)
|
||||
return response.aiMessage().text()
|
||||
}
|
||||
|
||||
@@ -271,7 +278,7 @@ object RagService {
|
||||
val response = chatModel.chat(UserMessage.from(prompt))
|
||||
val rawResponse = response.aiMessage().text()
|
||||
val jsonResponse = JsonSanitizer.formatJson(rawResponse)
|
||||
println("📥 [AI Raw JSON]:\n$jsonResponse")
|
||||
// println("📥 [AI Raw JSON]:\n$jsonResponse")
|
||||
|
||||
// 2. 유연한 파서 설정 (소수점 및 예외 상황 대응)
|
||||
val lenientJson = Json {
|
||||
@@ -283,12 +290,14 @@ object RagService {
|
||||
|
||||
// JSON 파싱 (Kotlinx Serialization 활용)
|
||||
return try {
|
||||
println(jsonResponse)
|
||||
// println(jsonResponse)
|
||||
val decision = lenientJson.decodeFromString<TradingDecision>(jsonResponse)
|
||||
decision.financialData = tempDecision.financialData
|
||||
decision.newsContext = tempDecision.newsContext
|
||||
decision.techSummary = tempDecision.techSummary
|
||||
decision.stockCode = tempDecision.stockCode
|
||||
decision.corpName = tempDecision.corpName
|
||||
decision.stockName = tempDecision.stockName
|
||||
decision
|
||||
} catch (e: dev.langchain4j.exception.InternalServerException) {
|
||||
// 서버 에러 (컨텍스트 초과 등) 발생 시 로그 남기고 null 반환 혹은 커스텀 에러 처리
|
||||
@@ -308,11 +317,14 @@ object RagService {
|
||||
}
|
||||
@Serializable
|
||||
class TradingDecision {
|
||||
|
||||
var corpName : String = ""
|
||||
var stockName : String = ""
|
||||
val ultraShortScore: Double = 0.0 // 초단기 (분봉/에너지)
|
||||
val shortTermScore: Double = 0.0 // 단기 (일봉/뉴스)
|
||||
val midTermScore: Double = 0.0 // 중기 (주봉/재무)
|
||||
val longTermScore: Double = 0.0
|
||||
// [추가] 화면 전환용 종목명
|
||||
var currentPrice: Double = 0.0
|
||||
var stockCode: String = ""
|
||||
var decision: String? = null
|
||||
var reason: String? = null
|
||||
@@ -323,12 +335,18 @@ class TradingDecision {
|
||||
|
||||
fun profitPossible() =
|
||||
listOf<Double>(ultraShortScore,
|
||||
shortTermScore,
|
||||
midTermScore,
|
||||
longTermScore).average()
|
||||
shortTermScore,
|
||||
midTermScore,
|
||||
longTermScore).average()
|
||||
|
||||
fun safePossible() =
|
||||
listOf<Double>(
|
||||
midTermScore,
|
||||
longTermScore).average()
|
||||
|
||||
override fun toString(): String {
|
||||
return """
|
||||
$corpName($stockName)
|
||||
수익실현 가능성 : ${profitPossible()}
|
||||
ultraShortScore :$ultraShortScore
|
||||
shortTermScore :$shortTermScore
|
||||
|
||||
Reference in New Issue
Block a user