.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,7 +5,6 @@ build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
upbit_db_init.py
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
|
||||
226
upbit_db_init.py
Normal file
226
upbit_db_init.py
Normal file
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
upbit_db_init.py — upbit_quant_db MariaDB 테이블 초기화 스크립트
|
||||
=================================================================
|
||||
실행: python3 upbit_db_init.py
|
||||
- 필요한 테이블이 없으면 생성 (IF NOT EXISTS → 재실행 안전)
|
||||
- env_config에 초기 기본값 row 삽입
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pymysql
|
||||
import pymysql.cursors
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(message)s", datefmt="%H:%M:%S")
|
||||
logger = logging.getLogger("UpbitDBInit")
|
||||
|
||||
DB_CFG = dict(
|
||||
host="192.168.0.141",
|
||||
port=3306,
|
||||
user="jae",
|
||||
password="1234",
|
||||
database="upbit_quant_db",
|
||||
charset="utf8mb4",
|
||||
autocommit=True,
|
||||
cursorclass=pymysql.cursors.DictCursor,
|
||||
connect_timeout=10,
|
||||
)
|
||||
|
||||
DDL_STATEMENTS = [
|
||||
# ── 1. 현재 보유 포지션 ──────────────────────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS active_trades (
|
||||
code VARCHAR(20) NOT NULL PRIMARY KEY COMMENT '마켓코드 (KRW-BTC)',
|
||||
name VARCHAR(50) COMMENT '종목명',
|
||||
strategy VARCHAR(50) COMMENT '전략명',
|
||||
avg_buy_price DECIMAL(20,8) COMMENT '평균 매수가',
|
||||
current_price DECIMAL(20,8) COMMENT '현재가',
|
||||
stop_price DECIMAL(20,8) COMMENT '손절가',
|
||||
target_price DECIMAL(20,8) COMMENT '목표가',
|
||||
max_price DECIMAL(20,8) COMMENT '보유 중 최고가 (트레일링스탑용)',
|
||||
atr_entry DECIMAL(20,8) COMMENT '진입 시점 ATR (변동성)',
|
||||
target_qty DECIMAL(30,10) COMMENT '목표 수량',
|
||||
current_qty DECIMAL(30,10) COMMENT '현재 수량',
|
||||
total_invested DECIMAL(20,2) COMMENT '총 투자금액 (원)',
|
||||
status VARCHAR(20) DEFAULT 'HOLDING' COMMENT '상태 (HOLDING)',
|
||||
buy_date DATETIME COMMENT '매수 시각',
|
||||
updated_at DATETIME COMMENT '최종 업데이트',
|
||||
rsi DECIMAL(8,4) COMMENT '진입 시 RSI',
|
||||
volume_ratio DECIMAL(8,4) COMMENT '거래량 비율',
|
||||
tail_length_pct DECIMAL(8,4) COMMENT '꼬리 길이 (%)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='현재 보유 포지션'
|
||||
""",
|
||||
|
||||
# ── 2. 매매 기록 ────────────────────────────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS trade_history (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
code VARCHAR(20) COMMENT '마켓코드',
|
||||
name VARCHAR(50) COMMENT '종목명',
|
||||
strategy VARCHAR(50) COMMENT '전략명',
|
||||
buy_price DECIMAL(20,8) COMMENT '매수가',
|
||||
sell_price DECIMAL(20,8) COMMENT '매도가',
|
||||
qty DECIMAL(30,10) COMMENT '거래 수량',
|
||||
profit_rate DECIMAL(10,4) COMMENT '수익률 (%)',
|
||||
realized_pnl DECIMAL(20,2) COMMENT '실현 손익 (원)',
|
||||
hold_minutes INT COMMENT '보유 시간 (분)',
|
||||
buy_date DATETIME COMMENT '매수 시각',
|
||||
sell_date DATETIME COMMENT '매도 시각',
|
||||
sell_reason VARCHAR(200) COMMENT '매도 사유',
|
||||
rsi DECIMAL(8,4) COMMENT '진입 시 RSI',
|
||||
volume_ratio DECIMAL(8,4) COMMENT '거래량 비율',
|
||||
tail_length_pct DECIMAL(8,4) COMMENT '꼬리 길이 (%)',
|
||||
INDEX idx_sell_date (sell_date),
|
||||
INDEX idx_code (code),
|
||||
INDEX idx_strategy (strategy)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='매매 기록'
|
||||
""",
|
||||
|
||||
# ── 3. 전략 설정값 (Upbit 전용) ──────────────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS env_config (
|
||||
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
created_at DATETIME DEFAULT NOW() COMMENT '생성 시각',
|
||||
-- 업비트 API 키
|
||||
UPBIT_ACCESS_KEY VARCHAR(200) DEFAULT '' COMMENT '업비트 Access Key',
|
||||
UPBIT_SECRET_KEY VARCHAR(200) DEFAULT '' COMMENT '업비트 Secret Key',
|
||||
-- 알림 (Mattermost)
|
||||
MM_SERVER_URL VARCHAR(200) DEFAULT '' COMMENT 'MM 서버 URL',
|
||||
MM_BOT_TOKEN_ VARCHAR(200) DEFAULT '' COMMENT 'MM 봇 토큰',
|
||||
MATTERMOST_CHANNEL VARCHAR(100) DEFAULT 'upbit' COMMENT 'MM 채널명',
|
||||
-- 포지션 관리
|
||||
MAX_STOCKS VARCHAR(20) DEFAULT '5' COMMENT '최대 보유 코인 수',
|
||||
SLOT_MONEY_DEFAULT VARCHAR(20) DEFAULT '100000' COMMENT '코인당 투자금액 (원)',
|
||||
-- 손익 기준
|
||||
STOP_LOSS_PCT VARCHAR(20) DEFAULT '-0.02' COMMENT '손절 비율 (음수, 예:-0.02)',
|
||||
TAKE_PROFIT_PCT VARCHAR(20) DEFAULT '0.05' COMMENT '익절 비율 (예:0.05)',
|
||||
MAX_LOSS_PER_TRADE_KRW VARCHAR(20) DEFAULT '50000' COMMENT '거래당 최대 원화 손실 한도',
|
||||
-- 어깨 매도 (수익 보존)
|
||||
SHOULDER_CUT_PCT VARCHAR(20) DEFAULT '0.03' COMMENT '어깨매도: 고점 대비 하락률',
|
||||
SHOULDER_MIN_HIGH_PCT VARCHAR(20) DEFAULT '0.01' COMMENT '어깨매도: 발동 최소 이익률',
|
||||
SHOULDER_MIN_NET_PCT VARCHAR(20) DEFAULT '0.001' COMMENT '어깨매도: 수수료 반영 최소 이익',
|
||||
-- ATR 스캘핑 엑시트
|
||||
SCALP_ATR_UP_MULT VARCHAR(20) DEFAULT '1.0' COMMENT 'ATR 스캘핑: 상승 배수',
|
||||
SCALP_ATR_DOWN_MULT VARCHAR(20) DEFAULT '0.2' COMMENT 'ATR 스캘핑: 하락 배수',
|
||||
SCALP_ATR_DROP_MULT VARCHAR(20) DEFAULT '1.0' COMMENT 'ATR 스캘핑: 낙폭 배수',
|
||||
-- ATR 손절/목표가 배수
|
||||
STOP_ATR_MULTIPLIER_TAIL VARCHAR(20) DEFAULT '2.5' COMMENT '손절선: 진입가 - ATR * 배수',
|
||||
TARGET_ATR_MULTIPLIER_TAIL VARCHAR(20) DEFAULT '7.0' COMMENT '목표가: 진입가 + ATR * 배수',
|
||||
-- 스캔 조건
|
||||
MIN_DROP_RATE VARCHAR(20) DEFAULT '0.03' COMMENT '매수 스캔: 최소 낙폭 (예:0.03)',
|
||||
MIN_RECOVERY_RATIO VARCHAR(20) DEFAULT '0.30' COMMENT '매수 스캔: 최소 회복률',
|
||||
MAX_RECOVERY_RATIO VARCHAR(20) DEFAULT '0.80' COMMENT '매수 스캔: 최대 회복률',
|
||||
HIGH_PRICE_CHASE_THRESHOLD VARCHAR(20) DEFAULT '0.96' COMMENT '고점 추격 방지 임계값',
|
||||
RSI_OVERHEAT_THRESHOLD VARCHAR(20) DEFAULT '78.0' COMMENT 'RSI 과열 임계값',
|
||||
-- 꼬리봉 조건
|
||||
TAIL_RATIO_MIN VARCHAR(20) DEFAULT '1.5' COMMENT '꼬리/몸통 최소 비율',
|
||||
TAIL_PCT_MIN VARCHAR(20) DEFAULT '0.003' COMMENT '꼬리 최소 % (예:0.003)',
|
||||
TAIL_SCORE_BASE VARCHAR(20) DEFAULT '5.0' COMMENT '꼬리 기본 점수',
|
||||
TAIL_SCORE_RATIO_MULT VARCHAR(20) DEFAULT '2.0' COMMENT '꼬리 비율 점수 가중치',
|
||||
-- 기타 매매 파라미터
|
||||
REENTRY_COOLDOWN_SEC VARCHAR(20) DEFAULT '300' COMMENT '재진입 쿨다운 (초)',
|
||||
ROUND_TRIP_COST_PCT VARCHAR(20) DEFAULT '0.001' COMMENT '왕복 수수료율 (업비트 0.05%×2)',
|
||||
MIN_HOLD_AFTER_BUY_SEC VARCHAR(20) DEFAULT '10.0' COMMENT '매수 후 최소 보유 시간 (초)',
|
||||
-- 스캔 주기
|
||||
UPBIT_SCAN_INTERVAL_SEC VARCHAR(20) DEFAULT '60' COMMENT '매수 스캔 주기 (초)',
|
||||
UPBIT_BUY_TOP_N VARCHAR(20) DEFAULT '2' COMMENT '스캔 후 상위 N개 매수',
|
||||
UPBIT_CANDLE_UNIT VARCHAR(20) DEFAULT '3' COMMENT '스캔용 분봉 단위 (3/5/15/60)'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='전략 설정값 (업비트 전용)'
|
||||
""",
|
||||
|
||||
# ── 4. Key-Value 저장소 (API 키 등) ──────────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS kv_store (
|
||||
k VARCHAR(100) NOT NULL PRIMARY KEY COMMENT '키',
|
||||
v TEXT COMMENT '값'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Key-Value 저장소'
|
||||
""",
|
||||
|
||||
# ── 5. 스캔 후보 목록 ───────────────────────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS target_candidates (
|
||||
code VARCHAR(20) NOT NULL PRIMARY KEY COMMENT '마켓코드',
|
||||
name VARCHAR(50) COMMENT '코인명',
|
||||
score DECIMAL(10,4) COMMENT '후보 점수',
|
||||
price DECIMAL(20,8) COMMENT '스캔 당시 가격',
|
||||
scan_time DATETIME COMMENT '스캔 시각',
|
||||
updated_at DATETIME COMMENT '최종 업데이트'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='스캔 후보 목록'
|
||||
""",
|
||||
|
||||
# ── 6. 업비트 분봉 데이터 (백테스트용) ──────────────────────────────
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS upbit_candles (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
code VARCHAR(20) NOT NULL COMMENT '마켓코드 (KRW-BTC)',
|
||||
candle_time VARCHAR(12) NOT NULL COMMENT '봉 시작시각 YYYYMMDDHHMI',
|
||||
timeframe SMALLINT NOT NULL DEFAULT 3 COMMENT '봉 단위 (3=3분, 60=60분봉)',
|
||||
open_price DECIMAL(20,8) COMMENT '시가',
|
||||
high_price DECIMAL(20,8) COMMENT '고가',
|
||||
low_price DECIMAL(20,8) COMMENT '저가',
|
||||
close_price DECIMAL(20,8) COMMENT '종가',
|
||||
volume DECIMAL(30,8) COMMENT '체결량',
|
||||
is_confirmed TINYINT DEFAULT 1 COMMENT '완성된 봉 여부',
|
||||
UNIQUE KEY uk_code_time_tf (code, candle_time, timeframe),
|
||||
INDEX idx_code_tf (code, timeframe),
|
||||
INDEX idx_time (candle_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='업비트 분봉 OHLCV (백테스트용)'
|
||||
""",
|
||||
]
|
||||
|
||||
# env_config 초기 기본값 INSERT (이미 row가 있으면 스킵)
|
||||
ENV_CONFIG_DEFAULT_INSERT = """
|
||||
INSERT IGNORE INTO env_config (id, created_at) VALUES (1, NOW())
|
||||
"""
|
||||
|
||||
|
||||
def run_init():
|
||||
logger.info("📦 upbit_quant_db 테이블 초기화 시작...")
|
||||
try:
|
||||
conn = pymysql.connect(**DB_CFG)
|
||||
except Exception as e:
|
||||
logger.error(f"❌ DB 연결 실패: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
for sql in DDL_STATEMENTS:
|
||||
table_name = sql.strip().split("TABLE IF NOT EXISTS")[1].split("(")[0].strip()
|
||||
cur.execute(sql)
|
||||
logger.info(f" ✅ 테이블 생성/확인: {table_name}")
|
||||
|
||||
# env_config 초기 row 삽입 (최초 1회)
|
||||
cur.execute("SELECT COUNT(*) as cnt FROM env_config")
|
||||
if cur.fetchone()["cnt"] == 0:
|
||||
cur.execute(ENV_CONFIG_DEFAULT_INSERT)
|
||||
logger.info(" ✅ env_config 초기값 row 삽입 완료")
|
||||
else:
|
||||
logger.info(" ℹ️ env_config row 이미 존재 — 스킵")
|
||||
|
||||
# kv_store 기본 키 삽입
|
||||
kv_defaults = [
|
||||
("UPBIT_ACCESS_KEY", ""),
|
||||
("UPBIT_SECRET_KEY", ""),
|
||||
("UPBIT_SCAN_INTERVAL_SEC", "60"),
|
||||
("UPBIT_BUY_TOP_N", "2"),
|
||||
]
|
||||
for k, v in kv_defaults:
|
||||
cur.execute(
|
||||
"INSERT IGNORE INTO kv_store (k, v) VALUES (%s, %s)", (k, v)
|
||||
)
|
||||
logger.info(" ✅ kv_store 기본 키 삽입 완료")
|
||||
|
||||
conn.commit()
|
||||
logger.info("🎉 upbit_quant_db 초기화 완료!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 초기화 중 오류: {e}")
|
||||
import traceback; traceback.print_exc()
|
||||
sys.exit(1)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_init()
|
||||
Reference in New Issue
Block a user