Compare commits

..

No commits in common. "acd1b137601fdcebe6d8068fbc3bbda37b5fb531" and "619407966ef9670bd3ae0be5452f8620f86b7bf1" have entirely different histories.

4 changed files with 24 additions and 81 deletions

View File

@ -103,32 +103,6 @@ object LocalReportGenerator {
} }
} }
fun generateAndOpenAsyncDirectly(
summary: RawSummaryData,
rawHoldings: List<RawHoldingData>,
rawTrades: List<RawTradeData>
) {
reportScope.launch {
try {
// 1. [핵심] 대시보드 통계 지표 추출 (Generator가 직접 계산)
val stats = calculateDashboardStats(rawHoldings, rawTrades)
// 2. 탭 2 & 3 HTML 가공
val holdingsHtml = processHoldings(rawHoldings)
val tradesHtml = processTrades(rawTrades)
// 3. 전체 HTML 조립
val htmlContent = buildHtml(summary, stats, holdingsHtml, tradesHtml)
if (summary.type.equals("END", true) || summary.type.equals("MIDDLE", true)) {
saveAndOpen(summary.type, htmlContent)
}
} catch (e: Exception) {
println("❌ [Report] 리포트 비동기 생성 중 오류 발생: ${e.message}")
e.printStackTrace()
}
}
}
// --- [새로운 통계 계산 로직] --- // --- [새로운 통계 계산 로직] ---
private fun calculateDashboardStats(holdings: List<RawHoldingData>, trades: List<RawTradeData>): DashboardStats { private fun calculateDashboardStats(holdings: List<RawHoldingData>, trades: List<RawTradeData>): DashboardStats {
val tradesByStock = trades.groupBy { it.stockCode } val tradesByStock = trades.groupBy { it.stockCode }

View File

@ -60,7 +60,6 @@ object TradingReportManager : TradingReportService {
override fun recordAssetSnapshot(type: SnapshotType, balance: UnifiedBalance, remark: String?) { override fun recordAssetSnapshot(type: SnapshotType, balance: UnifiedBalance, remark: String?) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
println("❌ [Report] 리포트 비동기 생성 중 오류 발생: gggg")
val todayDate = LocalDate.now().toString() val todayDate = LocalDate.now().toString()
// 1. 중복 없는 전체 종목 코드 리스트 추출 // 1. 중복 없는 전체 종목 코드 리스트 추출
@ -230,7 +229,7 @@ object TradingReportManager : TradingReportService {
} }
// 6. 코루틴 기반 제너레이터 호출 // 6. 코루틴 기반 제너레이터 호출
LocalReportGenerator.generateAndOpenAsyncDirectly(summaryData, holdingLogs, tradeLogs) LocalReportGenerator.generateAndOpenAsync(summaryData, holdingLogs, tradeLogs)
} }
} }
} }

View File

