Spaces:
Running
Running
| """ | |
| Quantitative Models: Features, Factors, and Signals. | |
| Stores computed quantitative data — technical features, | |
| factor exposures, and generated trading signals. | |
| """ | |
| from __future__ import annotations | |
| from datetime import date, datetime | |
| from sqlalchemy import Date, DateTime, Float, ForeignKey, Integer, String, Text, func | |
| from sqlalchemy.orm import Mapped, mapped_column, relationship | |
| from app.database import Base | |
| class FeatureData(Base): | |
| """Computed technical features for an asset (SMA, RSI, MACD, etc.).""" | |
| __tablename__ = "feature_data" | |
| id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) | |
| asset_id: Mapped[int] = mapped_column( | |
| Integer, ForeignKey("assets.id"), nullable=False, index=True | |
| ) | |
| date: Mapped[date] = mapped_column(Date, nullable=False, index=True) | |
| feature_name: Mapped[str] = mapped_column(String(100), nullable=False, index=True) | |
| feature_value: Mapped[float] = mapped_column(Float, nullable=True) | |
| parameters_json: Mapped[str] = mapped_column(Text, nullable=True) | |
| created_at: Mapped[datetime] = mapped_column( | |
| DateTime(timezone=True), server_default=func.now() | |
| ) | |
| asset = relationship("Asset", back_populates="features") | |
| def __repr__(self) -> str: | |
| return f"<FeatureData({self.feature_name}={self.feature_value}, date={self.date})>" | |
| class Factor(Base): | |
| """Quantitative factor definition (momentum, value, size, etc.).""" | |
| __tablename__ = "factors" | |
| id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) | |
| name: Mapped[str] = mapped_column(String(100), unique=True, nullable=False, index=True) | |
| display_name: Mapped[str] = mapped_column(String(200), nullable=True) | |
| description: Mapped[str] = mapped_column(Text, nullable=True) | |
| category: Mapped[str] = mapped_column( | |
| String(50), nullable=False | |
| ) # style, macro, sector, custom | |
| calculation_method: Mapped[str] = mapped_column(Text, nullable=True) | |
| is_active: Mapped[bool] = mapped_column(default=True, nullable=False) | |
| created_at: Mapped[datetime] = mapped_column( | |
| DateTime(timezone=True), server_default=func.now() | |
| ) | |
| exposures = relationship("FactorExposure", back_populates="factor", lazy="noload") | |
| def __repr__(self) -> str: | |
| return f"<Factor(name='{self.name}', category='{self.category}')>" | |
| class FactorExposure(Base): | |
| """Factor exposure (loading) for an asset on a given date.""" | |
| __tablename__ = "factor_exposures" | |
| id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) | |
| asset_id: Mapped[int] = mapped_column( | |
| Integer, ForeignKey("assets.id"), nullable=False, index=True | |
| ) | |
| factor_id: Mapped[int] = mapped_column( | |
| Integer, ForeignKey("factors.id"), nullable=False, index=True | |
| ) | |
| date: Mapped[date] = mapped_column(Date, nullable=False, index=True) | |
| exposure_value: Mapped[float] = mapped_column(Float, nullable=False) | |
| z_score: Mapped[float] = mapped_column(Float, nullable=True) | |
| percentile_rank: Mapped[float] = mapped_column(Float, nullable=True) | |
| created_at: Mapped[datetime] = mapped_column( | |
| DateTime(timezone=True), server_default=func.now() | |
| ) | |
| asset = relationship("Asset", back_populates="factor_exposures") | |
| factor = relationship("Factor", back_populates="exposures") | |
| def __repr__(self) -> str: | |
| return f"<FactorExposure(asset={self.asset_id}, factor={self.factor_id}, value={self.exposure_value})>" | |
| class Signal(Base): | |
| """Generated quantitative trading signal.""" | |
| __tablename__ = "signals" | |
| id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) | |
| name: Mapped[str] = mapped_column(String(200), nullable=False, index=True) | |
| signal_type: Mapped[str] = mapped_column( | |
| String(50), nullable=False | |
| ) # momentum, mean_reversion, sentiment, volatility, factor | |
| asset_id: Mapped[int] = mapped_column( | |
| Integer, ForeignKey("assets.id"), nullable=True, index=True | |
| ) | |
| date: Mapped[date] = mapped_column(Date, nullable=False, index=True) | |
| value: Mapped[float] = mapped_column(Float, nullable=False) | |
| strength: Mapped[float] = mapped_column(Float, nullable=True) # 0-1 confidence | |
| direction: Mapped[str] = mapped_column( | |
| String(10), nullable=True | |
| ) # long, short, neutral | |
| metadata_json: Mapped[str] = mapped_column(Text, nullable=True) | |
| created_at: Mapped[datetime] = mapped_column( | |
| DateTime(timezone=True), server_default=func.now() | |
| ) | |
| asset = relationship("Asset", back_populates="signals") | |
| def __repr__(self) -> str: | |
| return f"<Signal(name='{self.name}', type='{self.signal_type}', direction='{self.direction}')>" | |