58 lines
2.3 KiB
Python
58 lines
2.3 KiB
Python
"""ORM 模型。
|
||
|
||
Candle 表设计与 TimescaleDB hypertable 完全兼容:将来在目标 PG 库执行
|
||
SELECT create_hypertable('candles', 'ts');
|
||
即可升级为时序表 + Continuous Aggregates 多周期预聚合,无需改表结构。
|
||
"""
|
||
from datetime import datetime
|
||
|
||
from sqlalchemy import DateTime, Float, Integer, String, UniqueConstraint
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from .db import Base
|
||
|
||
|
||
def _utcnow() -> datetime:
|
||
# naive UTC,避免 SQLite 存储时区带来的麻烦
|
||
from datetime import timezone
|
||
return datetime.now(timezone.utc).replace(tzinfo=None)
|
||
|
||
|
||
class Candle(Base):
|
||
__tablename__ = "candles"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||
symbol: Mapped[str] = mapped_column(String(16), index=True)
|
||
timeframe: Mapped[str] = mapped_column(String(4), default="1d", index=True)
|
||
ts: Mapped[datetime] = mapped_column(DateTime, index=True) # bar 开始时间
|
||
open: Mapped[float] = mapped_column(Float)
|
||
high: Mapped[float] = mapped_column(Float)
|
||
low: Mapped[float] = mapped_column(Float)
|
||
close: Mapped[float] = mapped_column(Float)
|
||
volume: Mapped[float] = mapped_column(Float)
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint("symbol", "timeframe", "ts", name="uq_candle_sym_tf_ts"),
|
||
)
|
||
|
||
|
||
class BacktestRun(Base):
|
||
"""回测运行注册表(可复现/可审计/可回归对比的基础)。
|
||
|
||
完整版应记录 策略版本 + 参数快照 + 数据快照(复权/数据源/库版本)+ 环境指纹 + 结果指纹。
|
||
MVP 先落关键字段,结构就位。
|
||
"""
|
||
__tablename__ = "backtest_runs"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||
created_at: Mapped[datetime] = mapped_column(DateTime, default=_utcnow)
|
||
symbol: Mapped[str] = mapped_column(String(16))
|
||
strategy: Mapped[str] = mapped_column(String(64))
|
||
timeframe: Mapped[str] = mapped_column(String(4), default="1d")
|
||
params_json: Mapped[str] = mapped_column(String, default="{}")
|
||
initial_cash: Mapped[float] = mapped_column(Float, default=100000.0)
|
||
total_return: Mapped[float] = mapped_column(Float, default=0.0)
|
||
max_drawdown: Mapped[float] = mapped_column(Float, default=0.0)
|
||
sharpe: Mapped[float] = mapped_column(Float, default=0.0)
|
||
num_trades: Mapped[int] = mapped_column(Integer, default=0)
|