package handlers import ( "encoding/json" "net/http" "stocksearch/services" ) // OrderHandler 주문/계좌 REST API 핸들러 type OrderHandler struct { orderSvc *services.OrderService accountSvc *services.AccountService } // NewOrderHandler 핸들러 초기화 func NewOrderHandler() *OrderHandler { return &OrderHandler{ orderSvc: services.GetOrderService(), accountSvc: services.GetAccountService(), } } // Buy POST /api/order/buy — 매수주문 (kt10000) func (h *OrderHandler) Buy(w http.ResponseWriter, r *http.Request) { var req services.OrderRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { jsonError(w, "요청 파싱 실패", http.StatusBadRequest) return } if req.Exchange == "" { req.Exchange = "KRX" } if req.TradeTP == "" { req.TradeTP = "0" } result, err := h.orderSvc.Buy(req) if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // Sell POST /api/order/sell — 매도주문 (kt10001) func (h *OrderHandler) Sell(w http.ResponseWriter, r *http.Request) { var req services.OrderRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { jsonError(w, "요청 파싱 실패", http.StatusBadRequest) return } if req.Exchange == "" { req.Exchange = "KRX" } if req.TradeTP == "" { req.TradeTP = "0" } result, err := h.orderSvc.Sell(req) if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // Modify PUT /api/order/modify — 정정주문 (kt10002) func (h *OrderHandler) Modify(w http.ResponseWriter, r *http.Request) { var req struct { Exchange string `json:"exchange"` OrigOrdNo string `json:"origOrdNo"` Code string `json:"code"` Qty string `json:"qty"` Price string `json:"price"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { jsonError(w, "요청 파싱 실패", http.StatusBadRequest) return } if req.Exchange == "" { req.Exchange = "KRX" } result, err := h.orderSvc.Modify(req.Exchange, req.OrigOrdNo, req.Code, req.Qty, req.Price) if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // Cancel DELETE /api/order — 취소주문 (kt10003) func (h *OrderHandler) Cancel(w http.ResponseWriter, r *http.Request) { var req struct { Exchange string `json:"exchange"` OrigOrdNo string `json:"origOrdNo"` Code string `json:"code"` Qty string `json:"qty"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { jsonError(w, "요청 파싱 실패", http.StatusBadRequest) return } if req.Exchange == "" { req.Exchange = "KRX" } if req.Qty == "" { req.Qty = "0" // 전량취소 } result, err := h.orderSvc.Cancel(req.Exchange, req.OrigOrdNo, req.Code, req.Qty) if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // GetBalance GET /api/account/balance — 계좌 잔고 (kt00018) func (h *OrderHandler) GetBalance(w http.ResponseWriter, r *http.Request) { result, err := h.accountSvc.GetBalance() if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // GetPending GET /api/account/pending — 미체결 주문 (ka10075) func (h *OrderHandler) GetPending(w http.ResponseWriter, r *http.Request) { orders, err := h.accountSvc.GetPendingOrders() if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } if orders == nil { orders = []services.PendingOrder{} } jsonOK(w, orders) } // GetHistory GET /api/account/history — 체결내역 (ka10076) func (h *OrderHandler) GetHistory(w http.ResponseWriter, r *http.Request) { history, err := h.accountSvc.GetOrderHistory() if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } if history == nil { history = []services.OrderHistory{} } jsonOK(w, history) } // GetDeposit GET /api/account/deposit — 예수금 상세 조회 (kt00001) func (h *OrderHandler) GetDeposit(w http.ResponseWriter, r *http.Request) { result, err := h.accountSvc.GetDepositDetail() if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) } // GetOrderable GET /api/account/orderable?code=&price=&side= — 주문가능금액/수량 (kt00010) func (h *OrderHandler) GetOrderable(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") price := r.URL.Query().Get("price") side := r.URL.Query().Get("side") // buy 또는 sell if price == "" { price = "0" } // 키움 API: 1=매도, 2=매수 tradeTp := "2" if side == "sell" { tradeTp = "1" } result, err := h.accountSvc.GetOrderable(code, price, tradeTp) if err != nil { jsonError(w, err.Error(), http.StatusInternalServerError) return } jsonOK(w, result) }