//package ui // // // //import network.TradingDecision //import androidx.compose.foundation.layout.* //import androidx.compose.material.* //import androidx.compose.runtime.* //// 아래 두 import가 'delegate' 에러를 해결합니다. //import androidx.compose.runtime.getValue //import androidx.compose.runtime.setValue //import androidx.compose.ui.Alignment //import androidx.compose.ui.Modifier //import androidx.compose.ui.graphics.Color //import androidx.compose.ui.text.font.FontWeight //import androidx.compose.ui.unit.dp //import androidx.compose.ui.unit.sp //import kotlinx.coroutines.coroutineScope //import kotlinx.coroutines.launch //import model.CandleData //import network.DartCodeManager //import network.KisTradeService //import network.KisWebSocketManager //import java.time.LocalTime //import java.time.format.DateTimeFormatter //import kotlin.collections.isNotEmpty // //@Composable //fun StockDetailSection( // stockCode: String, // stockName: String, // holdingQuantity: String, // isDomestic: Boolean, // tradeService: KisTradeService, // wsManager: KisWebSocketManager, // onOrderSaved: (String) -> Unit, // completeTradingDecision: TradingDecision?, // min30 : MutableList, // daySummary : MutableList, // weekSummary : MutableList, // monthSummary : MutableList, // yearSummary : MutableList //) { // //// var openPrice by remember { mutableStateOf("0") } // var chartData by remember { mutableStateOf>(emptyList()) } // var isLoading by remember { mutableStateOf(false) } // var resultMessage by remember { mutableStateOf("") } // var isSuccess by remember { mutableStateOf(true) } // // // val todayOpen = remember(daySummary) { // daySummary.lastOrNull()?.stck_oprc ?: "0" // } // val previousClose = remember(daySummary) { // if (daySummary.size >= 2) daySummary[daySummary.size - 2].stck_prpr else "0" // } // // // // // 이전 종목 코드를 기억하기 위한 상태 // var previousCode by remember { mutableStateOf("") } // var lastPrice by remember { mutableStateOf("0") } // // // // 종목 변경 시 데이터 로드 및 웹소켓 구독 관리 // LaunchedEffect(stockCode) { // if (stockCode.isEmpty()) return@LaunchedEffect // // isLoading = true // // // 1. 웹소켓 구독 관리: 이전 종목 해제 -> 새 종목 구독 // if (previousCode.isNotEmpty()) { // wsManager.unsubscribeStock(previousCode) // } // wsManager.clearData() // wsManager.subscribeStock(stockCode) // previousCode = stockCode // // // // 2. 차트 데이터 로드 (KisSession 기반으로 파라미터 간소화) // // coroutineScope { // launch { // wsManager.onPriceUpdate = {tradeLog -> // // // if (tradeLog.code.equals(stockCode)) { // val code = tradeLog.code // val price = tradeLog.price // wsManager.tradeLogs.add(tradeLog) // if (wsManager.tradeLogs.size > 50) wsManager.tradeLogs.removeLast() //// println("code $code ,price $price") // val currentPrice = price // if (chartData.isNotEmpty() && currentPrice != "0") { // val priceDouble = currentPrice.replace(",", "").toDoubleOrNull() ?: 0.0 // val lastCandle = chartData.last() // // // 현재 시간(분 단위) 확인 // val currentMinute = LocalTime.now().format(DateTimeFormatter.ofPattern("HHmm00")) // // if (lastCandle.stck_bsop_date != currentMinute) { // // [개선] 시간이 바뀌었으면 새로운 캔들 추가 (차트가 밀려나는 효과) // val newCandle = CandleData( // stck_bsop_date = currentMinute, // stck_oprc = currentPrice, // stck_hgpr = currentPrice, // stck_lwpr = currentPrice, // stck_prpr = currentPrice, // stck_cntg_hour = currentMinute, // cntg_vol = "1", // acml_tr_pbmn = "1", // ) // // 최대 100개까지만 유지하여 성능 최적화 // chartData = (chartData + newCandle).takeLast(100) // } else { // // 같은 분 내에서는 기존 마지막 캔들만 업데이트 // val updatedCandle = lastCandle.copy( // stck_prpr = currentPrice, // stck_hgpr = if (priceDouble > (lastCandle.stck_hgpr.toDoubleOrNull() ?: 0.0)) currentPrice else lastCandle.stck_hgpr, // stck_lwpr = if (priceDouble < (lastCandle.stck_lwpr.toDoubleOrNull() ?: Double.MAX_VALUE)) currentPrice else lastCandle.stck_lwpr // ) // chartData = chartData.dropLast(1) + updatedCandle // } // } // lastPrice = currentPrice // } // // } // } // launch {tradeService.fetchChartData(stockCode, isDomestic) // .onSuccess { data -> //// println("✅ 차트 데이터 로드 성공: ${data.size}개") // ${} 사용하여 정확히 출력 // chartData = data // min30.clear() // min30.addAll(chartData) // } // .onFailure { error -> //// println("❌ 차트 데이터 로드 실패: ${error.localizedMessage}") // chartData = emptyList() // } // } // launch { tradeService.fetchPeriodChartData(stockCode, "D").onSuccess { // daySummary.clear() // daySummary.addAll(it) // } // } // 최근 7일 // launch { tradeService.fetchPeriodChartData(stockCode, "W").onSuccess { // weekSummary.clear() // weekSummary.addAll(it.takeLast(4)) //// println("weekSummary ${weekSummary.size} total: ${it.size} ${it.firstOrNull()?.toString()}") // } // } // 최근 4주 // launch { tradeService.fetchPeriodChartData(stockCode, "M").onSuccess { // monthSummary.clear() // monthSummary.addAll(it.takeLast(6)) // yearSummary.clear() // yearSummary.addAll(it.takeLast(36)) // } // } // launch { // DartCodeManager.getCorpCode(stockCode)?.let { // it.stockName = stockName //// NewsService.fetchAndIngestNews(it) // } // } // } // isLoading = false // } // // // //// LaunchedEffect(latestPrice) { //// println("latestPrice >>> $latestPrice") //// if (chartData.isNotEmpty() && latestPrice != "0") { //// val latestPrice = latestPrice ?: "0" //// val priceDouble = latestPrice?.replace(",", "")?.toDoubleOrNull() ?: return@LaunchedEffect //// val lastCandle = chartData.last() //// //// // 현재 시간(분 단위) 확인 //// val currentMinute = LocalTime.now().format(DateTimeFormatter.ofPattern("HHmm00")) //// //// if (lastCandle.stck_bsop_date != currentMinute) { //// // [개선] 시간이 바뀌었으면 새로운 캔들 추가 (차트가 밀려나는 효과) //// val newCandle = CandleData( //// stck_bsop_date = currentMinute, //// stck_oprc = latestPrice, //// stck_hgpr = latestPrice, //// stck_lwpr = latestPrice, //// stck_prpr = latestPrice, //// stck_cntg_hour = currentMinute, //// cntg_vol = "1", //// acml_tr_pbmn = "1", //// ) //// // 최대 100개까지만 유지하여 성능 최적화 //// chartData = (chartData + newCandle).takeLast(100) //// } else { //// // 같은 분 내에서는 기존 마지막 캔들만 업데이트 //// val updatedCandle = lastCandle.copy( //// stck_prpr = latestPrice, //// stck_hgpr = if (priceDouble > (lastCandle.stck_hgpr.toDoubleOrNull() ?: 0.0)) latestPrice else lastCandle.stck_hgpr, //// stck_lwpr = if (priceDouble < (lastCandle.stck_lwpr.toDoubleOrNull() ?: Double.MAX_VALUE)) latestPrice else lastCandle.stck_lwpr //// ) //// chartData = chartData.dropLast(1) + updatedCandle //// } //// } //// } // // Column(modifier = Modifier.fillMaxSize().padding(16.dp)) { // // [상단] 종목명 및 상태 메시지 // Row( // modifier = Modifier.fillMaxWidth(), // horizontalArrangement = Arrangement.SpaceBetween, // verticalAlignment = Alignment.CenterVertically // ) { // StockHeader( // name = stockName, // code = stockCode, // isDomestic = isDomestic, // previousClose = previousClose, // openPrice = lastPrice, // resultMessage = resultMessage, // resultMessageClear = {resultMessage = ""}, // isSuccess = isSuccess // ) // // // 실시간 가격 표시 (WebSocket 데이터) // Column(horizontalAlignment = Alignment.End) { // Text( // text = "${lastPrice} 원", // style = MaterialTheme.typography.h4, // fontWeight = FontWeight.Bold, // color = if (lastPrice?.contains("-") ?: false) Color.Blue else Color.Red // ) // Text("실시간 체결가", style = MaterialTheme.typography.caption, color = Color.Gray) // } // } // // 통합된 트렌드 카드 배치 // Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) { // PeriodTrendCard("7일", daySummary, Modifier.weight(1f)) // PeriodTrendCard("4주", weekSummary, Modifier.weight(1f)) // PeriodTrendCard("6개월", monthSummary, Modifier.weight(1f)) // PeriodTrendCard("3년", yearSummary, Modifier.weight(1f)) // } // // Spacer(modifier = Modifier.height(4.dp)) // // [중앙] 캔들 차트 (Card 내부) // Card( // modifier = Modifier.fillMaxWidth().height(320.dp), // backgroundColor = Color(0xFF121212) // ) { // if (isLoading) { // Box(contentAlignment = Alignment.Center) { CircularProgressIndicator(color = Color.White) } // } else { // CandleChart(data = chartData, modifier = Modifier.padding(16.dp)) // } // } // // Spacer(modifier = Modifier.height(4.dp)) // // // // // [하단] 실시간 체결 내역 및 주문 섹션 // Row(modifier = Modifier.weight(1f)) { // // 실시간 체결 리스트 // Column(modifier = Modifier.weight(1f)) { // Text("실시간 체결", style = MaterialTheme.typography.subtitle2, fontWeight = FontWeight.Bold) // RealTimeTradeList(wsManager.tradeLogs) // } // // Spacer(modifier = Modifier.width(12.dp)) // // // 주문 섹션 (인자 간소화) // Column(modifier = Modifier.weight(0.6f)) { // IntegratedOrderSection( // stockCode = stockCode, // stockName = stockName, // isDomestic = isDomestic, // currentPrice = lastPrice, // holdingQuantity = holdingQuantity, // tradeService = tradeService, // onOrderSaved = onOrderSaved, // onOrderResult = { msg, success -> // resultMessage = msg // isSuccess = success // }, // completeTradingDecision // ) // } // } // } //} // //@Composable //fun PeriodSummaryCard(label: String, avgPrice: String, modifier: Modifier = Modifier) { // Card(modifier = modifier, elevation = 2.dp, backgroundColor = Color.White) { // Column(modifier = Modifier.padding(8.dp), horizontalAlignment = Alignment.CenterHorizontally) { // Text(label, fontSize = 10.sp, color = Color.Gray) // Text(text = "${avgPrice}원", fontSize = 13.sp, fontWeight = FontWeight.Bold, color = Color.Black) // } // } //}