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>
59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""트레일링 스탑 감시 - 백그라운드 스레드에서 실행."""
|
|
|
|
import logging
|
|
import time
|
|
|
|
from .market import get_current_price
|
|
from . import trader
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
STOP_LOSS_PCT = 0.10 # 최고가 대비 -10%
|
|
CHECK_INTERVAL = 10 # 10초마다 체크
|
|
|
|
|
|
def _check_stop(ticker: str, pos: dict) -> None:
|
|
"""단일 포지션 스탑 체크."""
|
|
current = get_current_price(ticker)
|
|
if current is None:
|
|
return
|
|
|
|
# 최고가 갱신
|
|
trader.update_peak(ticker, current)
|
|
|
|
# 최신 peak_price 읽기 (update 후)
|
|
pos = trader.get_positions().get(ticker)
|
|
if pos is None:
|
|
return
|
|
|
|
peak = pos["peak_price"]
|
|
buy_price = pos["buy_price"]
|
|
drop_from_peak = (peak - current) / peak
|
|
|
|
# 로그 (보유 중 상태 확인)
|
|
pnl = (current - buy_price) / buy_price * 100
|
|
logger.info(
|
|
f"[감시] {ticker} 현재={current:,.0f} | "
|
|
f"최고={peak:,.0f} | 하락={drop_from_peak:.1%} | 수익률={pnl:+.1f}%"
|
|
)
|
|
|
|
if drop_from_peak >= STOP_LOSS_PCT:
|
|
reason = (
|
|
f"트레일링스탑 | 최고가={peak:,.0f}원 → "
|
|
f"현재={current:,.0f}원 ({drop_from_peak:.1%} 하락)"
|
|
)
|
|
trader.sell(ticker, reason=reason)
|
|
|
|
|
|
def run_monitor(interval: int = CHECK_INTERVAL) -> None:
|
|
"""전체 포지션 감시 루프."""
|
|
logger.info(f"모니터 시작 (체크 주기={interval}초, 스탑={STOP_LOSS_PCT:.0%})")
|
|
while True:
|
|
positions_snapshot = dict(trader.get_positions())
|
|
for ticker, pos in positions_snapshot.items():
|
|
try:
|
|
_check_stop(ticker, pos)
|
|
except Exception as e:
|
|
logger.error(f"모니터 오류 {ticker}: {e}")
|
|
time.sleep(interval)
|