from typing import Any, Optional, Union from sqlalchemy import Boolean, ForeignKey, Numeric, Text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column from src.db.base import Base class TradeExecution(Base): __tablename__ = "trade_executions" id: Mapped[int] = mapped_column(primary_key=True) signal_id: Mapped[int] = mapped_column(ForeignKey("trade_signals.id"), nullable=False) execution_ticket_id: Mapped[Optional[int]] = mapped_column(ForeignKey("execution_tickets.id")) venue_order_id: Mapped[Optional[str]] = mapped_column(Text) execution_mode: Mapped[str] = mapped_column(Text, nullable=False) side: Mapped[str] = mapped_column(Text, nullable=False) entry_price: Mapped[Optional[float]] = mapped_column(Numeric(20, 10)) stop_loss: Mapped[Optional[float]] = mapped_column(Numeric(20, 10)) take_profit_1: Mapped[Optional[float]] = mapped_column(Numeric(20, 10)) take_profit_2: Mapped[Optional[float]] = mapped_column(Numeric(20, 10)) size: Mapped[Optional[float]] = mapped_column(Numeric(28, 10)) risk_pct: Mapped[Optional[float]] = mapped_column(Numeric(8, 4)) status: Mapped[str] = mapped_column(Text, nullable=False) confirmation_required: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) confirmed_by: Mapped[Optional[str]] = mapped_column(Text) confirmed_at: Mapped[Optional[object]] = mapped_column() opened_ts: Mapped[Optional[object]] = mapped_column() closed_ts: Mapped[Optional[object]] = mapped_column() pnl: Mapped[Optional[float]] = mapped_column(Numeric(28, 10)) broker_order_ids: Mapped[list] = mapped_column(JSONB, nullable=False, default=list) bracket_state: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict) fill_state: Mapped[Optional[str]] = mapped_column(Text) position_state: Mapped[Optional[str]] = mapped_column(Text) close_reason: Mapped[Optional[str]] = mapped_column(Text) reconciliation_state: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict) quality_score: Mapped[Optional[float]] = mapped_column(Numeric(10, 4)) ai_explanation: Mapped[Optional[str]] = mapped_column(Text) meta: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)