@ -538,21 +538,15 @@ object AutoTradingManager {
isBuy = false, isBuy = false,
).onSuccess { newOrderNo -> ).onSuccess { newOrderNo ->
println("✅ [보유 주식 손절 처리] 수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도.") println("✅ [보유 주식 손절 처리] 수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도.")
TradingLogStore.addSellLog(
holding.code,
targetPrice.toString(),
"SELL",
"☠️ 보유 주식 손절 처리 [수익률 : ${profit}%] ${holding.valuationProfitAmount} 손해 중이며 현시세{${holding.currentPrice}}로 기준 호가 위 매도[$targetPrice] 주문 완료"
)
}.onFailure { err-> }.onFailure { err->
println("✅ [보유 주식 손절 처리] 실패 ${err.message}") println("✅ [보유 주식 손절 처리] 실패 ${err.message}")
} }
// TradingLogStore.addNotice( TradingLogStore.addNotice(
// "보유주식[${holding.name}]", "보유주식[${holding.name}]",
// holding.code, holding.code,
// "수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도." "수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도."
// ) )
} }
analyzeDeepLossHoldingsAfterMarket(holding , true) analyzeDeepLossHoldingsAfterMarket(holding , true)
} }
@ -767,15 +761,15 @@ object AutoTradingManager {
var myOredsAndBalanceCodes : MutableSet<String> = mutableSetOf() var myOredsAndBalanceCodes : MutableSet<String> = mutableSetOf()
suspend fun checkBalance(isMorning: Boolean = true) { suspend fun checkBalance(isMorning: Boolean = true) {
if (isMorning) { if (isMorning) {
// currentBalance = KisTradeService.fetchIntegratedBalance().getOrNull() currentBalance = KisTradeService.fetchIntegratedBalance().getOrNull()
// currentBalance?.let { currentBalance -> currentBalance?.let { currentBalance ->
// if (LocalTime.now().isBefore(LocalTime.of(18,1))) { if (LocalTime.now().isBefore(LocalTime.of(18,1))) {
// TradingReportManager.recordAssetSnapshot( TradingReportManager.recordAssetSnapshot(
// if (LocalTime.now().isAfter(LocalTime.of(18, 0)) if (LocalTime.now().isAfter(LocalTime.of(18, 0))
// ) SnapshotType.END else SnapshotType.MIDDLE, currentBalance, "" ) SnapshotType.END else SnapshotType.MIDDLE, currentBalance, ""
// ) )
// } }
// } }
if (KisSession.config.take_profit) currentBalance?.let { resumePendingSellOrders(KisTradeService, it) } if (KisSession.config.take_profit) currentBalance?.let { resumePendingSellOrders(KisTradeService, it) }
if (KisSession.tradeConfig.auto_cancel_pending_buy) { checkAndCancelPendingBuyOrders() } if (KisSession.tradeConfig.auto_cancel_pending_buy) { checkAndCancelPendingBuyOrders() }

View File

@ -50,13 +50,9 @@ import model.KisSession
import network.KisTradeService import network.KisTradeService
import network.NewsService import network.NewsService
import network.StockUniverseLoader import network.StockUniverseLoader
import report.SnapshotType
import report.TradingReportManager
import service.AutoTradingManager import service.AutoTradingManager
import service.AutoTradingManager.currentBalance
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import java.time.LocalTime
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@ -109,34 +105,14 @@ fun TradingDecisionLog() {
Row(modifier = Modifier.fillMaxSize().background(Color(0xFFF2F2F2))) { Row(modifier = Modifier.fillMaxSize().background(Color(0xFFF2F2F2))) {
Column(modifier = Modifier.weight(1f).padding(8.dp).fillMaxHeight().background(Color.White)) { Column(modifier = Modifier.weight(1f).padding(8.dp).fillMaxHeight().background(Color.White)) {
Row(modifier = Modifier.fillMaxWidth(), Button(
horizontalArrangement = Arrangement.spacedBy(4.dp), onClick = {
) { coroutineScope.launch {
Button( // index 0으로 부드럽게 스크롤 (즉시 이동은 scrollToItem(0))
onClick = { listState.animateScrollToItem(filteredLogs.size - 1)
coroutineScope.launch {
// index 0으로 부드럽게 스크롤 (즉시 이동은 scrollToItem(0))
listState.animateScrollToItem(filteredLogs.size - 1)
}
} }
) { Text("AI 자동매매 실시간 로그", style = MaterialTheme.typography.h6) } }
) { Text("AI 자동매매 실시간 로그", style = MaterialTheme.typography.h6) }
Button(
onClick = {
coroutineScope.launch {
currentBalance = KisTradeService.fetchIntegratedBalance().getOrNull()
currentBalance?.let { currentBalance ->
if (LocalTime.now().isBefore(LocalTime.of(18,1))) {
TradingReportManager.recordAssetSnapshot(
if (LocalTime.now().isAfter(LocalTime.of(18, 0))
) SnapshotType.END else SnapshotType.MIDDLE, currentBalance, ""
)
}
}
}
}
) { Text("Open the report", style = MaterialTheme.typography.body2) }
}
Row( Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
@ -248,9 +224,9 @@ fun TradingDecisionLog() {
Text( Text(
text = log.decision, text = log.decision,
color = when (log.decision) { color = when (log.decision) {
"BUY" -> Color(0xFF800080) "BUY" -> Color.Red
"SETTING" -> Color(0xFFFFA500) "SETTING" -> Color(0xFFFFA500)
"SELL" -> if (log.reason.contains("손절 처리")) Color.Blue else Color.Red "SELL" -> Color(0xFF800080)
"HOLD" -> Color.DarkGray "HOLD" -> Color.DarkGray
"ANALYZER" -> Color.Green "ANALYZER" -> Color.Green
"PASS" -> Color.Yellow "PASS" -> Color.Yellow