""" Backtest related models. """ from datetime import datetime from sqlalchemy import ( Column, Integer, String, Numeric, DateTime, Date, Text, ForeignKey, JSON, Enum as SQLEnum ) from sqlalchemy.orm import relationship import enum from app.core.database import Base class BacktestStatus(str, enum.Enum): PENDING = "pending" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" class RebalancePeriod(str, enum.Enum): MONTHLY = "monthly" QUARTERLY = "quarterly" SEMI_ANNUAL = "semi_annual" ANNUAL = "annual" class Backtest(Base): __tablename__ = "backtests" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False) strategy_type = Column(String(50), nullable=False) strategy_params = Column(JSON, default={}) start_date = Column(Date, nullable=False) end_date = Column(Date, nullable=False) rebalance_period = Column(SQLEnum(RebalancePeriod), default=RebalancePeriod.QUARTERLY) initial_capital = Column(Numeric(20, 2), nullable=False) commission_rate = Column(Numeric(10, 6), default=0.00015) slippage_rate = Column(Numeric(10, 6), default=0.001) benchmark = Column(String(20), default="KOSPI") top_n = Column(Integer, default=30) status = Column(SQLEnum(BacktestStatus), default=BacktestStatus.PENDING) created_at = Column(DateTime, default=datetime.utcnow) completed_at = Column(DateTime, nullable=True) error_message = Column(Text, nullable=True) # Relationships result = relationship("BacktestResult", back_populates="backtest", uselist=False) equity_curve = relationship("BacktestEquityCurve", back_populates="backtest") holdings = relationship("BacktestHolding", back_populates="backtest") transactions = relationship("BacktestTransaction", back_populates="backtest") class BacktestResult(Base): __tablename__ = "backtest_results" backtest_id = Column(Integer, ForeignKey("backtests.id"), primary_key=True) total_return = Column(Numeric(10, 4)) cagr = Column(Numeric(10, 4)) mdd = Column(Numeric(10, 4)) sharpe_ratio = Column(Numeric(10, 4)) volatility = Column(Numeric(10, 4)) benchmark_return = Column(Numeric(10, 4)) excess_return = Column(Numeric(10, 4)) backtest = relationship("Backtest", back_populates="result") class BacktestEquityCurve(Base): __tablename__ = "backtest_equity_curve" backtest_id = Column(Integer, ForeignKey("backtests.id"), primary_key=True) date = Column(Date, primary_key=True) portfolio_value = Column(Numeric(20, 2)) benchmark_value = Column(Numeric(20, 2)) drawdown = Column(Numeric(10, 4)) backtest = relationship("Backtest", back_populates="equity_curve") class BacktestHolding(Base): __tablename__ = "backtest_holdings" backtest_id = Column(Integer, ForeignKey("backtests.id"), primary_key=True) rebalance_date = Column(Date, primary_key=True) ticker = Column(String(20), primary_key=True) name = Column(String(100)) weight = Column(Numeric(10, 4)) shares = Column(Integer) price = Column(Numeric(12, 2)) backtest = relationship("Backtest", back_populates="holdings") class BacktestTransaction(Base): __tablename__ = "backtest_transactions" id = Column(Integer, primary_key=True, index=True) backtest_id = Column(Integer, ForeignKey("backtests.id"), nullable=False) date = Column(Date, nullable=False) ticker = Column(String(20), nullable=False) action = Column(String(10), nullable=False) # buy/sell shares = Column(Integer, nullable=False) price = Column(Numeric(12, 2), nullable=False) commission = Column(Numeric(12, 2), nullable=False) backtest = relationship("Backtest", back_populates="transactions")