Files
kis_bot/kis_trader/utils/strategy_ids.py
Hwang 61c72a8a4c feat(tests): 신규 키움 웹소켓 조건검색 및 실시간 조건검색 테스트 추가
변경 사항
----
- _test_kiwoom_condition_list.py: 키움 웹소켓 조건검색 '목록조회' 기능을 단독으로 테스트하는 스크립트 추가
- _test_kiwoom_condition_realtime.py: 'momentum' 조건식을 실시간으로 등록하고 초기 매칭 종목 리스트 및 실시간 편입/이탈을 수신하는 테스트 스크립트 추가
- _verify_columnar_bitid.py, _verify_shared_e2e_breakout.py, _verify_shared_e2e.py: 공유 메모리 및 dict 간의 데이터 일관성을 검증하는 테스트 추가

영향
----
- 신규 테스트 스크립트 추가로 키움 웹소켓 API의 기능 검증 및 안정성을 높임
- 기존 기능에 대한 영향 없음

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 01:27:00 +09:00

119 lines
3.9 KiB
Python

"""
kis_trader 전략 ID 단일 정의 — active_trades / trade_history / 웹 실거래·보유탭 공통.
- ``main.py`` 전략 클래스의 ``strategy_id`` (SCALP, SHORT, MOMENTUM, UPDOW, BREAKOUT, HOLDING)
- ``trade_history`` 신규 기록은 ``canonical_strategy_id()`` 로 위 ID 만 저장 → 실거래 분석 탭과 일치
- 구식명(SCALP_RSI_REVERSAL, SHORT_ANT_SHAKING)은 조회 시 접두어(LIKE)로 묶고, 신규 저장은 canonical
"""
from __future__ import annotations
from typing import List, Optional
# kis_trader/main.py 에 등록되는 전략 ID (실거래 분석·보유탭 공통)
KIS_TRADER_STRATEGY_IDS: List[str] = [
"SCALP",
"SHORT",
"MOMENTUM",
"UPDOW",
"BREAKOUT",
"RANGE_BREAK",
"DBBAND",
"HOLDING",
]
# 사용자 지정 — 웹·계산에서 완전히 숨길 전략 (비활성·중복·저성능).
# DB 에 기존 거래기록이 남아 있어도 실거래 분석·대시보드·보유탭·운영설정에서 표시·집계하지 않는다.
# SCALP : MOMENTUM 과 1분봉 슬롯 중복 (반등 vs 추세) → MOMENTUM 만 사용
# RANGE_BREAK : BREAKOUT 과 돌파 컨셉 중복 + 미검증 (파라서치 거래 0건)
# DBBAND : 표본 부족·미성숙 (백테 2~4건)
HIDDEN_STRATEGY_IDS: List[str] = [
"SCALP",
"RANGE_BREAK",
"DBBAND",
]
# 웹·실거래 집계에서 제외 (DB에 남아 있어도 표시·집계 안 함)
EXCLUDED_STRATEGY_IDS: List[str] = [
"MANUAL",
"SCALP_RSI_REVERSAL",
"SHORT_ANT_SHAKING",
"SCALP_TEST",
] + HIDDEN_STRATEGY_IDS
# 보유·매도 탭 전용 — 홀딩봇(HOLDING)은 조회만, 여기서 매도 대상 아님
PORTFOLIO_EXCLUDED_STRATEGY_IDS: List[str] = EXCLUDED_STRATEGY_IDS + [
"HOLDING",
]
def canonical_strategy_id(strategy: Optional[str]) -> str:
"""
DB 저장·trade_history 기록용 canonical ID.
MANUAL 은 그대로, 구식명은 SCALP/SHORT 등으로 접힘.
"""
s = (strategy or "").strip().upper()
if not s:
return "MANUAL"
if s == "MANUAL":
return "MANUAL"
if s.startswith("SCALP"):
return "SCALP"
if s.startswith("SHORT") or s.startswith("TAIL"):
return "SHORT"
if s.startswith("MOMENTUM"):
return "MOMENTUM"
if s.startswith("UPDOW"):
return "UPDOW"
if s.startswith("BREAKOUT"):
return "BREAKOUT"
if s.startswith("RANGE_BREAK"):
return "RANGE_BREAK"
if s.startswith("DBBAND") or s.startswith("BBBAND"):
return "DBBAND"
if s.startswith("HOLDING"):
return "HOLDING"
return s
def strategy_prefix_for_filter(strategy: Optional[str]) -> str:
"""
trade_history / active_trades LIKE 필터용 접두어.
실거래 분석 탭·보유탭이 동일 규칙 사용.
"""
s_upper = (strategy or "").upper().strip()
if not s_upper or s_upper == "ALL":
return ""
if s_upper == "MANUAL":
return "MANUAL"
if s_upper.startswith("SCALP"):
return "SCALP"
if s_upper.startswith("SHORT") or s_upper.startswith("TAIL"):
return "SHORT"
if s_upper.startswith("MOMENTUM"):
return "MOMENTUM"
if s_upper.startswith("UPDOW"):
return "UPDOW"
if s_upper.startswith("BREAKOUT"):
return "BREAKOUT"
if s_upper.startswith("RANGE_BREAK"):
return "RANGE_BREAK"
if s_upper.startswith("DBBAND") or s_upper.startswith("BBBAND"):
return "DBBAND"
if s_upper.startswith("HOLDING"):
return "HOLDING"
return s_upper
def strategy_like_pattern(strategy: Optional[str]) -> Optional[str]:
"""None 이면 전체, 아니면 ``PREFIX%``."""
prefix = strategy_prefix_for_filter(strategy)
if not prefix:
return None
return prefix + "%"
def is_bot_strategy(strategy: Optional[str]) -> bool:
"""kis_trader 봇 전략 row 인지 (MANUAL 제외)."""
c = canonical_strategy_id(strategy)
return c in KIS_TRADER_STRATEGY_IDS