feat: add quant strategy Pydantic schemas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3218e26a5a
commit
d671befb90
@ -9,6 +9,12 @@ from app.schemas.portfolio import (
|
||||
RebalanceItem, RebalanceResponse,
|
||||
RebalanceSimulationRequest, RebalanceSimulationResponse,
|
||||
)
|
||||
from app.schemas.strategy import (
|
||||
FactorWeights, UniverseFilter,
|
||||
StrategyRequest, MultiFactorRequest, QualityRequest, ValueMomentumRequest,
|
||||
StockFactor, StrategyResult,
|
||||
StockInfo, StockSearchResult, PriceData,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"UserBase",
|
||||
@ -24,4 +30,8 @@ __all__ = [
|
||||
"SnapshotResponse", "SnapshotHoldingResponse",
|
||||
"RebalanceItem", "RebalanceResponse",
|
||||
"RebalanceSimulationRequest", "RebalanceSimulationResponse",
|
||||
"FactorWeights", "UniverseFilter",
|
||||
"StrategyRequest", "MultiFactorRequest", "QualityRequest", "ValueMomentumRequest",
|
||||
"StockFactor", "StrategyResult",
|
||||
"StockInfo", "StockSearchResult", "PriceData",
|
||||
]
|
||||
|
||||
132
backend/app/schemas/strategy.py
Normal file
132
backend/app/schemas/strategy.py
Normal file
@ -0,0 +1,132 @@
|
||||
"""
|
||||
Quant strategy related Pydantic schemas.
|
||||
"""
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import Optional, List, Dict
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class FactorWeights(BaseModel):
|
||||
"""Factor weights for multi-factor strategy."""
|
||||
value: Decimal = Field(default=Decimal("0.25"), ge=0, le=1)
|
||||
quality: Decimal = Field(default=Decimal("0.25"), ge=0, le=1)
|
||||
momentum: Decimal = Field(default=Decimal("0.25"), ge=0, le=1)
|
||||
low_vol: Decimal = Field(default=Decimal("0.25"), ge=0, le=1)
|
||||
|
||||
|
||||
class UniverseFilter(BaseModel):
|
||||
"""Stock universe filtering criteria."""
|
||||
markets: List[str] = ["KOSPI", "KOSDAQ"]
|
||||
min_market_cap: Optional[int] = None # in 억원
|
||||
max_market_cap: Optional[int] = None
|
||||
exclude_stock_types: List[str] = ["spac", "preferred", "reit"]
|
||||
exclude_sectors: List[str] = []
|
||||
|
||||
|
||||
class StrategyRequest(BaseModel):
|
||||
"""Base request for running a strategy."""
|
||||
universe: UniverseFilter = UniverseFilter()
|
||||
top_n: int = Field(default=30, ge=1, le=100)
|
||||
base_date: Optional[date] = None
|
||||
|
||||
|
||||
class MultiFactorRequest(StrategyRequest):
|
||||
"""Multi-factor strategy request."""
|
||||
weights: FactorWeights = FactorWeights()
|
||||
|
||||
|
||||
class QualityRequest(StrategyRequest):
|
||||
"""Super Quality strategy request."""
|
||||
min_fscore: int = Field(default=7, ge=0, le=9)
|
||||
|
||||
|
||||
class ValueMomentumRequest(StrategyRequest):
|
||||
"""Value-Momentum strategy request."""
|
||||
value_weight: Decimal = Field(default=Decimal("0.5"), ge=0, le=1)
|
||||
momentum_weight: Decimal = Field(default=Decimal("0.5"), ge=0, le=1)
|
||||
|
||||
|
||||
class StockFactor(BaseModel):
|
||||
"""Factor scores for a single stock."""
|
||||
ticker: str
|
||||
name: str
|
||||
market: str
|
||||
sector_name: Optional[str] = None
|
||||
market_cap: Optional[int] = None
|
||||
close_price: Optional[Decimal] = None
|
||||
|
||||
# Raw metrics
|
||||
per: Optional[Decimal] = None
|
||||
pbr: Optional[Decimal] = None
|
||||
psr: Optional[Decimal] = None
|
||||
pcr: Optional[Decimal] = None
|
||||
dividend_yield: Optional[Decimal] = None
|
||||
roe: Optional[Decimal] = None
|
||||
|
||||
# Factor scores (z-scores)
|
||||
value_score: Optional[Decimal] = None
|
||||
quality_score: Optional[Decimal] = None
|
||||
momentum_score: Optional[Decimal] = None
|
||||
|
||||
# Composite
|
||||
total_score: Optional[Decimal] = None
|
||||
rank: Optional[int] = None
|
||||
fscore: Optional[int] = None
|
||||
|
||||
|
||||
class StrategyResult(BaseModel):
|
||||
"""Result from running a strategy."""
|
||||
strategy_name: str
|
||||
base_date: date
|
||||
universe_count: int
|
||||
result_count: int
|
||||
stocks: List[StockFactor]
|
||||
|
||||
|
||||
class StockInfo(BaseModel):
|
||||
"""Detailed stock information."""
|
||||
ticker: str
|
||||
name: str
|
||||
market: str
|
||||
sector_name: Optional[str] = None
|
||||
stock_type: str
|
||||
close_price: Optional[Decimal] = None
|
||||
market_cap: Optional[int] = None
|
||||
|
||||
# Valuation
|
||||
per: Optional[Decimal] = None
|
||||
pbr: Optional[Decimal] = None
|
||||
psr: Optional[Decimal] = None
|
||||
pcr: Optional[Decimal] = None
|
||||
dividend_yield: Optional[Decimal] = None
|
||||
|
||||
# Per-share data
|
||||
eps: Optional[Decimal] = None
|
||||
bps: Optional[Decimal] = None
|
||||
|
||||
base_date: Optional[date] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class StockSearchResult(BaseModel):
|
||||
"""Stock search result."""
|
||||
ticker: str
|
||||
name: str
|
||||
market: str
|
||||
|
||||
|
||||
class PriceData(BaseModel):
|
||||
"""Price data point."""
|
||||
date: date
|
||||
open: Decimal
|
||||
high: Decimal
|
||||
low: Decimal
|
||||
close: Decimal
|
||||
volume: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
Loading…
x
Reference in New Issue
Block a user