Some checks failed
Build Push and Restart Compose / deploy (push) Failing after 1m47s
- `github.com/lib/pq` PostgreSQL 드라이버 vendor 디렉토리에 추가. - PostgreSQL 관련 내부 패키지(`pqsql`, `proto`, `pqtime`, `pgpass`, `pgservice`, `pqutil`) 구현: - SQL 어휘 처리, 프로토콜 상수 및 구조 정의, 시간 파서/포맷터(`Parse`, `Format`). - `.pgpass` 파일 및 `pg_service.conf` 관리 기능 추가. - 파일/사용자 권한 검증 및 플랫폼별 사용자 정보 조회 기능 포함. - 데이터베이스 초기화 로직 추가 (`services/db.go`): - PostgreSQL 연결 설정 및 초기 스키마 생성. - 자동매매 관련 DB 레포지토리(`services/autotrade_repo.go`) 구현: - 자동매매 규칙 및 포지션 관리 로직 추가 (`dbInsertRule`, `dbLoadRules` 등).
102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
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)
|
|
}
|
|
}
|