189 lines
6.1 KiB
PL/PgSQL
189 lines
6.1 KiB
PL/PgSQL
-- 트레이딩 규칙 테이블
|
|
CREATE TABLE IF NOT EXISTS trading_rules (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
rule_type VARCHAR(50) NOT NULL,
|
|
conditions JSONB NOT NULL,
|
|
actions JSONB NOT NULL,
|
|
is_active BOOLEAN DEFAULT true,
|
|
priority INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 거래 이력 테이블
|
|
CREATE TABLE IF NOT EXISTS trade_history (
|
|
id SERIAL PRIMARY KEY,
|
|
rule_id INTEGER REFERENCES trading_rules(id),
|
|
stock_code VARCHAR(20) NOT NULL,
|
|
stock_name VARCHAR(100),
|
|
order_type VARCHAR(20) NOT NULL, -- BUY, SELL
|
|
order_price DECIMAL(15, 2),
|
|
order_quantity INTEGER NOT NULL,
|
|
executed_price DECIMAL(15, 2),
|
|
executed_quantity INTEGER,
|
|
status VARCHAR(50) NOT NULL, -- PENDING, EXECUTED, FAILED, CANCELLED
|
|
order_id VARCHAR(100),
|
|
message TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
executed_at TIMESTAMP
|
|
);
|
|
|
|
-- 포트폴리오 테이블
|
|
CREATE TABLE IF NOT EXISTS portfolio (
|
|
id SERIAL PRIMARY KEY,
|
|
stock_code VARCHAR(20) NOT NULL UNIQUE,
|
|
stock_name VARCHAR(100),
|
|
quantity INTEGER NOT NULL DEFAULT 0,
|
|
average_price DECIMAL(15, 2),
|
|
current_price DECIMAL(15, 2),
|
|
profit_loss DECIMAL(15, 2),
|
|
profit_loss_rate DECIMAL(10, 4),
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 시장 데이터 캐시 테이블
|
|
CREATE TABLE IF NOT EXISTS market_data (
|
|
id SERIAL PRIMARY KEY,
|
|
stock_code VARCHAR(20) NOT NULL,
|
|
price DECIMAL(15, 2) NOT NULL,
|
|
change_rate DECIMAL(10, 4),
|
|
volume BIGINT,
|
|
high_price DECIMAL(15, 2),
|
|
low_price DECIMAL(15, 2),
|
|
open_price DECIMAL(15, 2),
|
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(stock_code, timestamp)
|
|
);
|
|
|
|
-- 뉴스 테이블
|
|
CREATE TABLE IF NOT EXISTS news (
|
|
id SERIAL PRIMARY KEY,
|
|
title VARCHAR(500) NOT NULL,
|
|
content TEXT,
|
|
source VARCHAR(100),
|
|
url TEXT,
|
|
stock_codes TEXT[],
|
|
sentiment VARCHAR(20), -- POSITIVE, NEGATIVE, NEUTRAL
|
|
published_at TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Claude 분석 로그 테이블
|
|
CREATE TABLE IF NOT EXISTS claude_analysis_log (
|
|
id SERIAL PRIMARY KEY,
|
|
rule_id INTEGER REFERENCES trading_rules(id),
|
|
stock_code VARCHAR(20),
|
|
analysis_type VARCHAR(50), -- RULE_VALIDATION, MARKET_ANALYSIS, RISK_ASSESSMENT
|
|
input_data JSONB,
|
|
analysis_result JSONB,
|
|
decision VARCHAR(50),
|
|
confidence DECIMAL(5, 4),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- MCP 도구 호출 로그 테이블
|
|
CREATE TABLE IF NOT EXISTS mcp_tool_calls (
|
|
id SERIAL PRIMARY KEY,
|
|
tool_name VARCHAR(100) NOT NULL,
|
|
parameters JSONB,
|
|
result JSONB,
|
|
status VARCHAR(50),
|
|
execution_time_ms INTEGER,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- 인덱스 생성
|
|
CREATE INDEX idx_trade_history_stock_code ON trade_history(stock_code);
|
|
CREATE INDEX idx_trade_history_created_at ON trade_history(created_at DESC);
|
|
CREATE INDEX idx_market_data_stock_code ON market_data(stock_code);
|
|
CREATE INDEX idx_market_data_timestamp ON market_data(timestamp DESC);
|
|
CREATE INDEX idx_news_published_at ON news(published_at DESC);
|
|
CREATE INDEX idx_claude_analysis_created_at ON claude_analysis_log(created_at DESC);
|
|
CREATE INDEX idx_mcp_tool_calls_created_at ON mcp_tool_calls(created_at DESC);
|
|
|
|
-- 기본 트레이딩 규칙 샘플 삽입
|
|
INSERT INTO trading_rules (name, description, rule_type, conditions, actions, is_active, priority) VALUES
|
|
(
|
|
'기본 매수 규칙',
|
|
'RSI 30 이하이고 거래량이 평균보다 높을 때 매수',
|
|
'BUY',
|
|
'{"rsi_below": 30, "volume_above_average": 1.5}'::jsonb,
|
|
'{"order_type": "BUY", "quantity_percent": 10, "max_amount": 1000000}'::jsonb,
|
|
true,
|
|
10
|
|
),
|
|
(
|
|
'손절매 규칙',
|
|
'손실률 -5% 이하일 때 자동 매도',
|
|
'SELL',
|
|
'{"loss_rate_below": -5}'::jsonb,
|
|
'{"order_type": "SELL", "quantity_percent": 100}'::jsonb,
|
|
true,
|
|
100
|
|
),
|
|
(
|
|
'익절 규칙',
|
|
'수익률 15% 이상일 때 50% 매도',
|
|
'SELL',
|
|
'{"profit_rate_above": 15}'::jsonb,
|
|
'{"order_type": "SELL", "quantity_percent": 50}'::jsonb,
|
|
true,
|
|
90
|
|
);
|
|
|
|
-- 업데이트 트리거 함수
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END;
|
|
$$ language 'plpgsql';
|
|
|
|
-- 업데이트 트리거 생성
|
|
CREATE TRIGGER update_trading_rules_updated_at BEFORE UPDATE ON trading_rules
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
CREATE TRIGGER update_portfolio_updated_at BEFORE UPDATE ON portfolio
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- =============================
|
|
-- 배치 종목 분석 캐시 테이블
|
|
-- 매일 아침 batch_daily_analysis.py로 채워짐
|
|
-- =============================
|
|
CREATE TABLE IF NOT EXISTS stock_analysis (
|
|
id SERIAL PRIMARY KEY,
|
|
stock_code VARCHAR(20) NOT NULL,
|
|
stock_name VARCHAR(100) NOT NULL,
|
|
analysis_date DATE NOT NULL,
|
|
current_price INTEGER NOT NULL,
|
|
change_rate DECIMAL(10,4),
|
|
volume BIGINT,
|
|
rsi DECIMAL(10,4),
|
|
ma5 DECIMAL(15,2),
|
|
ma20 DECIMAL(15,2),
|
|
ma60 DECIMAL(15,2),
|
|
stochastic_k DECIMAL(10,4),
|
|
stochastic_d DECIMAL(10,4),
|
|
bollinger_upper DECIMAL(15,2),
|
|
bollinger_lower DECIMAL(15,2),
|
|
bollinger_middle DECIMAL(15,2),
|
|
signals JSONB, -- ["RSI 과매도", "골든크로스"]
|
|
score INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_stock_analysis_stock_code ON stock_analysis(stock_code);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_analysis_analysis_date ON stock_analysis(analysis_date);
|
|
CREATE INDEX IF NOT EXISTS idx_stock_analysis_score_desc ON stock_analysis(score DESC);
|
|
|
|
-- UPSERT (ON CONFLICT) 동작을 위한 unique constraint (batch_daily/intraday UPSERT 필수)
|
|
ALTER TABLE stock_analysis
|
|
ADD CONSTRAINT uq_stock_analysis_code_date UNIQUE (stock_code, analysis_date);
|
|
|
|
CREATE TRIGGER update_stock_analysis_updated_at BEFORE UPDATE ON stock_analysis
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|