Files
upbit-trader/core/strategy.py
joungmin 83bd51117f feat: initial upbit auto-trader implementation
Strategy C: volatility breakout (Larry Williams K=0.5) AND momentum
(MA20 + 2x volume surge) must both trigger for a buy signal.

Hard rules:
- Trailing stop: sell when price drops -10% from peak
- Max budget: 1,000,000 KRW total, up to 3 positions (333,333 KRW each)
- Scan top 20 KRW tickers by 24h trading volume every 60s
- Monitor positions every 10s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:20:02 +09:00

70 lines
2.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
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.
"""Strategy C: 변동성 돌파 AND 모멘텀 동시 충족 시 매수 신호."""
import logging
from .market import get_current_price, get_ohlcv
logger = logging.getLogger(__name__)
# 변동성 돌파 계수 (래리 윌리엄스 기본값)
BREAKOUT_K = 0.5
# 모멘텀 이동평균 기간
MA_PERIOD = 20
# 거래량 급증 배수
VOLUME_MULTIPLIER = 2.0
def check_volatility_breakout(ticker: str) -> bool:
"""변동성 돌파 조건: 현재가 > 오늘 시가 + 전일 변동폭 × K."""
df = get_ohlcv(ticker, count=2)
if df is None or len(df) < 2:
return False
prev = df.iloc[-2]
today = df.iloc[-1]
target = today["open"] + (prev["high"] - prev["low"]) * BREAKOUT_K
current = get_current_price(ticker)
if current is None:
return False
result = current > target
if result:
logger.debug(f"[변동성돌파] {ticker} 현재가={current:,.0f} 목표가={target:,.0f}")
return result
def check_momentum(ticker: str) -> bool:
"""모멘텀 조건: 현재가 > MA20 AND 오늘 거래량 > 20일 평균 × 2."""
df = get_ohlcv(ticker, count=MA_PERIOD + 1)
if df is None or len(df) < MA_PERIOD + 1:
return False
ma = df["close"].iloc[-MA_PERIOD:].mean()
avg_vol = df["volume"].iloc[:-1].mean() # 오늘 제외한 20일 평균
today_vol = df["volume"].iloc[-1]
current = get_current_price(ticker)
if current is None:
return False
price_ok = current > ma
vol_ok = today_vol > avg_vol * VOLUME_MULTIPLIER
result = price_ok and vol_ok
if result:
logger.debug(
f"[모멘텀] {ticker} 현재가={current:,.0f} MA20={ma:,.0f} "
f"오늘거래량={today_vol:.1f} 평균={avg_vol:.1f}"
)
return result
def should_buy(ticker: str) -> bool:
"""Strategy C: 변동성 돌파 AND 모멘텀 모두 충족 시 True."""
vb = check_volatility_breakout(ticker)
if not vb:
return False
mo = check_momentum(ticker)
return vb and mo