[2026-05-28] 진입 지연 및 섹터 필터 수정
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ Claude Code가 이 파일을 읽고 필요시 수정함
|
||||
|
||||
# ── 변동성 돌파 ──
|
||||
STRATEGY_K = 0.5
|
||||
ENTRY_START = "09:15"
|
||||
ENTRY_START = "09:20"
|
||||
ENTRY_END = "14:30"
|
||||
FORCE_EXIT = "14:50" # 절대 변경 불가
|
||||
TP1_PCT = 0.020 # 1차 익절 +2.0% → 70% 매도
|
||||
|
||||
+50
@@ -93,6 +93,7 @@ class StockBot:
|
||||
self.positions = {} # ticker → {name, entry, qty, tp1_done, entry_time}
|
||||
self.universe = [] # 감시 종목 리스트
|
||||
self.ticker_names = {} # ticker → 종목명 캐시
|
||||
self.ticker_sectors = {} # ticker -> sector name cache
|
||||
self.sl_tickers = set() # 당일 SL 당한 종목 — 재진입 차단
|
||||
self.risk = None # RiskManager (잔고 확인 후 초기화)
|
||||
self.running = False
|
||||
@@ -524,6 +525,18 @@ class StockBot:
|
||||
# ETF/ETN/인버스/레버리지 종목 필터
|
||||
_ETF_KEYWORDS = ('인버스', '레버리지', '선물', 'KODEX', 'TIGER', 'KBSTAR',
|
||||
'HANARO', 'ARIRANG', 'KOSEF', 'SOL', 'ACE', 'RISE', 'PLUS')
|
||||
_SECTOR_FIELDS = (
|
||||
"sector",
|
||||
"sector_name",
|
||||
"bstp_kor_isnm",
|
||||
"bstp_cls_name",
|
||||
"bstp_name",
|
||||
)
|
||||
_AVOID_SECTOR_NAME_HINTS = (
|
||||
("\uac74\uc124", ("\uac74\uc124", "\ub300\uc6b0\uac74\uc124", "\ud604\ub300\uac74\uc124", "GS\uac74\uc124", "DL\uc774\uc564\uc528", "HDC\ud604\ub300\uc0b0\uc5c5\uac1c\ubc1c")),
|
||||
("\uc804\uae30\uac00\uc2a4", ("\ud55c\uad6d\uc804\ub825", "\ud55c\uc804", "\ud55c\uad6d\uac00\uc2a4", "\uc9c0\uc5ed\ub09c\ubc29", "\uc804\uae30", "\uac00\uc2a4")),
|
||||
("\uc8fc\ub958", ("\ud558\uc774\ud2b8\uc9c4\ub85c", "\ub86f\ub370\uce60\uc131", "\ubb34\ud559", "\ubcf4\ud574\uc591\uc870", "\uad6d\uc21c\ub2f9", "\uc8fc\ub958")),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_etf(ticker: str, name: str) -> bool:
|
||||
@@ -531,6 +544,35 @@ class StockBot:
|
||||
return True
|
||||
return any(kw in name for kw in StockBot._ETF_KEYWORDS)
|
||||
|
||||
@classmethod
|
||||
def _sector_from_rank_row(cls, row: dict) -> str:
|
||||
for field in cls._SECTOR_FIELDS:
|
||||
value = row.get(field)
|
||||
if value:
|
||||
return str(value).strip()
|
||||
return ""
|
||||
|
||||
def _infer_avoid_sector_from_name(self, name: str) -> str:
|
||||
compact_name = (name or "").replace(" ", "")
|
||||
if not compact_name:
|
||||
return ""
|
||||
|
||||
for sector in self.strategy.context.get("avoid_sectors", []):
|
||||
sector_name = str(sector or "").strip()
|
||||
if not sector_name:
|
||||
continue
|
||||
compact_sector = sector_name.replace(" ", "")
|
||||
|
||||
for key, hints in self._AVOID_SECTOR_NAME_HINTS:
|
||||
if key in compact_sector and any(hint in compact_name for hint in hints):
|
||||
return sector_name
|
||||
|
||||
generic_token = compact_sector.replace("\uc5c5", "")
|
||||
if len(generic_token) >= 2 and generic_token in compact_name:
|
||||
return sector_name
|
||||
|
||||
return ""
|
||||
|
||||
async def update_universe(self):
|
||||
"""종목 풀 갱신 + 전일 데이터 수집"""
|
||||
logger.info("유니버스 갱신 시작")
|
||||
@@ -541,6 +583,9 @@ class StockBot:
|
||||
# 종목명 캐시 갱신 + ETF 필터
|
||||
for r in rank:
|
||||
self.ticker_names[r["ticker"]] = r["name"]
|
||||
sector = self._sector_from_rank_row(r)
|
||||
if sector:
|
||||
self.ticker_sectors[r["ticker"]] = sector
|
||||
tickers = [r["ticker"] for r in rank
|
||||
if not self._is_etf(r["ticker"], r["name"])]
|
||||
|
||||
@@ -732,11 +777,16 @@ class StockBot:
|
||||
price_info = await self.kis.get_price(ticker) # rate limiter가 자동 throttle
|
||||
current = price_info["current"]
|
||||
name = self.ticker_names.get(ticker, ticker)
|
||||
sector = (
|
||||
self.ticker_sectors.get(ticker, "")
|
||||
or self._infer_avoid_sector_from_name(name)
|
||||
)
|
||||
|
||||
signal = self.strategy.check_entry(
|
||||
ticker=ticker,
|
||||
name=name,
|
||||
current_price=current,
|
||||
sector=sector,
|
||||
)
|
||||
|
||||
if not signal["signal"]:
|
||||
|
||||
Reference in New Issue
Block a user