..
This commit is contained in:
@@ -14,8 +14,12 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import model.CandleData
|
||||
import network.DartCodeManager
|
||||
import network.FinancialMapper
|
||||
import network.FinancialStatement
|
||||
import network.NewsService
|
||||
import org.apache.lucene.store.MMapDirectory
|
||||
import service.FinancialAnalyzer
|
||||
import service.InvestmentScores
|
||||
import service.TechnicalAnalyzer
|
||||
import service.TradingDecisionCallback
|
||||
import service.UrlCacheManager
|
||||
@@ -131,39 +135,46 @@ object RagService {
|
||||
// 1. 10분간의 데이터 가져오기 (API 호출)
|
||||
coroutineScope {
|
||||
try {
|
||||
|
||||
|
||||
var tradingDecision: TradingDecision = TradingDecision()
|
||||
tradingDecision.stockCode = stockCode
|
||||
var corpInfo = DartCodeManager.getCorpCode(stockCode)
|
||||
corpInfo?.stockName = stockName
|
||||
tradingDecision.stockName = stockName
|
||||
tradingDecision.corpName = corpInfo?.cName ?: ""
|
||||
corpInfo?.let {
|
||||
try {
|
||||
NewsService.fetchAndIngestNews(it)
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
|
||||
val financialDataDeferred = async { NewsService.fetchFinancialGrowth(corpInfo?.cCode ?: "") }
|
||||
|
||||
tradingDecision.financialData = financialDataDeferred.await()
|
||||
result(tradingDecision, false)
|
||||
|
||||
tradingDecision.techSummary = technicalAnalyzer.generateComprehensiveReport()
|
||||
result(tradingDecision, false)
|
||||
val financialStmt = FinancialMapper.mapRawTextToStatement(tradingDecision.financialData ?: "")
|
||||
if (FinancialAnalyzer.isSafetyBeltMet(financialStmt)) {
|
||||
corpInfo?.let {
|
||||
try {
|
||||
NewsService.fetchAndIngestNews(it)
|
||||
} catch (e: Exception) {}
|
||||
}
|
||||
|
||||
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)
|
||||
val financialScore = FinancialAnalyzer.calculateScore(financialStmt)
|
||||
val scores = technicalAnalyzer.calculateScores(financialScore)
|
||||
|
||||
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, scores,financialStmt,tradingDecision), true)
|
||||
} else {
|
||||
result(tradingDecision, false)
|
||||
}
|
||||
}catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -237,45 +248,55 @@ object RagService {
|
||||
|
||||
suspend fun decideTrading(
|
||||
stockName: String,
|
||||
scores: InvestmentScores, // 직접 계산한 점수 객체
|
||||
financialStmt: FinancialStatement, // 매핑된 재무 수치 객체
|
||||
tempDecision: TradingDecision
|
||||
): TradingDecision? {
|
||||
val prompt = """
|
||||
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
|
||||
당신은 수치 기반의 '정량 분석(Quantitative Analysis)' 트레이딩 전문가이자 전문 애널리스트입니다.
|
||||
제공된 데이터를 바탕으로 투자 기간별 스코어를 산출하고 최종 매매 결정을 내리십시오.
|
||||
아래 데이터를 분석하여 '매수', '매도', '관망' 중 하나를 결정하세요.
|
||||
|
||||
[데이터 요약]
|
||||
- 종목: $stockName
|
||||
- 분석: ${tempDecision.techSummary}
|
||||
- 기업/재무: ${tempDecision.financialData}
|
||||
- 시장 심리: ${tempDecision.newsContext}
|
||||
당신은 정량적 수치와 정성적 뉴스를 통합 분석하는 'AI 수석 애널리스트'입니다.
|
||||
시스템이 계산한 지표 점수와 실제 재무제표 요약본을 바탕으로 최종 매매 전략을 수립하십시오.
|
||||
|
||||
[스코어 산출 가이드 (0-100)]
|
||||
1. 초단기: 30분봉 추세, MFI, OBV 에너지가 일치하면 80점 이상.
|
||||
2. 단기: 일봉 이평선 정배열 및 3일 변동률 양수일 때 70점 이상.
|
||||
3. 중기: 주봉 추세와 재무 성장성(매출/영익)이 동반 상승 시 75점 이상.
|
||||
4. 장기: 월봉 위치와 기업의 근본적인 시장 지배력 기반 판단.
|
||||
[종목 정보]
|
||||
- 종목명: $stockName
|
||||
|
||||
[1. 시스템 산출 스코어 (0-100)]
|
||||
- 초단기(Scalping): ${scores.ultraShort}
|
||||
- 단기(Daily): ${scores.shortTerm}
|
||||
- 중기(Weekly): ${scores.midTerm}
|
||||
- 장기(Monthly): ${scores.longTerm}
|
||||
|
||||
[2. 핵심 재무제표 요약]
|
||||
- 영업이익: ${if(financialStmt.isOperatingProfitPositive) "흑자" else "적자"} (성장률: ${"%.2f".format(financialStmt.operatingProfitGrowth)}%)
|
||||
- 당기순이익: ${if(financialStmt.isNetIncomePositive) "흑자" else "적자"} (성장률: ${"%.2f".format(financialStmt.netIncomeGrowth)}%)
|
||||
- 수익성(ROE): ${"%.2f".format(financialStmt.roe)}%
|
||||
- 안정성(부채비율): ${"%.2f".format(financialStmt.debtRatio)}%
|
||||
- 유동성(당좌비율): ${"%.2f".format(financialStmt.quickRatio)}%
|
||||
|
||||
[3. 시장 심리 및 뉴스 컨텍스트]
|
||||
${tempDecision.newsContext}
|
||||
|
||||
[분석 지침]
|
||||
1. **재무-뉴스 정합성**: 재무제표상 영업이익이 적자임에도 뉴스가 장기적 장밋빛 전망만 내놓는다면 '신중(HOLD)' 의견을 제시하십시오.
|
||||
2. **기술-심리 동기화**: 초단기 점수가 높고 뉴스에서 수급 급증 키워드가 포착되면 'BUY' 신뢰도를 높이십시오.
|
||||
3. **종합 결정**: 모든 수치와 컨텍스트를 고려하여 최종 Decision을 내리고, 그 근거를 핵심만 기술하십시오.
|
||||
|
||||
[응답 지침]
|
||||
- JSON 데이터만 출력하십시오. 설명이나 서론은 생략합니다.
|
||||
- 반드시 아래 형식을 엄격히 준수하십시오.
|
||||
|
||||
[응답 지침 - 엄격 준수]
|
||||
1. 분석 내용에 대한 설명, 서론, 결론을 절대 작성하지 마십시오.
|
||||
2. 오직 JSON 데이터만 출력하십시오.
|
||||
3. JSON 외의 텍스트가 포함될 경우 시스템이 중단됩니다.
|
||||
4. 응답은 반드시 '{' 문자로 시작하여 '}' 문자로 끝나야 합니다.
|
||||
[응답 형식]
|
||||
반드시 아래 JSON 형식으로만 답변하십시오:
|
||||
{
|
||||
"ultraShortScore": (숫자),
|
||||
"shortTermScore": (숫자),
|
||||
"midTermScore": (숫자),
|
||||
"longTermScore": (숫자),
|
||||
"ultraShortScore": ${scores.ultraShort},
|
||||
"shortTermScore": ${scores.shortTerm},
|
||||
"midTermScore": ${scores.midTerm},
|
||||
"longTermScore": ${scores.longTerm},
|
||||
"decision": "BUY" | "SELL" | "HOLD",
|
||||
"reason": "결정적 근거 한 줄",
|
||||
"reason": "재무 수치와 뉴스 심리를 대조한 최종 결론 한 줄",
|
||||
"confidence": 0~100
|
||||
}
|
||||
<|eot_id|>
|
||||
<|start_header_id|>user<|end_header_id|>
|
||||
모든 데이터를 종합하여 스코어링 리포트를 작성하십시오.
|
||||
상기 데이터를 통합 분석하여 최종 리포트를 생성하십시오.
|
||||
<|eot_id|><|start_header_id|>assistant<|end_header_id|>
|
||||
""".trimIndent()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user