first commit
This commit is contained in:
148
handlers/autotrade_handler.go
Normal file
148
handlers/autotrade_handler.go
Normal file
@@ -0,0 +1,148 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user