Files
upbit_trader/upbit_db_init.py
2026-03-13 04:37:58 +09:00

227 lines
13 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()