from datetime import date, datetime from decimal import Decimal from typing import List, Optional from pydantic import BaseModel from app.schemas.portfolio import FloatDecimal class ScreeningSignalResponse(BaseModel): id: int screen_date: date ticker: str name: Optional[str] = None sector: Optional[str] = None market_cap: Optional[int] = None trading_value: Optional[int] = None is_limit_up: bool = False daily_return: Optional[FloatDecimal] = None trigger_low: Optional[FloatDecimal] = None market_state: Optional[str] = None status: str entry_date: Optional[date] = None entry_price: Optional[FloatDecimal] = None exit_date: Optional[date] = None exit_price: Optional[FloatDecimal] = None created_at: datetime class Config: from_attributes = True class AutoOrderResponse(BaseModel): id: int order_date: datetime ticker: str order_type: Optional[str] = None qty: Optional[int] = None price: Optional[FloatDecimal] = None order_no: Optional[str] = None status: Optional[str] = None screening_signal_id: Optional[int] = None created_at: datetime class Config: from_attributes = True class WatchlistItem(BaseModel): ticker: str name: Optional[str] = None sector: Optional[str] = None screen_date: date trading_value: Optional[int] = None is_limit_up: bool = False daily_return: Optional[FloatDecimal] = None trigger_low: Optional[FloatDecimal] = None market_state: Optional[str] = None status: str class Config: from_attributes = True class SectorStrongSignalResponse(BaseModel): sector: str signal_count: int id: int screen_date: date ticker: str name: Optional[str] = None trading_value: Optional[int] = None is_limit_up: bool = False daily_return: Optional[FloatDecimal] = None signal_strength: FloatDecimal status: str class SectorCandidateSignal(BaseModel): ticker: str name: Optional[str] = None sector: str latest_date: date close_price: FloatDecimal daily_return: FloatDecimal one_month_return: FloatDecimal relative_strength: FloatDecimal trading_value: int avg_trading_value_20: int trading_value_ratio: FloatDecimal ma5_support: bool breakout: bool score: FloatDecimal is_stronger_than_source: bool class RecentSectorCandidateResponse(BaseModel): signal_id: int screen_date: date ticker: str name: Optional[str] = None sector: str source_score: FloatDecimal source_one_month_return: FloatDecimal source_relative_strength: FloatDecimal stronger_count: int candidates: List[SectorCandidateSignal] class ScreeningSummary(BaseModel): date: date market_state: str total_screened: int limit_up_count: int watchlist_count: int signals: List[ScreeningSignalResponse]