161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
"""
|
|
db/models.py - SQLite 스키마 생성
|
|
기획서 v2.1 기준 4개 테이블
|
|
"""
|
|
import sqlite3
|
|
import os
|
|
|
|
DB_PATH = os.getenv("DB_PATH", "data/stockbot.db")
|
|
|
|
def _ensure_columns(cursor, table: str, columns: dict[str, str]):
|
|
existing = {row[1] for row in cursor.execute(f"PRAGMA table_info({table})").fetchall()}
|
|
for name, ddl in columns.items():
|
|
if name not in existing:
|
|
cursor.execute(f"ALTER TABLE {table} ADD COLUMN {name} {ddl}")
|
|
|
|
def init_db():
|
|
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
# 체결 내역
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS trades (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
date TEXT NOT NULL,
|
|
ticker TEXT NOT NULL,
|
|
name TEXT,
|
|
entry_time TEXT NOT NULL,
|
|
exit_time TEXT,
|
|
entry_price REAL NOT NULL,
|
|
exit_price REAL,
|
|
quantity INTEGER NOT NULL,
|
|
side TEXT NOT NULL,
|
|
exit_reason TEXT,
|
|
pnl REAL,
|
|
fee REAL,
|
|
slippage REAL,
|
|
strategy TEXT DEFAULT 'VB',
|
|
ai_boosted INTEGER DEFAULT 0
|
|
)""")
|
|
|
|
# 일일 요약
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS daily_summary (
|
|
date TEXT PRIMARY KEY,
|
|
total_trades INTEGER DEFAULT 0,
|
|
win_trades INTEGER DEFAULT 0,
|
|
lose_trades INTEGER DEFAULT 0,
|
|
gross_pnl REAL DEFAULT 0,
|
|
total_fee REAL DEFAULT 0,
|
|
net_pnl REAL DEFAULT 0,
|
|
max_drawdown REAL DEFAULT 0,
|
|
trading_stopped INTEGER DEFAULT 0
|
|
)""")
|
|
|
|
# 포지션 (장중 현황)
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS positions (
|
|
ticker TEXT PRIMARY KEY,
|
|
name TEXT,
|
|
entry_time TEXT,
|
|
entry_price REAL,
|
|
quantity INTEGER,
|
|
tp1_done INTEGER DEFAULT 0,
|
|
target_price REAL,
|
|
stop_price REAL,
|
|
ai_boosted INTEGER DEFAULT 0
|
|
)""")
|
|
|
|
# AI 판단 이력
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS ai_context_log (
|
|
date TEXT PRIMARY KEY,
|
|
generated_at TEXT,
|
|
trade_allowed INTEGER,
|
|
market_sentiment TEXT,
|
|
sentiment_score INTEGER,
|
|
risk_level TEXT,
|
|
hot_sectors TEXT,
|
|
avoid_sectors TEXT,
|
|
boosted_tickers TEXT,
|
|
blacklist_tickers TEXT,
|
|
position_size_mult REAL,
|
|
reason TEXT,
|
|
claude_tokens_used INTEGER,
|
|
api_call_success INTEGER DEFAULT 1
|
|
)""")
|
|
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS entry_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
trade_id INTEGER,
|
|
date TEXT NOT NULL,
|
|
ticker TEXT NOT NULL,
|
|
name TEXT,
|
|
entry_time TEXT NOT NULL,
|
|
current_price REAL,
|
|
entry_price REAL,
|
|
target_price REAL,
|
|
stop_price REAL,
|
|
today_open REAL,
|
|
prev_high REAL,
|
|
prev_low REAL,
|
|
prev_amount REAL,
|
|
volume REAL,
|
|
change_pct REAL,
|
|
market_sentiment TEXT,
|
|
sentiment_score INTEGER,
|
|
risk_level TEXT,
|
|
trade_allowed INTEGER,
|
|
hot_sectors TEXT,
|
|
avoid_sectors TEXT,
|
|
boosted_tickers TEXT,
|
|
blacklist_tickers TEXT,
|
|
ai_boosted INTEGER DEFAULT 0,
|
|
ai_win_score REAL,
|
|
ai_stop_loss_score REAL,
|
|
ai_model_version TEXT,
|
|
position_size_multiplier REAL,
|
|
combined_multiplier REAL,
|
|
entry_reason TEXT,
|
|
strategy TEXT DEFAULT 'VB',
|
|
created_at TEXT NOT NULL
|
|
)""")
|
|
c.execute("CREATE INDEX IF NOT EXISTS idx_entry_snapshots_trade_id ON entry_snapshots(trade_id)")
|
|
c.execute("CREATE INDEX IF NOT EXISTS idx_entry_snapshots_date_ticker ON entry_snapshots(date, ticker)")
|
|
_ensure_columns(c, "entry_snapshots", {
|
|
"ai_win_score": "REAL",
|
|
"ai_stop_loss_score": "REAL",
|
|
"ai_model_version": "TEXT",
|
|
})
|
|
|
|
c.execute("""
|
|
CREATE TABLE IF NOT EXISTS post_entry_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
trade_id INTEGER,
|
|
date TEXT NOT NULL,
|
|
ticker TEXT NOT NULL,
|
|
sample_time TEXT NOT NULL,
|
|
elapsed_sec INTEGER NOT NULL,
|
|
entry_price REAL,
|
|
current_price REAL,
|
|
return_pct REAL,
|
|
mfe_pct REAL,
|
|
mae_pct REAL,
|
|
volume REAL,
|
|
change_pct REAL,
|
|
position_open INTEGER DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
UNIQUE(trade_id, elapsed_sec)
|
|
)""")
|
|
c.execute("CREATE INDEX IF NOT EXISTS idx_post_entry_snapshots_trade_id ON post_entry_snapshots(trade_id)")
|
|
c.execute("CREATE INDEX IF NOT EXISTS idx_post_entry_snapshots_date_ticker ON post_entry_snapshots(date, ticker)")
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
print(f"DB 초기화 완료: {DB_PATH}")
|
|
|
|
def get_conn():
|
|
return sqlite3.connect(DB_PATH)
|