| from sqlalchemy import Column, String, Float, Integer, DateTime, Text, Boolean, JSON, ForeignKey, Index |
| from sqlalchemy.sql import func |
| from sqlalchemy.orm import relationship |
| import uuid |
| from datetime import datetime |
| from typing import Optional, Dict, Any |
| from enum import Enum |
|
|
| from app.core.db_selector import Base |
|
|
|
|
| class BacktestStatus(str, Enum): |
| """回测状态枚举""" |
| PENDING = "pending" |
| RUNNING = "running" |
| COMPLETED = "completed" |
| FAILED = "failed" |
| CANCELLED = "cancelled" |
|
|
|
|
| class BacktestType(str, Enum): |
| """回测类型枚举""" |
| SINGLE_STRATEGY = "single_strategy" |
| MULTI_STRATEGY = "multi_strategy" |
| PORTFOLIO = "portfolio" |
| WALK_FORWARD = "walk_forward" |
|
|
|
|
| class Backtest(Base): |
| """回测任务表""" |
| __tablename__ = "backtests" |
|
|
| id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) |
| name = Column(String(100), nullable=False, comment="回测名称") |
| description = Column(Text, comment="回测描述") |
| backtest_type = Column(String(20), nullable=False, comment="回测类型") |
| status = Column(String(20), default=BacktestStatus.PENDING, comment="回测状态") |
|
|
| |
| strategy_id = Column(String(36), ForeignKey('strategies.id'), comment="策略ID") |
| strategy_config = Column(JSON, comment="策略配置") |
|
|
| |
| start_date = Column(DateTime, nullable=False, comment="开始日期") |
| end_date = Column(DateTime, nullable=False, comment="结束日期") |
| initial_capital = Column(Float, default=1000000.0, comment="初始资金") |
| benchmark = Column(String(20), comment="基准指数") |
|
|
| |
| commission = Column(Float, default=0.0003, comment="手续费率") |
| slippage = Column(Float, default=0.001, comment="滑点") |
| min_commission = Column(Float, default=5.0, comment="最小手续费") |
|
|
| |
| universe = Column(JSON, comment="股票池") |
| filters = Column(JSON, comment="筛选条件") |
|
|
| |
| max_position_size = Column(Float, default=0.1, comment="最大单股仓位") |
| max_sector_exposure = Column(Float, default=0.3, comment="最大行业敞口") |
| stop_loss = Column(Float, comment="止损比例") |
| take_profit = Column(Float, comment="止盈比例") |
|
|
| |
| start_time = Column(DateTime, comment="开始时间") |
| end_time = Column(DateTime, comment="结束时间") |
| execution_time = Column(Float, comment="执行时长(秒)") |
| error_message = Column(Text, comment="错误信息") |
|
|
| |
| created_by = Column(String(36), comment="创建者ID") |
|
|
| |
| created_at = Column(DateTime, default=func.now(), comment="创建时间") |
| updated_at = Column( |
| DateTime, |
| default=func.now(), |
| onupdate=func.now(), |
| comment="更新时间") |
|
|
| |
| strategy = relationship("Strategy", backref="backtests") |
|
|
| |
| __table_args__ = ( |
| Index('idx_backtest_strategy', 'strategy_id'), |
| Index('idx_backtest_status', 'status'), |
| Index('idx_backtest_creator', 'created_by'), |
| Index('idx_backtest_date_range', 'start_date', 'end_date'), |
| ) |
|
|
| def __repr__(self): |
| return f"<Backtest(name='{self.name}', status='{self.status}', period='{self.start_date}~{self.end_date}')>" |
|
|
|
|
| class BacktestResult(Base): |
| """回测结果表""" |
| __tablename__ = "backtest_results" |
|
|
| id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) |
| backtest_id = Column(String(36), ForeignKey('backtests.id'), nullable=False) |
|
|
| |
| total_days = Column(Integer, comment="总交易天数") |
| trading_days = Column(Integer, comment="实际交易天数") |
|
|
| |
| total_return = Column(Float, comment="总收益率") |
| annual_return = Column(Float, comment="年化收益率") |
| benchmark_return = Column(Float, comment="基准收益率") |
| excess_return = Column(Float, comment="超额收益率") |
|
|
| |
| volatility = Column(Float, comment="年化波动率") |
| sharpe_ratio = Column(Float, comment="夏普比率") |
| sortino_ratio = Column(Float, comment="索提诺比率") |
| calmar_ratio = Column(Float, comment="卡玛比率") |
|
|
| |
| max_drawdown = Column(Float, comment="最大回撤") |
| max_drawdown_duration = Column(Integer, comment="最大回撤持续天数") |
| recovery_time = Column(Integer, comment="回撤恢复天数") |
|
|
| |
| total_trades = Column(Integer, comment="总交易次数") |
| winning_trades = Column(Integer, comment="盈利交易次数") |
| losing_trades = Column(Integer, comment="亏损交易次数") |
| win_rate = Column(Float, comment="胜率") |
|
|
| |
| avg_win = Column(Float, comment="平均盈利") |
| avg_loss = Column(Float, comment="平均亏损") |
| profit_factor = Column(Float, comment="盈亏比") |
| largest_win = Column(Float, comment="最大盈利") |
| largest_loss = Column(Float, comment="最大亏损") |
|
|
| |
| final_capital = Column(Float, comment="最终资金") |
| peak_capital = Column(Float, comment="资金峰值") |
|
|
| |
| tracking_error = Column(Float, comment="跟踪误差") |
| information_ratio = Column(Float, comment="信息比率") |
| beta = Column(Float, comment="贝塔值") |
| alpha = Column(Float, comment="阿尔法值") |
|
|
| |
| daily_returns = Column(JSON, comment="日收益率序列") |
| equity_curve = Column(JSON, comment="资金曲线") |
| drawdown_series = Column(JSON, comment="回撤序列") |
|
|
| |
| created_at = Column(DateTime, default=func.now(), comment="创建时间") |
|
|
| |
| backtest = relationship("Backtest", backref="results") |
|
|
| |
| __table_args__ = ( |
| Index('idx_result_backtest', 'backtest_id'), |
| ) |
|
|
| def __repr__(self): |
| return f"<BacktestResult(backtest_id='{self.backtest_id}', return={self.total_return}, sharpe={self.sharpe_ratio})>" |
|
|
|
|
| class BacktestMetrics(Base): |
| """回测指标详情表""" |
| __tablename__ = "backtest_metrics" |
|
|
| id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) |
| backtest_id = Column(String(36), ForeignKey('backtests.id'), nullable=False) |
| metric_date = Column(DateTime, nullable=False, comment="指标日期") |
|
|
| |
| portfolio_value = Column(Float, comment="组合价值") |
| cash = Column(Float, comment="现金") |
| positions_value = Column(Float, comment="持仓价值") |
| daily_return = Column(Float, comment="日收益率") |
| cumulative_return = Column(Float, comment="累计收益率") |
|
|
| |
| benchmark_value = Column(Float, comment="基准价值") |
| benchmark_return = Column(Float, comment="基准日收益率") |
| excess_return = Column(Float, comment="超额收益率") |
|
|
| |
| drawdown = Column(Float, comment="回撤") |
| volatility = Column(Float, comment="滚动波动率") |
|
|
| |
| positions_count = Column(Integer, comment="持仓股票数量") |
| turnover = Column(Float, comment="换手率") |
|
|
| |
| created_at = Column(DateTime, default=func.now(), comment="创建时间") |
|
|
| |
| backtest = relationship("Backtest", backref="metrics") |
|
|
| |
| __table_args__ = ( |
| Index('idx_metrics_backtest_date', 'backtest_id', 'metric_date'), |
| Index('idx_metrics_date', 'metric_date'), |
| ) |
|
|
| def __repr__(self): |
| return f"<BacktestMetrics(backtest_id='{self.backtest_id}', date='{self.metric_date}', value={self.portfolio_value})>" |
|
|
|
|
| class BacktestTrade(Base): |
| """回测交易记录表""" |
| __tablename__ = "backtest_trades" |
|
|
| id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) |
| backtest_id = Column(String(36), ForeignKey('backtests.id'), nullable=False) |
|
|
| |
| symbol = Column(String(20), nullable=False, comment="股票代码") |
| trade_date = Column(DateTime, nullable=False, comment="交易日期") |
| action = Column(String(10), nullable=False, comment="交易动作") |
|
|
| |
| price = Column(Float, nullable=False, comment="交易价格") |
| quantity = Column(Integer, nullable=False, comment="交易数量") |
| amount = Column(Float, nullable=False, comment="交易金额") |
|
|
| |
| commission = Column(Float, comment="手续费") |
| slippage = Column(Float, comment="滑点成本") |
| total_cost = Column(Float, comment="总成本") |
|
|
| |
| signal_type = Column(String(20), comment="信号类型") |
| signal_strength = Column(Float, comment="信号强度") |
|
|
| |
| position_before = Column(Integer, comment="交易前持仓") |
| position_after = Column(Integer, comment="交易后持仓") |
|
|
| |
| buy_price = Column(Float, comment="买入价格") |
| pnl = Column(Float, comment="盈亏金额") |
| pnl_pct = Column(Float, comment="盈亏比例") |
| holding_days = Column(Integer, comment="持有天数") |
|
|
| |
| created_at = Column(DateTime, default=func.now(), comment="创建时间") |
|
|
| |
| backtest = relationship("Backtest", backref="trades") |
|
|
| |
| __table_args__ = ( |
| Index('idx_trade_backtest_date', 'backtest_id', 'trade_date'), |
| Index('idx_trade_symbol', 'symbol'), |
| Index('idx_trade_action', 'action'), |
| ) |
|
|
| def __repr__(self): |
| return f"<BacktestTrade(backtest_id='{self.backtest_id}', symbol='{self.symbol}', action='{self.action}', price={self.price})>" |
|
|