Some checks failed
Build Push and Restart Compose / deploy (push) Failing after 11m20s
- `/templates/pages/asset.html`, `/templates/pages/autotrade.html` HTML 템플릿 삭제. - `/static/js/asset.js`, `/static/js/autotrade.js` 클라이언트 스크립트 제거. - 관련 함수 및 초기화 로직 삭제 (자산 조회 및 자동매매 기능 비활성화).
144 lines
5.9 KiB
Go
144 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"stocksearch/config"
|
|
"stocksearch/handlers"
|
|
"stocksearch/middleware"
|
|
"stocksearch/models"
|
|
"stocksearch/services"
|
|
ws "stocksearch/websocket"
|
|
)
|
|
|
|
func main() {
|
|
// 환경변수 로딩
|
|
config.Load()
|
|
|
|
// PostgreSQL 초기화 (DATABASE_URL 미설정 시 메모리 모드)
|
|
services.InitDB()
|
|
|
|
// 키움증권 토큰 발급 (서버 시작 시 즉시 실행)
|
|
tokenSvc := services.GetTokenService()
|
|
if err := tokenSvc.Start(); err != nil {
|
|
log.Fatalf("토큰 발급 실패: %v\n키움증권 API 키를 .env 파일에 설정해주세요.", err)
|
|
}
|
|
|
|
// 체결강도 상승 감지 스캐너 시작 (08:00 KST 이후 10초 주기)
|
|
services.GetScannerService().Start()
|
|
|
|
// 종목 리스트 백그라운드 로딩 (검색용)
|
|
services.GetSearchService().Load()
|
|
|
|
// WebSocket Hub 시작 (내부에서 키움 WS 클라이언트 초기화)
|
|
hub := ws.NewHub()
|
|
go hub.Run()
|
|
|
|
// 키움 WS 실시간 연결 시작 (Hub 이벤트 루프 실행 후)
|
|
if err := hub.StartKiwoomWS(); err != nil {
|
|
log.Printf("키움 WS 초기 연결 실패: %v (자동 재연결 시도)", err)
|
|
}
|
|
|
|
// 서비스 추가
|
|
sessionSvc := services.GetSessionService()
|
|
watchlistSvc := services.GetWatchlistService()
|
|
autoTradeSvc := services.GetAutoTradeService()
|
|
|
|
// 스캐너 구독 종목 → WebSocket 내부 구독 연결
|
|
services.GetScannerService().SetSubscribeCallback(func(codes []string) {
|
|
hub.SubscribeInternal(codes)
|
|
})
|
|
|
|
// 자동매매 로그 → WebSocket 브로드캐스트 연결
|
|
autoTradeSvc.SetLogBroadcaster(func(l models.AutoTradeLog) {
|
|
hub.BroadcastTradeLog(l)
|
|
})
|
|
|
|
// 핸들러 초기화
|
|
stockHandler := handlers.NewStockHandler(watchlistSvc)
|
|
wsHandler := handlers.NewWSHandler(hub)
|
|
authHandler := handlers.NewAuthHandler(sessionSvc)
|
|
orderHandler := handlers.NewOrderHandler()
|
|
autoTradeHandler := handlers.NewAutoTradeHandler(autoTradeSvc)
|
|
|
|
// 라우터 설정 (Go 1.22 패턴 매칭)
|
|
mux := http.NewServeMux()
|
|
|
|
// --- 인증 라우트 ---
|
|
mux.HandleFunc("POST /login", authHandler.Login)
|
|
mux.HandleFunc("POST /logout", authHandler.Logout)
|
|
mux.HandleFunc("GET /api/auth/check", authHandler.CheckSession)
|
|
|
|
// --- REST API 라우트 ---
|
|
mux.HandleFunc("GET /api/stock/{code}", stockHandler.GetCurrentPrice)
|
|
mux.HandleFunc("GET /api/stock/{code}/chart", stockHandler.GetDailyChart)
|
|
mux.HandleFunc("GET /api/scanner/status", stockHandler.GetScannerStatus)
|
|
mux.HandleFunc("POST /api/scanner/toggle", stockHandler.ToggleScanner)
|
|
mux.HandleFunc("GET /api/signal", stockHandler.GetSignals)
|
|
mux.HandleFunc("GET /api/watchlist-signal", stockHandler.GetWatchlistSignals)
|
|
mux.HandleFunc("GET /api/indices", stockHandler.GetIndices)
|
|
mux.HandleFunc("GET /api/search", stockHandler.Search)
|
|
mux.HandleFunc("GET /api/disclosure", stockHandler.GetDisclosures)
|
|
mux.HandleFunc("GET /api/news", stockHandler.GetNews)
|
|
mux.HandleFunc("GET /api/kospi200", stockHandler.GetKospi200)
|
|
mux.HandleFunc("GET /api/themes", stockHandler.GetThemes)
|
|
mux.HandleFunc("GET /api/themes/{code}", stockHandler.GetThemeStocks)
|
|
mux.HandleFunc("GET /api/watchlist", stockHandler.GetWatchlist)
|
|
mux.HandleFunc("POST /api/watchlist", stockHandler.AddWatchlist)
|
|
mux.HandleFunc("DELETE /api/watchlist/{code}", stockHandler.RemoveWatchlist)
|
|
|
|
// --- 주문/계좌 API 라우트 ---
|
|
mux.HandleFunc("POST /api/order/buy", orderHandler.Buy)
|
|
mux.HandleFunc("POST /api/order/sell", orderHandler.Sell)
|
|
mux.HandleFunc("PUT /api/order/modify", orderHandler.Modify)
|
|
mux.HandleFunc("DELETE /api/order", orderHandler.Cancel)
|
|
mux.HandleFunc("GET /api/account/balance", orderHandler.GetBalance)
|
|
mux.HandleFunc("GET /api/account/pending", orderHandler.GetPending)
|
|
mux.HandleFunc("GET /api/account/history", orderHandler.GetHistory)
|
|
mux.HandleFunc("GET /api/account/deposit", orderHandler.GetDeposit)
|
|
mux.HandleFunc("GET /api/account/orderable", orderHandler.GetOrderable)
|
|
|
|
// --- 자동매매 API 라우트 ---
|
|
mux.HandleFunc("GET /api/autotrade/status", autoTradeHandler.GetStatus)
|
|
mux.HandleFunc("GET /api/autotrade/rules", autoTradeHandler.GetRules)
|
|
mux.HandleFunc("POST /api/autotrade/rules", autoTradeHandler.AddRule)
|
|
mux.HandleFunc("PUT /api/autotrade/rules/{id}", autoTradeHandler.UpdateRule)
|
|
mux.HandleFunc("DELETE /api/autotrade/rules/{id}", autoTradeHandler.DeleteRule)
|
|
mux.HandleFunc("POST /api/autotrade/rules/{id}/toggle", autoTradeHandler.ToggleRule)
|
|
mux.HandleFunc("GET /api/autotrade/positions", autoTradeHandler.GetPositions)
|
|
mux.HandleFunc("GET /api/autotrade/trades", autoTradeHandler.GetTrades)
|
|
mux.HandleFunc("GET /api/autotrade/logs", autoTradeHandler.GetLogs)
|
|
mux.HandleFunc("GET /api/autotrade/watch-source", autoTradeHandler.GetWatchSource)
|
|
mux.HandleFunc("PUT /api/autotrade/watch-source", autoTradeHandler.SetWatchSource)
|
|
mux.HandleFunc("POST /api/autotrade/start", autoTradeHandler.Start)
|
|
mux.HandleFunc("POST /api/autotrade/stop", autoTradeHandler.Stop)
|
|
mux.HandleFunc("POST /api/autotrade/emergency", autoTradeHandler.Emergency)
|
|
mux.HandleFunc("POST /api/autotrade/positions/{code}/close", autoTradeHandler.ClosePosition)
|
|
|
|
// --- WebSocket 라우트 ---
|
|
mux.HandleFunc("GET /ws", wsHandler.ServeWS)
|
|
|
|
// --- SvelteKit 빌드 정적 서빙 (SPA fallback 포함) ---
|
|
if _, err := os.Stat("frontend/build"); err == nil {
|
|
spa := http.FileServer(http.Dir("frontend/build"))
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
path := "frontend/build" + r.URL.Path
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
http.ServeFile(w, r, "frontend/build/index.html")
|
|
return
|
|
}
|
|
spa.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// 미들웨어 체인 적용 (CORS → Auth → Logger → Recovery 순)
|
|
handler := middleware.Chain(mux, middleware.Recovery, middleware.Logger, middleware.Auth(sessionSvc), middleware.CORS)
|
|
|
|
addr := "0.0.0.0:" + config.App.ServerPort
|
|
log.Printf("서버 시작: http://%s", addr)
|
|
if err := http.ListenAndServe(addr, handler); err != nil {
|
|
log.Fatalf("서버 실행 실패: %v", err)
|
|
}
|
|
}
|