187 lines
4.8 KiB
Go
187 lines
4.8 KiB
Go
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)
|
|
}
|