feat(phase-0): scaffold backend + web + docker + DB schema
- docker-compose.yml: timescaledb-ha (timescaledb 2.27 + vectorscale + pgvector + pgai) + backend (FastAPI, CUDA 12.1) + web (Next.js 14) - docker-compose.gpu.yml: GPU profile overlay for RTX 3070 Ti - build.bat: Windows bootstrap, auto-detects nvidia-smi and selects GPU/CPU compose - backend: Dockerfile, pyproject.toml, FastAPI skeleton with /health and /health/db - DB migration 001_init.sql: symbols (with trigram search), ohlcv_daily/1m (hypertables), macro_daily, trading_value_daily, news (vector embedding), predictions (with user_triggered flag for on-demand UX), prediction_outcomes, model_performance - web: Next.js 14 + Tailwind + lightweight-charts placeholder - README: KIS/DART/HuggingFace token issuance guides + 10 seed tickers + run instructions
This commit is contained in:
139
backend/app/db/migrations/001_init.sql
Normal file
139
backend/app/db/migrations/001_init.sql
Normal file
@@ -0,0 +1,139 @@
|
||||
-- Init schema for stock_chart_site
|
||||
-- Loaded automatically on first DB container start via /docker-entrypoint-initdb.d
|
||||
|
||||
\set ON_ERROR_STOP on
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- 종목 마스터 (Phase 1 에서 KRX 전체 종목 시드. 검색은 name 또는 code 둘 다 지원)
|
||||
CREATE TABLE IF NOT EXISTS symbols (
|
||||
code TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
market TEXT NOT NULL, -- 'KOSPI' / 'KOSDAQ' / 'NASDAQ'
|
||||
sector TEXT,
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
is_seed BOOLEAN DEFAULT FALSE, -- 학습/배치 대상 10종목 여부
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS symbols_name_trgm ON symbols USING gin (name gin_trgm_ops);
|
||||
CREATE INDEX IF NOT EXISTS symbols_active ON symbols(active);
|
||||
|
||||
-- 일별 시세
|
||||
CREATE TABLE IF NOT EXISTS ohlcv_daily (
|
||||
code TEXT NOT NULL REFERENCES symbols(code),
|
||||
date DATE NOT NULL,
|
||||
open NUMERIC,
|
||||
high NUMERIC,
|
||||
low NUMERIC,
|
||||
close NUMERIC,
|
||||
volume BIGINT,
|
||||
PRIMARY KEY (code, date)
|
||||
);
|
||||
SELECT create_hypertable('ohlcv_daily', 'date', if_not_exists => TRUE);
|
||||
CREATE INDEX IF NOT EXISTS ohlcv_daily_code_date ON ohlcv_daily(code, date DESC);
|
||||
|
||||
-- 분봉 (M8 인트라데이용, 스키마만 미리 둔다)
|
||||
CREATE TABLE IF NOT EXISTS ohlcv_1m (
|
||||
code TEXT NOT NULL,
|
||||
ts TIMESTAMPTZ NOT NULL,
|
||||
open NUMERIC,
|
||||
high NUMERIC,
|
||||
low NUMERIC,
|
||||
close NUMERIC,
|
||||
volume BIGINT,
|
||||
PRIMARY KEY (code, ts)
|
||||
);
|
||||
SELECT create_hypertable('ohlcv_1m', 'ts', if_not_exists => TRUE);
|
||||
|
||||
-- 거시 / 환율 / 지수
|
||||
CREATE TABLE IF NOT EXISTS macro_daily (
|
||||
date DATE NOT NULL,
|
||||
key TEXT NOT NULL, -- 'kospi','kosdaq','usdkrw','us10y',...
|
||||
value NUMERIC,
|
||||
PRIMARY KEY (date, key)
|
||||
);
|
||||
|
||||
-- 외인 / 기관 순매수 (KRW 기준 거래대금)
|
||||
CREATE TABLE IF NOT EXISTS trading_value_daily (
|
||||
code TEXT NOT NULL REFERENCES symbols(code),
|
||||
date DATE NOT NULL,
|
||||
foreign_net NUMERIC,
|
||||
institution_net NUMERIC,
|
||||
individual_net NUMERIC,
|
||||
PRIMARY KEY (code, date)
|
||||
);
|
||||
|
||||
-- 뉴스 / 공시
|
||||
CREATE TABLE IF NOT EXISTS news (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code TEXT REFERENCES symbols(code),
|
||||
source TEXT NOT NULL, -- 'naver_finance' / 'dart' / 'google_rss'
|
||||
published_at TIMESTAMPTZ NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
url TEXT NOT NULL UNIQUE,
|
||||
body TEXT,
|
||||
sentiment_score REAL, -- KR-FinBERT 출력 -1..+1
|
||||
sentiment_label TEXT, -- 'positive' / 'neutral' / 'negative'
|
||||
embedding VECTOR(768),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS news_code_pub ON news(code, published_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS news_pub ON news(published_at DESC);
|
||||
|
||||
-- 모델 예측 이력
|
||||
-- user_triggered=TRUE 인 행만 다음날 outcomes 매칭/오차수정 학습에 사용
|
||||
CREATE TABLE IF NOT EXISTS predictions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code TEXT NOT NULL REFERENCES symbols(code),
|
||||
predicted_at TIMESTAMPTZ NOT NULL,
|
||||
base_date DATE NOT NULL, -- 예측 기준일(=마지막 관측일)
|
||||
target_date DATE NOT NULL,
|
||||
horizon INT NOT NULL, -- 1, 3, 5
|
||||
model TEXT NOT NULL, -- 'chronos2' / 'lgbm' / 'ensemble'
|
||||
direction TEXT, -- 'up' / 'flat' / 'down'
|
||||
prob_up REAL,
|
||||
prob_flat REAL,
|
||||
prob_down REAL,
|
||||
expected_return REAL,
|
||||
point_forecast NUMERIC, -- median 가격
|
||||
ci_low NUMERIC, -- quantile 10
|
||||
ci_high NUMERIC, -- quantile 90
|
||||
features_snapshot JSONB,
|
||||
user_triggered BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE (code, base_date, target_date, horizon, model)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS predictions_code_target ON predictions(code, target_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS predictions_user_triggered ON predictions(user_triggered) WHERE user_triggered = TRUE;
|
||||
|
||||
-- 예측 vs 실제 결과 (오차 수정 / 메트릭 / 가중치 튜닝의 입력)
|
||||
CREATE TABLE IF NOT EXISTS prediction_outcomes (
|
||||
prediction_id BIGINT PRIMARY KEY REFERENCES predictions(id) ON DELETE CASCADE,
|
||||
code TEXT NOT NULL REFERENCES symbols(code),
|
||||
target_date DATE NOT NULL,
|
||||
horizon INT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
predicted_close NUMERIC,
|
||||
actual_close NUMERIC,
|
||||
actual_return REAL,
|
||||
direction_hit BOOLEAN, -- 방향성 적중 여부
|
||||
abs_error REAL,
|
||||
resolved_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS po_code_target ON prediction_outcomes(code, target_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS po_model ON prediction_outcomes(model);
|
||||
|
||||
-- 모델별 롤링 성능 (앙상블 가중치 튜닝에 사용)
|
||||
CREATE TABLE IF NOT EXISTS model_performance (
|
||||
code TEXT NOT NULL REFERENCES symbols(code),
|
||||
model TEXT NOT NULL,
|
||||
window_days INT NOT NULL, -- 7, 30 등
|
||||
as_of DATE NOT NULL,
|
||||
hit_rate REAL,
|
||||
mae REAL,
|
||||
brier REAL,
|
||||
sample_count INT,
|
||||
PRIMARY KEY (code, model, window_days, as_of)
|
||||
);
|
||||
Reference in New Issue
Block a user