"""Learning domain models: TradeOutcome, LearningAdjustment.""" import uuid from datetime import timedelta from sqlalchemy import Boolean, Float, ForeignKey, Interval, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from shared.models.base import Base, TimestampMixin class TradeOutcome(TimestampMixin, Base): __tablename__ = "trade_outcomes" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) trade_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("trades.id"), unique=True, nullable=False ) hold_duration: Mapped[timedelta | None] = mapped_column(Interval, nullable=True) realized_pnl: Mapped[float] = mapped_column(Float, nullable=False) roi_pct: Mapped[float] = mapped_column(Float, nullable=False) was_profitable: Mapped[bool] = mapped_column(Boolean, nullable=False) # Relationships trade: Mapped["Trade"] = relationship("Trade", back_populates="outcome") class LearningAdjustment(TimestampMixin, Base): __tablename__ = "learning_adjustments" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) strategy_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("strategies.id"), nullable=False ) old_weight: Mapped[float] = mapped_column(Float, nullable=False) new_weight: Mapped[float] = mapped_column(Float, nullable=False) reason: Mapped[str | None] = mapped_column(Text, nullable=True) reward_signal: Mapped[float] = mapped_column(Float, nullable=False) # Relationships strategy: Mapped["Strategy"] = relationship("Strategy") # Avoid circular imports — reference by string in relationship() from shared.models.trading import Trade as Trade # noqa: E402, F401 from shared.models.trading import Strategy as Strategy # noqa: E402, F401