Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b1d334a6cd | |||
| 93907c2dac | |||
| acd1b13760 | |||
| 81ce68e07b | |||
| 95f43e105d |
@ -103,6 +103,32 @@ 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 {
|
||||
val tradesByStock = trades.groupBy { it.stockCode }
|
||||
|
||||
@ -60,6 +60,7 @@ object TradingReportManager : TradingReportService {
|
||||
|
||||
override fun recordAssetSnapshot(type: SnapshotType, balance: UnifiedBalance, remark: String?) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
println("❌ [Report] 리포트 비동기 생성 중 오류 발생: gggg")
|
||||
val todayDate = LocalDate.now().toString()
|
||||
|
||||
// 1. 중복 없는 전체 종목 코드 리스트 추출
|
||||
@ -229,7 +230,7 @@ object TradingReportManager : TradingReportService {
|
||||
}
|
||||
|
||||
// 6. 코루틴 기반 제너레이터 호출
|
||||
LocalReportGenerator.generateAndOpenAsync(summaryData, holdingLogs, tradeLogs)
|
||||
LocalReportGenerator.generateAndOpenAsyncDirectly(summaryData, holdingLogs, tradeLogs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,15 +538,21 @@ object AutoTradingManager {
|
||||
isBuy = false,
|
||||
).onSuccess { newOrderNo ->
|
||||
println("✅ [보유 주식 손절 처리] 수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도.")
|
||||
TradingLogStore.addSellLog(
|
||||
holding.code,
|
||||
targetPrice.toString(),
|
||||
"SELL",
|
||||
"☠️ 보유 주식 손절 처리 [수익률 : ${profit}%] ${holding.valuationProfitAmount} 손해 중이며 현시세{${holding.currentPrice}}로 기준 호가 위 매도[$targetPrice] 주문 완료"
|
||||
)
|
||||
}.onFailure { err->
|
||||
println("✅ [보유 주식 손절 처리] 실패 ${err.message}")
|
||||
}
|
||||
|
||||
TradingLogStore.addNotice(
|
||||
"보유주식[${holding.name}]",
|
||||
holding.code,
|
||||
"수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도."
|
||||
)
|
||||
// TradingLogStore.addNotice(
|
||||
// "보유주식[${holding.name}]",
|
||||
// holding.code,
|
||||
// "수익률($profit%) -> ${holding.valuationProfitAmount} 손해 중이며 현제 손절 가이드에 적합함 시장가 매도."
|
||||
// )
|
||||
}
|
||||
analyzeDeepLossHoldingsAfterMarket(holding , true)
|
||||
}
|
||||
@ -762,14 +768,14 @@ object AutoTradingManager {
|
||||
suspend fun checkBalance(isMorning: Boolean = true) {
|
||||
if (isMorning) {
|
||||
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, ""
|
||||
)
|
||||
}
|
||||
}
|
||||
// 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, ""
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
if (KisSession.config.take_profit) currentBalance?.let { resumePendingSellOrders(KisTradeService, it) }
|
||||
if (KisSession.tradeConfig.auto_cancel_pending_buy) { checkAndCancelPendingBuyOrders() }
|
||||
|
||||
@ -50,9 +50,13 @@ import model.KisSession
|
||||
import network.KisTradeService
|
||||
import network.NewsService
|
||||
import network.StockUniverseLoader
|
||||
import report.SnapshotType
|
||||
import report.TradingReportManager
|
||||
import service.AutoTradingManager
|
||||
import service.AutoTradingManager.currentBalance
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.time.LocalTime
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
@ -105,14 +109,34 @@ fun TradingDecisionLog() {
|
||||
|
||||
Row(modifier = Modifier.fillMaxSize().background(Color(0xFFF2F2F2))) {
|
||||
Column(modifier = Modifier.weight(1f).padding(8.dp).fillMaxHeight().background(Color.White)) {
|
||||
Button(
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
// index 0으로 부드럽게 스크롤 (즉시 이동은 scrollToItem(0))
|
||||
listState.animateScrollToItem(filteredLogs.size - 1)
|
||||
Row(modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
// index 0으로 부드럽게 스크롤 (즉시 이동은 scrollToItem(0))
|
||||
listState.animateScrollToItem(if (filteredLogs.size - 1 >= 0) filteredLogs.size - 1 else 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
) { 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(
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
|
||||
@ -224,9 +248,9 @@ fun TradingDecisionLog() {
|
||||
Text(
|
||||
text = log.decision,
|
||||
color = when (log.decision) {
|
||||
"BUY" -> Color.Red
|
||||
"BUY" -> Color(0xFF800080)
|
||||
"SETTING" -> Color(0xFFFFA500)
|
||||
"SELL" -> Color(0xFF800080)
|
||||
"SELL" -> if (log.reason.contains("손절 처리")) Color.Blue else Color.Red
|
||||
"HOLD" -> Color.DarkGray
|
||||
"ANALYZER" -> Color.Green
|
||||
"PASS" -> Color.Yellow
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user