...
This commit is contained in:
parent
681472df58
commit
62e408230e
7
src/main/kotlin/Defines.kt
Normal file
7
src/main/kotlin/Defines.kt
Normal file
@ -0,0 +1,7 @@
|
||||
object Defines {
|
||||
val DETAILLOG = false
|
||||
val LLM_PORT = 8080
|
||||
val EMBEDDING_PORT = 8081
|
||||
val AUTOSELL = false
|
||||
val BLACKLISTEDSTOCKCODES = listOf<String>()
|
||||
}
|
||||
@ -9,6 +9,9 @@ import ConfigTable.grade_4_profit
|
||||
import ConfigTable.grade_5_buy
|
||||
import ConfigTable.grade_5_profit
|
||||
import ConfigTable.max_count
|
||||
import Defines.DETAILLOG
|
||||
import Defines.EMBEDDING_PORT
|
||||
import Defines.LLM_PORT
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
@ -93,7 +96,7 @@ fun initLogger(isDebug: Boolean) {
|
||||
}
|
||||
|
||||
fun main() = application {
|
||||
initLogger(AutoTradingManager.DETAILLOG)
|
||||
initLogger(DETAILLOG)
|
||||
val trayState = rememberTrayState()
|
||||
var isWindowOpen by remember { mutableStateOf(false) } // 창의 표시 상태 관리
|
||||
|
||||
@ -208,10 +211,10 @@ fun main() = application {
|
||||
}
|
||||
|
||||
if (config.modelPath.isNotEmpty()) {
|
||||
LlamaServerManager.startServer(binPath, config.modelPath,port = AutoTradingManager.LLM_PORT)
|
||||
LlamaServerManager.startServer(binPath, config.modelPath,port = LLM_PORT)
|
||||
}
|
||||
if (config.embedModelPath.isNotEmpty()) {
|
||||
LlamaServerManager.startServer(binPath, config.embedModelPath, port = AutoTradingManager.EMBEDDING_PORT)
|
||||
LlamaServerManager.startServer(binPath, config.embedModelPath, port = EMBEDDING_PORT)
|
||||
}
|
||||
|
||||
// 대시보드로 화면 전환
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package network// src/main/kotlin/network/RagService.kt
|
||||
|
||||
import Defines.EMBEDDING_PORT
|
||||
import Defines.LLM_PORT
|
||||
import TradingLogStore
|
||||
import dev.langchain4j.community.rag.content.retriever.lucene.LuceneEmbeddingStore
|
||||
import dev.langchain4j.data.document.Metadata
|
||||
@ -56,12 +58,12 @@ object RagService {
|
||||
|
||||
// 임베딩 모델 (8081) 및 채팅 모델 (8080) 설정
|
||||
private val embeddingModel = OpenAiEmbeddingModel.builder()
|
||||
.baseUrl("http://127.0.0.1:${AutoTradingManager.EMBEDDING_PORT}/v1")
|
||||
.baseUrl("http://127.0.0.1:${EMBEDDING_PORT}/v1")
|
||||
.apiKey("unused")
|
||||
.build()
|
||||
|
||||
private val chatModel = OpenAiChatModel.builder()
|
||||
.baseUrl("http://127.0.0.1:${AutoTradingManager.LLM_PORT}/v1")
|
||||
.baseUrl("http://127.0.0.1:${LLM_PORT}/v1")
|
||||
.apiKey("unused")
|
||||
.temperature(0.0) // [중요] 0.0으로 설정하여 결정론적 응답 유도
|
||||
.timeout(Duration.ofSeconds(60))
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
package service
|
||||
|
||||
import AutoTradeItem
|
||||
import Defines.AUTOSELL
|
||||
import Defines.BLACKLISTEDSTOCKCODES
|
||||
import Defines.EMBEDDING_PORT
|
||||
import Defines.LLM_PORT
|
||||
import network.TradingDecision
|
||||
import TradingLogStore
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -49,9 +53,8 @@ import kotlin.math.*
|
||||
// service/AutoTradingManager.kt
|
||||
typealias TradingDecisionCallback = (TradingDecision?, Boolean)->Unit
|
||||
object AutoTradingManager {
|
||||
val DETAILLOG = true
|
||||
val LLM_PORT = 13080
|
||||
val EMBEDDING_PORT = 13081
|
||||
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
private var discoveryJob: Job? = null
|
||||
|
||||
@ -368,34 +371,47 @@ object AutoTradingManager {
|
||||
// 1. DB에서 매도 중(SELLING)이거나 만료(EXPIRED)된 매도 건을 가져옵니다.
|
||||
println("resumePendingSellOrders")
|
||||
balance.holdings.forEach { holding ->
|
||||
|
||||
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
|
||||
println("${holding.name} - 매수 : ${holding.avgPrice} - 현재 : ${holding.currentPrice} ")
|
||||
|
||||
// 3. 기존 목표가(targetPrice)로 다시 매도 주문 전송
|
||||
var targetPrice = holding.currentPrice.toDouble()
|
||||
targetPrice = MarketUtil.roundToTickSize(targetPrice + MarketUtil.getTickSize(targetPrice))
|
||||
|
||||
println("🔄 [재주문] ${holding.name} (${holding.code}) 매도 목표 ${targetPrice} 미체결 매도 건 재주문 시도")
|
||||
// TradingLogStore.addSellLog(holding.code,targetPrice.toString(),"SELL","🎊 보유 주식 매도 주문[예상수익 : ${holding.profitRate}] ")
|
||||
tradeService.postOrder(
|
||||
stockCode = holding.code,
|
||||
qty = holding.availOrderCount,
|
||||
price = targetPrice.toInt().toString(),
|
||||
isBuy = false
|
||||
).onSuccess { newOrderNo ->
|
||||
// 4. 새로운 주문번호로 DB 업데이트 및 상태를 SELLING으로 유지
|
||||
// DatabaseFactory.updateStatusAndOrderNo(item.id!!, TradeStatus.SELLING, newOrderNo)
|
||||
println("✅ [재주문 완료] ${holding.name}: $newOrderNo")
|
||||
TradingLogStore.addSellLog(holding.code,targetPrice.toString(),"SELL","🎊 보유 주식 매도 주문 완료[예상수익 : ${holding.profitRate}] ")
|
||||
}.onFailure {
|
||||
TradingLogStore.addSellLog(holding.code,targetPrice.toString(),"SELL","🎊 보유 주식 매도 주문 실패[${it.message}] ")
|
||||
// println("❌ [재주문 실패] ${holding.name}: ${it.message}")
|
||||
}
|
||||
if (BLACKLISTEDSTOCKCODES.contains(holding.code)){
|
||||
println("❌ 차단 처리된 주식 : ${holding.name}")
|
||||
} else {
|
||||
if (holding != null && holding.quantity.toInt() > 0 && holding.availOrderCount.toInt() > 0 && holding.profitRate.toDouble() > KisSession.config.SELL_PROFIT) {
|
||||
println("${holding.name} - 매수 : ${holding.avgPrice} - 현재 : ${holding.currentPrice} ")
|
||||
|
||||
// 3. 기존 목표가(targetPrice)로 다시 매도 주문 전송
|
||||
var targetPrice = holding.currentPrice.toDouble()
|
||||
targetPrice = MarketUtil.roundToTickSize(targetPrice + MarketUtil.getTickSize(targetPrice))
|
||||
|
||||
println("🔄 [재주문] ${holding.name} (${holding.code}) 매도 목표 ${targetPrice} 미체결 매도 건 재주문 시도")
|
||||
// TradingLogStore.addSellLog(holding.code,targetPrice.toString(),"SELL","🎊 보유 주식 매도 주문[예상수익 : ${holding.profitRate}] ")
|
||||
tradeService.postOrder(
|
||||
stockCode = holding.code,
|
||||
qty = holding.availOrderCount,
|
||||
price = targetPrice.toInt().toString(),
|
||||
isBuy = false
|
||||
).onSuccess { newOrderNo ->
|
||||
// 4. 새로운 주문번호로 DB 업데이트 및 상태를 SELLING으로 유지
|
||||
// DatabaseFactory.updateStatusAndOrderNo(item.id!!, TradeStatus.SELLING, newOrderNo)
|
||||
println("✅ [재주문 완료] ${holding.name}: $newOrderNo")
|
||||
TradingLogStore.addSellLog(
|
||||
holding.code,
|
||||
targetPrice.toString(),
|
||||
"SELL",
|
||||
"🎊 보유 주식 매도 주문 완료[예상수익 : ${holding.profitRate}] "
|
||||
)
|
||||
}.onFailure {
|
||||
TradingLogStore.addSellLog(
|
||||
holding.code,
|
||||
targetPrice.toString(),
|
||||
"SELL",
|
||||
"🎊 보유 주식 매도 주문 실패[${it.message}] "
|
||||
)
|
||||
// println("❌ [재주문 실패] ${holding.name}: ${it.message}")
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
delay(200) // API 호출 부하 방지
|
||||
}
|
||||
delay(200) // API 호출 부하 방지
|
||||
}
|
||||
}
|
||||
var isSystemReadyToday = false
|
||||
@ -537,7 +553,9 @@ object AutoTradingManager {
|
||||
|
||||
suspend fun executeMarketLoop() {
|
||||
val balance = KisTradeService.fetchIntegratedBalance().getOrNull()
|
||||
balance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||
|
||||
if (AUTOSELL) balance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||
|
||||
val myCash = balance?.deposit?.replace(",", "")?.toLongOrNull() ?: 0L
|
||||
val myHoldings = balance?.holdings?.filter { it.quantity.toInt() > 0 }?.map { it.code }?.toSet() ?: emptySet()
|
||||
val pendingStocks = DatabaseFactory.findAllMonitoringTrades().map { it.code }
|
||||
@ -582,15 +600,19 @@ object AutoTradingManager {
|
||||
while (iterator.hasNext()) {
|
||||
totalCount--
|
||||
val stock = iterator.next()
|
||||
try {
|
||||
processSingleStock(stock, myCash, KisTradeService, globalCallback)
|
||||
} catch (e: Exception) {
|
||||
println("❌ 처리 중 오류 발생 (건너뜀): ${stock.name}")
|
||||
} finally {
|
||||
iterator.remove()
|
||||
if (BLACKLISTEDSTOCKCODES.contains(stock.code)){
|
||||
println("❌ 차단 처리된 주식 : ${stock.name}")
|
||||
} else {
|
||||
try {
|
||||
processSingleStock(stock, myCash, KisTradeService, globalCallback)
|
||||
} catch (e: Exception) {
|
||||
println("❌ 처리 중 오류 발생 (건너뜀): ${stock.name}")
|
||||
} finally {
|
||||
iterator.remove()
|
||||
}
|
||||
println("남은 후보군 개수 : ${totalCount}")
|
||||
delay(100)
|
||||
}
|
||||
println("남은 후보군 개수 : ${totalCount}")
|
||||
delay(100)
|
||||
}
|
||||
println("⏱️ [Cycle End] ${LocalTime.now()}")
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package service
|
||||
|
||||
import Defines.DETAILLOG
|
||||
import Defines.EMBEDDING_PORT
|
||||
import Defines.LLM_PORT
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@ -94,12 +97,12 @@ object LlamaServerManager {
|
||||
binPath,
|
||||
"-m", modelPath,
|
||||
"--port", port.toString(),
|
||||
"-c", if (port == AutoTradingManager.EMBEDDING_PORT) "512" else "8192",
|
||||
"-c", if (port == EMBEDDING_PORT) "512" else "8192",
|
||||
"-ngl", optimalGpuLayers.toString(),
|
||||
"-t", optimalThreads.toString(),
|
||||
"--embedding"
|
||||
)
|
||||
if (port != AutoTradingManager.EMBEDDING_PORT) { // 텍스트 생성용 모델에만 적용
|
||||
if (port != EMBEDDING_PORT) { // 텍스트 생성용 모델에만 적용
|
||||
command.addAll(listOf(
|
||||
"-b", "512", // Batch size (토큰 병렬 처리량 제한으로 연산 안정화)
|
||||
"--threads-batch", optimalThreads.toString(),
|
||||
@ -142,14 +145,14 @@ object LlamaServerManager {
|
||||
var line: String?
|
||||
while (reader.readLine().also { line = it } != null) {
|
||||
// 로그 출력 (디버깅용)
|
||||
if (AutoTradingManager.DETAILLOG) println("[Server $port] $line")
|
||||
if (DETAILLOG) println("[Server $port] $line")
|
||||
|
||||
if (line?.contains("server is listening") == true) {
|
||||
println("🚀 AI 서버 준비 완료 (Port: $port)")
|
||||
if (port == AutoTradingManager.LLM_PORT){
|
||||
if (port == LLM_PORT){
|
||||
AutoTradingManager.llmAnalyser = true
|
||||
}
|
||||
if (port == AutoTradingManager.EMBEDDING_PORT){
|
||||
if (port == EMBEDDING_PORT){
|
||||
AutoTradingManager.llmNews = true
|
||||
}
|
||||
if (processes.size > 1) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user