80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
"""
|
|
Signal Data Class
|
|
|
|
전략이 생성하는 매매 신호 데이터 구조
|
|
"""
|
|
from enum import Enum
|
|
from dataclasses import dataclass
|
|
from typing import Optional, Dict, Any
|
|
from datetime import datetime
|
|
|
|
|
|
class SignalType(Enum):
|
|
"""신호 타입"""
|
|
BUY = "BUY" # 매수
|
|
SELL = "SELL" # 매도
|
|
HOLD = "HOLD" # 보유
|
|
CLOSE = "CLOSE" # 청산
|
|
STOP_LOSS = "STOP_LOSS" # 손절
|
|
TAKE_PROFIT = "TAKE_PROFIT" # 익절
|
|
|
|
|
|
@dataclass
|
|
class Signal:
|
|
"""
|
|
매매 신호 데이터 클래스
|
|
|
|
전략이 생성한 매매 신호를 표준화된 형식으로 전달
|
|
"""
|
|
# 필수 필드
|
|
stock_code: str # 종목코드
|
|
signal_type: SignalType # 신호 타입
|
|
strategy_name: str # 전략 이름
|
|
timestamp: datetime # 신호 생성 시각
|
|
|
|
# 주문 정보
|
|
quantity: Optional[int] = None # 수량
|
|
price: Optional[float] = None # 가격 (None = 시장가)
|
|
confidence: float = 1.0 # 신뢰도 (0.0 ~ 1.0)
|
|
|
|
# 손익 관리
|
|
stop_loss_price: Optional[float] = None # 손절가
|
|
take_profit_price: Optional[float] = None # 익절가
|
|
trailing_stop_pct: Optional[float] = None # 트레일링 스탑 %
|
|
|
|
# 메타데이터
|
|
reason: Optional[str] = None # 신호 발생 이유
|
|
metadata: Optional[Dict[str, Any]] = None # 추가 데이터
|
|
|
|
def __post_init__(self):
|
|
"""유효성 검증"""
|
|
if self.confidence < 0.0 or self.confidence > 1.0:
|
|
raise ValueError(f"Confidence must be 0.0~1.0, got {self.confidence}")
|
|
|
|
if isinstance(self.signal_type, str):
|
|
self.signal_type = SignalType(self.signal_type)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""딕셔너리 변환 (DB 저장용)"""
|
|
return {
|
|
"stock_code": self.stock_code,
|
|
"signal_type": self.signal_type.value,
|
|
"strategy_name": self.strategy_name,
|
|
"timestamp": self.timestamp.isoformat(),
|
|
"quantity": self.quantity,
|
|
"price": self.price,
|
|
"confidence": self.confidence,
|
|
"stop_loss_price": self.stop_loss_price,
|
|
"take_profit_price": self.take_profit_price,
|
|
"trailing_stop_pct": self.trailing_stop_pct,
|
|
"reason": self.reason,
|
|
"metadata": self.metadata,
|
|
}
|
|
|
|
def __repr__(self) -> str:
|
|
return (
|
|
f"Signal({self.signal_type.value} {self.stock_code} "
|
|
f"@{self.price or 'MARKET'} x{self.quantity} "
|
|
f"[{self.strategy_name}] conf={self.confidence:.2f})"
|
|
)
|