...
This commit is contained in:
parent
91f9e4ee9a
commit
5c088414c5
@ -123,11 +123,16 @@ data class UnifiedBalance(
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class UnfilledOrder(
|
data class UnfilledOrder(
|
||||||
val orgn_odno: String,
|
val orgn_odno: String,
|
||||||
@SerialName("odno") val ord_no: String, // JSON의 odno를 ord_no로 매핑
|
@SerialName("odno")
|
||||||
|
val ord_no: String, // JSON의 odno를 ord_no로 매핑
|
||||||
val pdno: String,
|
val pdno: String,
|
||||||
@SerialName("prdt_name") val prdt_name: String,
|
@SerialName("prdt_name")
|
||||||
|
val prdt_name: String,
|
||||||
val ord_unpr: String, // JSON이 문자열이므로 String 권장
|
val ord_unpr: String, // JSON이 문자열이므로 String 권장
|
||||||
@SerialName("psbl_qty") val rmnd_qty: String, // JSON의 psbl_qty를 rmnd_qty로 매핑
|
val ord_qty : String,
|
||||||
|
|
||||||
|
@SerialName("psbl_qty")
|
||||||
|
val rmnd_qty: String, // JSON의 psbl_qty를 rmnd_qty로 매핑
|
||||||
val ord_dvsn_name: String,
|
val ord_dvsn_name: String,
|
||||||
val rvse_cncl_dvsn_name: String
|
val rvse_cncl_dvsn_name: String
|
||||||
)
|
)
|
||||||
@ -145,7 +150,7 @@ fun UnfilledOrder.toAutoTradeItem(isDomestic: Boolean): AutoTradeItem {
|
|||||||
code = this.pdno,
|
code = this.pdno,
|
||||||
name = this.prdt_name,
|
name = this.prdt_name,
|
||||||
orderedPrice = this.ord_unpr.toDoubleOrNull() ?: 0.0,
|
orderedPrice = this.ord_unpr.toDoubleOrNull() ?: 0.0,
|
||||||
quantity = 0, // 미체결 내역에서는 원 주문 수량을 알기 어려우므로 0 또는 별도 처리
|
quantity = this.ord_qty.toIntOrNull() ?: 0, // 미체결 내역에서는 원 주문 수량을 알기 어려우므로 0 또는 별도 처리
|
||||||
remainedQuantity = this.rmnd_qty.toIntOrNull() ?: 0,
|
remainedQuantity = this.rmnd_qty.toIntOrNull() ?: 0,
|
||||||
status = "PENDING_BUY", // 기본적으로 미체결은 매수/매도 대기 상태
|
status = "PENDING_BUY", // 기본적으로 미체결은 매수/매도 대기 상태
|
||||||
isDomestic = isDomestic
|
isDomestic = isDomestic
|
||||||
|
|||||||
@ -79,7 +79,13 @@ class KisWebSocketManager {
|
|||||||
))
|
))
|
||||||
if (tradeLogs.size > 50) tradeLogs.removeLast()
|
if (tradeLogs.size > 50) tradeLogs.removeLast()
|
||||||
}
|
}
|
||||||
"H0STT084R" -> onExecutionReceived?.invoke(dataRows[5], dataRows[9], dataRows[12], dataRows[13], dataRows[15] == "02")
|
"H0STT084R" -> {
|
||||||
|
println("채결 데이터")
|
||||||
|
onExecutionReceived?.invoke(dataRows[5], dataRows[9], dataRows[12], dataRows[13], dataRows[15] == "02")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
println("쓰레기? ${trId}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun clearData() {
|
fun clearData() {
|
||||||
|
|||||||
@ -33,17 +33,32 @@ fun AutoTradeSection(
|
|||||||
var tradeList by remember { mutableStateOf(emptyList<AutoTradeItem>()) }
|
var tradeList by remember { mutableStateOf(emptyList<AutoTradeItem>()) }
|
||||||
// refreshTrigger가 바뀔 때마다 실행됨
|
// refreshTrigger가 바뀔 때마다 실행됨
|
||||||
LaunchedEffect(refreshTrigger) {
|
LaunchedEffect(refreshTrigger) {
|
||||||
|
// 1. 서버에서 실제 미체결 내역 가져오기
|
||||||
val serverUnfilled = tradeService.fetchUnfilledOrders().getOrNull()?.map { it.toAutoTradeItem(isDomestic) } ?: emptyList()
|
val serverUnfilled = tradeService.fetchUnfilledOrders().getOrNull()?.map { it.toAutoTradeItem(isDomestic) } ?: emptyList()
|
||||||
|
|
||||||
// 2. DB에서 로컬 감시 데이터 가져오기
|
// 2. DB에서 로컬 감시 데이터 가져오기
|
||||||
val localTrades = DatabaseFactory.getActiveAutoTrades()
|
val localTrades = DatabaseFactory.getActiveAutoTrades()
|
||||||
|
|
||||||
// 3. 동기화 로직: 서버에 없는 주문번호를 가진 로컬 데이터는 EXPIRED로 표시
|
// 3. 리스트 병합 및 동기화
|
||||||
tradeList = localTrades.map { local ->
|
val mergedList = mutableListOf<AutoTradeItem>()
|
||||||
if (local.status != "COMPLETED" && serverUnfilled.none { it.orderNo == local.orderNo }) {
|
|
||||||
local.copy(status = "EXPIRED")
|
// (A) DB에 있는 항목 처리
|
||||||
} else local
|
localTrades.forEach { local ->
|
||||||
|
val serverMatch = serverUnfilled.find { it.orderNo == local.orderNo }
|
||||||
|
if (local.status != "COMPLETED" && serverMatch == null) {
|
||||||
|
// 서버에 없으면 만료 처리
|
||||||
|
mergedList.add(local.copy(status = "EXPIRED"))
|
||||||
|
} else {
|
||||||
|
// 서버에 있으면 그대로 표시 (필요시 잔량 등 업데이트)
|
||||||
|
mergedList.add(local.copy(remainedQuantity = serverMatch?.remainedQuantity ?: 0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (B) 서버에는 있지만 DB에는 없는 항목(수동 주문 등) 추가
|
||||||
|
val manualOrders = serverUnfilled.filter { server -> localTrades.none { it.orderNo == server.orderNo } }
|
||||||
|
mergedList.addAll(manualOrders.map { it.copy(status = "MANUAL_ORDER") }) // 수동 주문 상태 등으로 표시
|
||||||
|
|
||||||
|
tradeList = mergedList
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize().padding(8.dp)) {
|
Column(modifier = Modifier.fillMaxSize().padding(8.dp)) {
|
||||||
|
|||||||
@ -61,9 +61,25 @@ fun DashboardScreen() {
|
|||||||
if (dbItem != null) {
|
if (dbItem != null) {
|
||||||
when (dbItem.status) {
|
when (dbItem.status) {
|
||||||
TradeStatus.PENDING_BUY -> {
|
TradeStatus.PENDING_BUY -> {
|
||||||
// 매수 주문 체결 -> 감시(MONITORING)로 전환 및 익절 주문 발주
|
// 1. 매수 주문 체결 확인됨 -> 즉시 익절 매도 주문 발주
|
||||||
// 여기서 익절 주문 후 받은 신규 주문번호를 DB에 갱신
|
println("✅ 매수 체결 확인 [${dbItem.name}]: 익절가 ${dbItem.targetPrice}로 매도 주문을 생성합니다.")
|
||||||
// updateStatusAndOrderNo(dbItem.id!!, TradeStatus.MONITORING, newSellOrderNo)
|
tradeService.postOrder(
|
||||||
|
stockCode = dbItem.code,
|
||||||
|
qty = dbItem.quantity.toString(),
|
||||||
|
price = dbItem.targetPrice.toLong().toString(), // 가격은 정수형 문자열로 전달
|
||||||
|
isBuy = false
|
||||||
|
).onSuccess { newSellOrderNo ->
|
||||||
|
// 2. 매도 주문 성공 시 DB 상태를 SELLING으로 변경하고 새로운 주문번호로 갱신
|
||||||
|
DatabaseFactory.updateStatusAndOrderNo(
|
||||||
|
id = dbItem.id!!,
|
||||||
|
newStatus = TradeStatus.SELLING,
|
||||||
|
newOrderNo = newSellOrderNo
|
||||||
|
)
|
||||||
|
println("🚀 익절 매도 주문 완료: 주문번호 $newSellOrderNo")
|
||||||
|
refreshTrigger++ // UI 갱신
|
||||||
|
}.onFailure {
|
||||||
|
println("❌ 매수 체결 후 익절 주문 발주 실패: ${it.message}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TradeStatus.SELLING -> {
|
TradeStatus.SELLING -> {
|
||||||
// 매도(손절/익절) 주문 체결 -> COMPLETED
|
// 매도(손절/익절) 주문 체결 -> COMPLETED
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user