feat: replace volatility breakout with DB-backed real-time trend check

- price_history table on Oracle ADB stores prices every 10 minutes
- check_trend(): current price vs N hours ago (default 1h, +3% threshold)
- check_momentum(): unchanged (MA20 + 2x volume still applies)
- Ticker list cached 5 minutes to avoid 429 rate limits
- Collector starts 30s after boot to avoid simultaneous API calls
- Configurable: TREND_HOURS, TREND_MIN_GAIN_PCT in .env

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-02-28 11:26:26 +09:00
parent 9fe3ce488e
commit 80ab004eba
6 changed files with 206 additions and 26 deletions

52
core/price_collector.py Normal file
View File

@@ -0,0 +1,52 @@
"""10분마다 상위 종목 현재가를 Oracle DB에 저장하는 수집기."""
from __future__ import annotations
import logging
import time
import requests
from .market import get_top_tickers
from .price_db import cleanup_old_prices, insert_prices
logger = logging.getLogger(__name__)
COLLECT_INTERVAL = 600 # 10분 (초)
CLEANUP_EVERY = 6 # 1시간(10분 × 6)마다 오래된 데이터 정리
def run_collector(interval: int = COLLECT_INTERVAL) -> None:
"""가격 수집 루프."""
logger.info(f"가격 수집기 시작 (주기={interval//60}분)")
time.sleep(30) # 스캐너와 동시 API 호출 방지
cycle = 0
while True:
try:
tickers = get_top_tickers()
if not tickers:
continue
resp = requests.get(
"https://api.upbit.com/v1/ticker",
params={"markets": ",".join(tickers)},
timeout=5,
)
resp.raise_for_status()
data = resp.json()
valid = {
item["market"]: item["trade_price"]
for item in data
if item.get("trade_price")
}
insert_prices(valid)
logger.info(f"[수집] {len(valid)}개 종목 가격 저장")
cycle += 1
if cycle % CLEANUP_EVERY == 0:
cleanup_old_prices(keep_hours=48)
logger.info("오래된 가격 데이터 정리 완료")
except Exception as e:
logger.error(f"가격 수집 오류: {e}")
time.sleep(interval)