1. daemon/runner.py: skip scan entirely in bear regime
- calls get_regime() at start of each scan loop
- logs bear block with score before sleeping
2. core/strategy.py: trend-continuation entry filter
- check_trend_6h(): 6h price trend >= 1% (rejects flash spikes)
- 15-min confirmation watchlist (_watchlist dict)
- should_buy() adds watchlist to existing 12h+regime+momentum logic
- CONFIRM_SECONDS env var (default 900 = 15min)
- TREND_6H_MIN_PCT env var (default 1.0%)
3. backtest.py: partial take-profit scenario comparison (--tp-cmp)
- simulate(): partial_tp_pct / partial_tp_ratio params
- blended pnl = ratio * partial_pnl + (1-ratio) * remaining_pnl
- main_tp_cmp(): 3 scenarios A/B/C (none / +5% 50% / +3% 50%)
- result: partial TP reduces cumulative return (-56% → -63%)
big winners carry the strategy; trimming them hurts expected value
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
"""매수 기회 스캔 루프 - 60초마다 전체 시장 스캔."""
|
|
|
|
import logging
|
|
import time
|
|
|
|
from core import trader
|
|
from core.market import get_top_tickers
|
|
from core.market_regime import get_regime
|
|
from core.strategy import should_buy
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
SCAN_INTERVAL = 60 # 초
|
|
|
|
|
|
def run_scanner() -> None:
|
|
"""메인 스캔 루프."""
|
|
logger.info(f"스캐너 시작 (주기={SCAN_INTERVAL}초)")
|
|
while True:
|
|
try:
|
|
# 포지션 꽉 찼으면 스캔 스킵
|
|
if len(trader.get_positions()) >= trader.MAX_POSITIONS:
|
|
logger.info("포지션 최대치 도달, 스캔 스킵")
|
|
time.sleep(SCAN_INTERVAL)
|
|
continue
|
|
|
|
# Bear 레짐 시 신규 매수 완전 차단
|
|
regime = get_regime()
|
|
if regime["name"] == "bear":
|
|
logger.info(
|
|
f"[Bear차단] 레짐={regime['emoji']} BEAR "
|
|
f"(score={regime['score']:+.2f}%) — 신규 매수 스킵"
|
|
)
|
|
time.sleep(SCAN_INTERVAL)
|
|
continue
|
|
|
|
tickers = get_top_tickers()
|
|
logger.info(f"스캔 시작: {len(tickers)}개 종목")
|
|
|
|
for ticker in tickers:
|
|
# 이미 보유 중인 종목 제외
|
|
if ticker in trader.get_positions():
|
|
continue
|
|
|
|
try:
|
|
if should_buy(ticker):
|
|
logger.info(f"매수 신호: {ticker}")
|
|
trader.buy(ticker)
|
|
time.sleep(0.15) # API rate limit 방지
|
|
except Exception as e:
|
|
logger.error(f"스캔 오류 {ticker}: {e}")
|
|
time.sleep(0.3)
|
|
|
|
except Exception as e:
|
|
logger.error(f"스캐너 루프 오류: {e}")
|
|
|
|
time.sleep(SCAN_INTERVAL)
|