package services import ( "database/sql" "log" "stocksearch/config" _ "github.com/lib/pq" ) var db *sql.DB // InitDB PostgreSQL 연결 초기화 및 스키마 생성 func InitDB() { dsn := config.App.DatabaseURL if dsn == "" { log.Println("DATABASE_URL 미설정 — DB 없이 메모리 모드로 동작") return } var err error db, err = sql.Open("postgres", dsn) if err != nil { log.Fatalf("DB 연결 실패: %v", err) } if err = db.Ping(); err != nil { log.Fatalf("DB ping 실패: %v", err) } db.SetMaxOpenConns(10) db.SetMaxIdleConns(5) createTables() log.Println("PostgreSQL 연결 완료") } // GetDB DB 인스턴스 반환 (nil이면 DB 미사용) func GetDB() *sql.DB { return db } func createTables() { schema := ` CREATE TABLE IF NOT EXISTS autotrade_rules ( id TEXT PRIMARY KEY, name TEXT NOT NULL, enabled BOOLEAN NOT NULL DEFAULT true, min_rise_score INTEGER NOT NULL DEFAULT 60, min_cntr_str REAL NOT NULL DEFAULT 110, require_bullish BOOLEAN NOT NULL DEFAULT false, order_amount BIGINT NOT NULL DEFAULT 1000000, max_positions INTEGER NOT NULL DEFAULT 3, stop_loss1_pct REAL NOT NULL DEFAULT -2.0, stop_loss1_count INTEGER NOT NULL DEFAULT 3, stop_loss_pct REAL NOT NULL DEFAULT -4.0, take_profit_pct REAL NOT NULL DEFAULT 5.0, max_hold_minutes INTEGER NOT NULL DEFAULT 60, exit_before_close BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS autotrade_positions ( id SERIAL PRIMARY KEY, code TEXT NOT NULL, name TEXT NOT NULL DEFAULT '', buy_price BIGINT NOT NULL DEFAULT 0, qty BIGINT NOT NULL DEFAULT 0, order_no TEXT NOT NULL DEFAULT '', entry_time TIMESTAMPTZ NOT NULL DEFAULT NOW(), rule_id TEXT NOT NULL DEFAULT '', stop_loss1 BIGINT NOT NULL DEFAULT 0, stop_loss1_touches INTEGER NOT NULL DEFAULT 0, stop_loss BIGINT NOT NULL DEFAULT 0, take_profit BIGINT NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'pending', exit_time TIMESTAMPTZ, exit_price BIGINT NOT NULL DEFAULT 0, exit_reason TEXT NOT NULL DEFAULT '' ); CREATE INDEX IF NOT EXISTS idx_positions_status ON autotrade_positions(status); CREATE INDEX IF NOT EXISTS idx_positions_exit_time ON autotrade_positions(exit_time); CREATE TABLE IF NOT EXISTS autotrade_logs ( id SERIAL PRIMARY KEY, at TIMESTAMPTZ NOT NULL DEFAULT NOW(), level TEXT NOT NULL DEFAULT 'info', message TEXT NOT NULL DEFAULT '', code TEXT NOT NULL DEFAULT '' ); CREATE INDEX IF NOT EXISTS idx_logs_at ON autotrade_logs(at); CREATE TABLE IF NOT EXISTS autotrade_watch_source ( id INTEGER PRIMARY KEY DEFAULT 1, use_scanner BOOLEAN NOT NULL DEFAULT true, selected_themes JSONB NOT NULL DEFAULT '[]' ); ` if _, err := db.Exec(schema); err != nil { log.Fatalf("스키마 생성 실패: %v", err) } }