...
This commit is contained in:
parent
57abcbf8f8
commit
7fa1c36355
@ -37,6 +37,7 @@ import model.AppConfig
|
||||
import model.KisSession
|
||||
import network.DartCodeManager
|
||||
import network.KisTradeService
|
||||
import network.KisWebSocketManager
|
||||
import service.LlamaServerManager
|
||||
import network.NewsService
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
@ -147,6 +148,7 @@ fun main() = application {
|
||||
AutoTradingManager.isSystemCleanedUpToday = false
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
AutoTradingManager.startAutoDiscoveryLoop()
|
||||
KisWebSocketManager.onExecutionReceived = AutoTradingManager.onExecutionReceived
|
||||
}
|
||||
|
||||
if (config.modelPath.isNotEmpty()) {
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import AutoTradeTable.orderNo
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import kotlinx.serialization.Serializable
|
||||
import model.AppConfig
|
||||
@ -399,6 +398,21 @@ object TradingLogStore {
|
||||
}
|
||||
}
|
||||
|
||||
fun addSellLog(stockName: String,sellPrice : String , decision: String, log: String) {
|
||||
synchronized(this) {
|
||||
if (decisionLogs.size > 1000) decisionLogs.removeAt(0)
|
||||
decisionLogs.add(
|
||||
LogEntry(
|
||||
time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")),
|
||||
stockName = "${stockName}[${sellPrice}][]",
|
||||
decision = decision,
|
||||
confidence = 100.0,
|
||||
reason = log
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun addLog(tradingDecision: TradingDecision , decision: String, log: String) {
|
||||
synchronized(this) {
|
||||
if (decisionLogs.size > 1000) decisionLogs.removeAt(0)
|
||||
@ -414,5 +428,20 @@ object TradingLogStore {
|
||||
}
|
||||
}
|
||||
|
||||
fun addSettingLog(settingDesc : String, old : String, new : String, log: String) {
|
||||
synchronized(this) {
|
||||
if (decisionLogs.size > 1000) decisionLogs.removeAt(0)
|
||||
decisionLogs.add(
|
||||
LogEntry(
|
||||
time = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")),
|
||||
stockName = "설정변경[${settingDesc}][$old]->[$new]",
|
||||
decision = "SETTING",
|
||||
confidence = 100.0,
|
||||
reason = log
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package service
|
||||
|
||||
import AutoTradeItem
|
||||
import TradingDecision
|
||||
import TradingLogStore
|
||||
import androidx.compose.runtime.remember
|
||||
import getLlamaBinPath
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -112,7 +113,7 @@ object AutoTradingManager {
|
||||
1
|
||||
}
|
||||
// 5. 매수 실행 (계산된 finalMargin 전달)
|
||||
AutoTradingManager.excuteTrade(
|
||||
excuteTrade(
|
||||
decision = completeTradingDecision,
|
||||
orderQty = min(calculatedQty, maxQty).toString(),
|
||||
profitRate1 = finalMargin,
|
||||
@ -120,7 +121,7 @@ object AutoTradingManager {
|
||||
)
|
||||
|
||||
} else if(totalScore >= (minScore * 0.85) && completeTradingDecision.confidence + append >= (MIN_CONFIDENCE * 0.85)) {
|
||||
AutoTradingManager.addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
||||
addToReanalysis(RankingStock(mksc_shrn_iscd = completeTradingDecision.stockCode,hts_kor_isnm = completeTradingDecision.stockName))
|
||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어 또는 신뢰도 미달 이나 약간의 오차로 재분석 대기열에 추가")
|
||||
} else {
|
||||
TradingLogStore.addLog(completeTradingDecision,"HOLD","✋ [관망] 토탈 스코어(${String.format("%.1f[${minScore}]", totalScore)}) 또는 신뢰도 (${String.format("%.1f[${MIN_CONFIDENCE}]", completeTradingDecision.confidence)}) 미달")
|
||||
@ -242,7 +243,13 @@ object AutoTradingManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var onExecutionReceived : ((String, String, String, String, Boolean) -> Unit)? = {code, qty, price,orderNo, isBuy ->
|
||||
scope.launch {
|
||||
val exec = ExecutionData(orderNo, code, price, qty, isBuy)
|
||||
executionCache[orderNo] = exec
|
||||
syncAndExecute(orderNo)
|
||||
}
|
||||
}
|
||||
val executionCache = mutableMapOf<String, ExecutionData>()
|
||||
val processingIds = mutableSetOf<String>() // 주문번호 기준 잠금
|
||||
suspend fun syncAndExecute(orderNo: String) {
|
||||
@ -278,14 +285,15 @@ object AutoTradingManager {
|
||||
).onSuccess { newSellOrderNo ->
|
||||
// 익절가 업데이트 및 상태 변경
|
||||
DatabaseFactory.updateStatusAndOrderNo(dbItem.id!!, TradeStatus.SELLING, newSellOrderNo)
|
||||
// (선택 사항) 실제 계산된 익절가를 DB에 기록하고 싶다면 별도 update 로직 추가 가능
|
||||
|
||||
TradingLogStore.addSellLog(dbItem.name,finalTargetPrice.toString(),"SELL","🎯 [매칭 성공] 익절 주문 실행: ${dbItem.name} | 매수가: ${actualBuyPrice.toInt()} -> 목표가: ${finalTargetPrice.toInt()} (${String.format("%.2f", finalProfitRate)}% 적용)")
|
||||
executionCache.remove(orderNo)
|
||||
}.onFailure {
|
||||
println("❌ 익절 주문 실패: ${it.message}")
|
||||
TradingLogStore.addSellLog(dbItem.name,finalTargetPrice.toString(),"SELL","❌ 익절 주문 실패: ${it.message}")
|
||||
}
|
||||
} else if (dbItem.status == TradeStatus.SELLING) {
|
||||
println("🎊 [매칭 성공] 매도 완료 처리: ${dbItem.name}")
|
||||
TradingLogStore.addSellLog(dbItem.name,execData.price,"SELL","🎊 [매칭 성공] 매도 완료 처리")
|
||||
DatabaseFactory.updateStatusAndOrderNo(dbItem.id!!, TradeStatus.COMPLETED)
|
||||
executionCache.remove(orderNo)
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package ui
|
||||
|
||||
|
||||
import AutoTradeItem
|
||||
import TradingDecision
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@ -14,7 +12,6 @@ import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@ -25,7 +22,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import model.ConfigIndex
|
||||
import model.KisSession
|
||||
import service.TechnicalAnalyzer
|
||||
|
||||
@Composable
|
||||
fun TradingDecisionLog() {
|
||||
@ -45,7 +41,13 @@ fun TradingDecisionLog() {
|
||||
Text("${log.time} - ${log.stockName}", fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
text = log.decision,
|
||||
color = if (log.decision == "BUY") Color.Red else Color.Gray,
|
||||
color = when (log.decision) {
|
||||
"BUY" -> Color.Red
|
||||
"SETTING" -> Color(0xFFFFA500) // 주황색
|
||||
"SELL" -> Color(0xFF800080) // 보라색
|
||||
"HOLD" -> Color.Gray // HOLD는 그레이
|
||||
else -> Color.Gray // 그 외 기본값 그레이
|
||||
},
|
||||
fontWeight = FontWeight.ExtraBold
|
||||
)
|
||||
}
|
||||
@ -63,6 +65,7 @@ fun TradingDecisionLog() {
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
modifier = Modifier.fillMaxWidth().fillMaxHeight().background(Color.White)
|
||||
) {
|
||||
var firstSet = mutableSetOf<ConfigIndex>()
|
||||
item(span = { GridItemSpan(maxLineSpan) }) { // 2열을 모두 차지함
|
||||
Text(
|
||||
"💰 거래 기본 설정",
|
||||
@ -92,9 +95,16 @@ fun TradingDecisionLog() {
|
||||
// 저장 로직을 공통 함수로 분리
|
||||
val saveAction = {
|
||||
var newValue = localText.toDoubleOrNull() ?: 0.0
|
||||
var oldValue = KisSession.config.getValues(configKey)
|
||||
if (configKey.label.contains("PROFIT")) {
|
||||
newValue = newValue / KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)
|
||||
}
|
||||
if (firstSet.contains(configKey)) {
|
||||
TradingLogStore.addSettingLog(configKey.label,oldValue.toString(),newValue.toString(),"💾 저장됨: ${configKey.label} = $newValue")
|
||||
} else {
|
||||
firstSet.add(configKey)
|
||||
}
|
||||
|
||||
KisSession.config.setValues(configKey, newValue)
|
||||
DatabaseFactory.saveConfig(KisSession.config)
|
||||
println("💾 저장됨: ${configKey.label} = $newValue")
|
||||
@ -173,11 +183,16 @@ fun TradingDecisionLog() {
|
||||
}
|
||||
|
||||
val saveAction = {
|
||||
var oldValue = KisSession.config.getValues(configKey)
|
||||
var newValue = localText.toDoubleOrNull() ?: 0.0
|
||||
//
|
||||
KisSession.config.setValues(configKey, newValue)
|
||||
DatabaseFactory.saveConfig(KisSession.config)
|
||||
println("💾 저장됨: ${configKey.label} = $newValue")
|
||||
if (firstSet.contains(configKey)) {
|
||||
TradingLogStore.addSettingLog(configKey.label,oldValue.toString(),newValue.toString(),"💾 저장됨: ${configKey.label} = $newValue")
|
||||
} else {
|
||||
firstSet.add(configKey)
|
||||
}
|
||||
labelText = if (configKey.name.contains("PROFIT")) {
|
||||
getRemaining(configKey.label,common) + ": 기준율(${KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)}) * 성향별 비율(${KisSession.config.getValues(configKey)}) + 세금제비용(${KisSession.config.getValues(
|
||||
ConfigIndex.TAX_INDEX)}) = ${(localText.toDouble() * KisSession.config.getValues(ConfigIndex.PROFIT_INDEX)) + KisSession.config.getValues(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user