atrade/src/main/kotlin/ui/IntegratedOrderSection.kt

142 lines
6.4 KiB
Kotlin
Raw Normal View History

2026-01-14 15:42:26 +09:00
// src/main/kotlin/ui/IntegratedOrderSection.kt
package ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
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.launch
import network.KisTradeService
@Composable
fun IntegratedOrderSection(
stockCode: String,
currentPrice: String,
tradeService: KisTradeService,
onOrderResult: (String, Boolean) -> Unit
) {
val scope = rememberCoroutineScope()
var orderQty by remember { mutableStateOf("1") }
var orderPrice by remember { mutableStateOf("") } // 빈 값이면 시장가
// 자동 매도 설정
var isAutoSellEnabled by remember { mutableStateOf(false) }
var profitRate by remember { mutableStateOf("5.0") }
var stopLossRate by remember { mutableStateOf("-3.0") }
val basePrice = (if (orderPrice.isEmpty()) currentPrice.replace(",", "") else orderPrice).toDoubleOrNull() ?: 0.0
val qty = orderQty.toDoubleOrNull() ?: 0.0
Column(modifier = Modifier.fillMaxWidth().padding(8.dp)) {
Text("주문 및 자동 매도 설정", style = MaterialTheme.typography.subtitle2, fontWeight = FontWeight.Bold)
// 1. 가격 및 수량 입력
Row(modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)) {
OutlinedTextField(
value = orderQty,
onValueChange = { if (it.all { c -> c.isDigit() }) orderQty = it },
label = { Text("수량") },
modifier = Modifier.weight(1f).padding(end = 4.dp)
)
OutlinedTextField(
value = orderPrice,
onValueChange = { if (it.all { c -> c.isDigit() }) orderPrice = it },
label = { Text("가격") },
placeholder = { Text("시장가 (${currentPrice})") },
modifier = Modifier.weight(1f)
)
}
// 2. 수익률 시뮬레이션 표 (신규 추가)
if (basePrice > 0 && qty > 0) {
Text("익절/손절 시뮬레이션 (수수료/세금 약 0.22% 반영)", fontSize = 11.sp, color = Color.Gray, modifier = Modifier.padding(bottom = 4.dp))
Card(backgroundColor = Color(0xFFF1F3F5), shape = RoundedCornerShape(4.dp), elevation = 0.dp) {
Column(modifier = Modifier.padding(8.dp)) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
SimulationColumn("수익률", listOf("+5%", "+3%", "+1%", "-1%", "-3%", "-5%"), true)
SimulationColumn("목표가", listOf(1.05, 1.03, 1.01, 0.99, 0.97, 0.95).map { (basePrice * it).toLong().toString() }, false)
SimulationColumn("예상수령액", listOf(1.05, 1.03, 1.01, 0.99, 0.97, 0.95).map { rate ->
val sellPrice = basePrice * rate
val totalAmount = sellPrice * qty
val netAmount = totalAmount * (1 - 0.0022) // 수수료+세금 약 0.22% 차감
String.format("%,d", netAmount.toLong())
}, false)
}
}
}
}
Spacer(modifier = Modifier.height(12.dp))
// 3. 자동 매도 옵션
Card(backgroundColor = Color(0xFFF8F9FA), elevation = 0.dp) {
Column(modifier = Modifier.padding(8.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(checked = isAutoSellEnabled, onCheckedChange = { isAutoSellEnabled = it })
Text("매수 체결 시 자동 매도 감시 시작", fontSize = 12.sp)
}
if (isAutoSellEnabled) {
Row {
OutlinedTextField(
value = profitRate, onValueChange = { profitRate = it },
label = { Text("익절 %") }, modifier = Modifier.weight(1f).padding(end = 4.dp)
)
OutlinedTextField(
value = stopLossRate, onValueChange = { stopLossRate = it },
label = { Text("손절 %") }, modifier = Modifier.weight(1f)
)
}
}
}
}
Spacer(modifier = Modifier.height(12.dp))
// 4. 매수/매도 버튼
Row(modifier = Modifier.fillMaxWidth()) {
Button(
onClick = {
scope.launch {
val finalPrice = if (orderPrice.isBlank()) "0" else orderPrice
tradeService.postOrder(stockCode, orderQty, finalPrice, isBuy = true)
.onSuccess {
onOrderResult(it, true)
if (isAutoSellEnabled) { /* 자동매도 등록 로직 호출 */ }
}
.onFailure { onOrderResult(it.message ?: "에러", false) }
}
},
modifier = Modifier.weight(1f).padding(end = 4.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFE03E2D))
) { Text("매수", color = Color.White) }
Button(
onClick = { /* 매도 로직동일 */ },
modifier = Modifier.weight(1f),
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFF0E62CF))
) { Text("매도", color = Color.White) }
}
}
}
@Composable
fun SimulationColumn(title: String, items: List<String>, isHeader: Boolean) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(title, fontSize = 10.sp, fontWeight = FontWeight.Bold, color = Color.DarkGray)
items.forEach { text ->
Text(
text = text,
fontSize = 11.sp,
color = if (text.contains("+")) Color(0xFFE03E2D) else if (text.contains("-")) Color(0xFF0E62CF) else Color.Black,
modifier = Modifier.padding(vertical = 1.dp)
)
}
}
}