package handlers import ( "encoding/json" "net/http" "stocksearch/models" "stocksearch/services" ) // AutoTradeHandler 자동매매 REST API 핸들러 type AutoTradeHandler struct { svc *services.AutoTradeService } // NewAutoTradeHandler 핸들러 초기화 func NewAutoTradeHandler(svc *services.AutoTradeService) *AutoTradeHandler { return &AutoTradeHandler{svc: svc} } // GetStatus GET /api/autotrade/status — 엔진 상태 + 오늘 통계 func (h *AutoTradeHandler) GetStatus(w http.ResponseWriter, r *http.Request) { tradeCount, totalPL := h.svc.GetStats() activePositions := 0 for _, p := range h.svc.GetPositions() { if p.Status == "pending" || p.Status == "open" { activePositions++ } } jsonResponse(w, map[string]interface{}{ "running": h.svc.IsRunning(), "activePositions": activePositions, "tradeCount": tradeCount, "totalPL": totalPL, }) } // GetRules GET /api/autotrade/rules — 규칙 목록 func (h *AutoTradeHandler) GetRules(w http.ResponseWriter, r *http.Request) { jsonResponse(w, h.svc.GetRules()) } // AddRule POST /api/autotrade/rules — 규칙 추가 func (h *AutoTradeHandler) AddRule(w http.ResponseWriter, r *http.Request) { var rule models.AutoTradeRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { http.Error(w, "요청 파싱 실패", http.StatusBadRequest) return } created := h.svc.AddRule(rule) w.WriteHeader(http.StatusCreated) jsonResponse(w, created) } // UpdateRule PUT /api/autotrade/rules/{id} — 규칙 수정 func (h *AutoTradeHandler) UpdateRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var rule models.AutoTradeRule if err := json.NewDecoder(r.Body).Decode(&rule); err != nil { http.Error(w, "요청 파싱 실패", http.StatusBadRequest) return } if !h.svc.UpdateRule(id, rule) { http.Error(w, "규칙을 찾을 수 없습니다", http.StatusNotFound) return } jsonResponse(w, map[string]bool{"ok": true}) } // DeleteRule DELETE /api/autotrade/rules/{id} — 규칙 삭제 func (h *AutoTradeHandler) DeleteRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if !h.svc.DeleteRule(id) { http.Error(w, "규칙을 찾을 수 없습니다", http.StatusNotFound) return } jsonResponse(w, map[string]bool{"ok": true}) } // ToggleRule POST /api/autotrade/rules/{id}/toggle — 규칙 ON/OFF func (h *AutoTradeHandler) ToggleRule(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") ok, enabled := h.svc.ToggleRule(id) if !ok { http.Error(w, "규칙을 찾을 수 없습니다", http.StatusNotFound) return } jsonResponse(w, map[string]bool{"enabled": enabled}) } // GetPositions GET /api/autotrade/positions — 포지션 목록 func (h *AutoTradeHandler) GetPositions(w http.ResponseWriter, r *http.Request) { jsonResponse(w, h.svc.GetPositions()) } // GetLogs GET /api/autotrade/logs — 최근 로그 (?level=action 이면 debug 제외) func (h *AutoTradeHandler) GetLogs(w http.ResponseWriter, r *http.Request) { logs := h.svc.GetLogs() if r.URL.Query().Get("level") == "action" { filtered := logs[:0:0] for _, l := range logs { if l.Level != "debug" { filtered = append(filtered, l) } } logs = filtered } jsonResponse(w, logs) } // GetWatchSource GET /api/autotrade/watch-source — 감시 소스 조회 func (h *AutoTradeHandler) GetWatchSource(w http.ResponseWriter, r *http.Request) { jsonResponse(w, h.svc.GetWatchSource()) } // SetWatchSource PUT /api/autotrade/watch-source — 감시 소스 설정 func (h *AutoTradeHandler) SetWatchSource(w http.ResponseWriter, r *http.Request) { var ws models.AutoTradeWatchSource if err := json.NewDecoder(r.Body).Decode(&ws); err != nil { http.Error(w, "요청 파싱 실패", http.StatusBadRequest) return } h.svc.SetWatchSource(ws) jsonResponse(w, map[string]bool{"ok": true}) } // Start POST /api/autotrade/start — 엔진 시작 func (h *AutoTradeHandler) Start(w http.ResponseWriter, r *http.Request) { h.svc.Start() jsonResponse(w, map[string]bool{"running": true}) } // Stop POST /api/autotrade/stop — 엔진 중지 func (h *AutoTradeHandler) Stop(w http.ResponseWriter, r *http.Request) { h.svc.Stop() jsonResponse(w, map[string]bool{"running": false}) } // Emergency POST /api/autotrade/emergency — 긴급 전량 청산 func (h *AutoTradeHandler) Emergency(w http.ResponseWriter, r *http.Request) { h.svc.EmergencyStop() jsonResponse(w, map[string]bool{"ok": true}) } // jsonResponse JSON 응답 헬퍼 func jsonResponse(w http.ResponseWriter, data interface{}) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(data) }