Files
StockRadar/internal/db/db.go
T
2026-04-20 21:29:22 +02:00

140 lines
4.5 KiB
Go

package db
import (
"database/sql"
_ "modernc.org/sqlite" // à la place de go-sqlite3
)
type DB struct {
*sql.DB
}
func Init(path string) (*DB, error) {
sqldb, err := sql.Open("sqlite", path) // "sqlite" au lieu de "sqlite3"
if err != nil {
return nil, err
}
if err := sqldb.Ping(); err != nil {
return nil, err
}
database := &DB{sqldb}
if err := database.migrate(); err != nil {
return nil, err
}
return database, nil
}
func (db *DB) migrate() error {
queries := []string{
`CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
encrypted INTEGER DEFAULT 0,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS watchlist (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL UNIQUE,
name TEXT,
sector TEXT,
exchange TEXT,
active INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS instruments (
instrument_id INTEGER PRIMARY KEY,
ticker TEXT NOT NULL,
name TEXT,
sector_id INTEGER,
exchange_id INTEGER,
asset_class_id INTEGER,
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS news (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT,
headline TEXT NOT NULL,
source TEXT,
url TEXT,
sentiment TEXT,
published_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
date DATE NOT NULL,
open REAL,
high REAL,
low REAL,
close REAL,
volume INTEGER,
UNIQUE(ticker, date)
)`,
`CREATE TABLE IF NOT EXISTS signals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL UNIQUE,
price REAL,
change_pct REAL,
rsi14 REAL,
macd REAL,
macd_signal REAL,
macd_hist REAL,
sma20 REAL,
sma50 REAL,
volume INTEGER,
avg_volume20 INTEGER,
alert TEXT DEFAULT '',
computed_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS insider_trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ticker TEXT NOT NULL,
insider_name TEXT,
insider_title TEXT,
transaction_code TEXT,
shares REAL,
price REAL,
total_value REAL,
transaction_date DATE,
accession_no TEXT UNIQUE,
filing_url TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE INDEX IF NOT EXISTS idx_insider_ticker ON insider_trades(ticker)`,
}
for _, q := range queries {
if _, err := db.Exec(q); err != nil {
return err
}
}
// Migrations additives — on ignore les erreurs si la colonne/index existe déjà
additive := []string{
`ALTER TABLE news ADD COLUMN finnhub_id INTEGER`,
`CREATE UNIQUE INDEX IF NOT EXISTS idx_news_finnhub_id ON news(finnhub_id) WHERE finnhub_id IS NOT NULL`,
`ALTER TABLE signals ADD COLUMN market_cap INTEGER DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN short_ratio REAL DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN score INTEGER DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN on_etoro INTEGER DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN week52_high REAL DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN week52_low REAL DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN pct_from_high REAL DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN insider_value_30d REAL DEFAULT 0`,
`ALTER TABLE signals ADD COLUMN source TEXT DEFAULT 'watchlist'`,
`CREATE INDEX IF NOT EXISTS idx_instruments_ticker ON instruments(ticker)`,
`CREATE INDEX IF NOT EXISTS idx_signals_score ON signals(score DESC)`,
`CREATE INDEX IF NOT EXISTS idx_signals_source ON signals(source)`,
}
for _, q := range additive {
db.Exec(q) // intentionnellement sans vérification d'erreur
}
return nil
}