85 lines
2.2 KiB
Python
85 lines
2.2 KiB
Python
# src/web/api/v2/schemas/calibration_risk.py
|
|
|
|
from typing import Literal, Optional, Dict, Any
|
|
from pydantic import BaseModel, Field, model_validator
|
|
|
|
|
|
|
|
class StopConfigSchema(BaseModel):
|
|
type: Literal["fixed", "trailing", "atr"]
|
|
|
|
stop_fraction: Optional[float] = Field(None, gt=0)
|
|
atr_period: Optional[int] = Field(None, gt=1)
|
|
atr_multiplier: Optional[float] = Field(None, gt=0)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_by_type(self):
|
|
if self.type in ("fixed", "trailing"):
|
|
if self.stop_fraction is None:
|
|
raise ValueError(
|
|
"stop_fraction required for fixed/trailing stop"
|
|
)
|
|
|
|
if self.type == "atr":
|
|
if self.atr_period is None:
|
|
raise ValueError(
|
|
"atr_period required for ATR stop"
|
|
)
|
|
if self.atr_multiplier is None:
|
|
raise ValueError(
|
|
"atr_multiplier required for ATR stop"
|
|
)
|
|
|
|
return self
|
|
|
|
|
|
# class StopConfigSchema(BaseModel):
|
|
# type: Literal["fixed", "trailing", "atr"]
|
|
|
|
# stop_fraction: Optional[float] = Field(None, gt=0)
|
|
|
|
# atr_period: Optional[int] = Field(None, gt=1)
|
|
# atr_multiplier: Optional[float] = Field(None, gt=0)
|
|
|
|
|
|
class RiskConfigSchema(BaseModel):
|
|
risk_fraction: float = Field(..., gt=0, lt=1)
|
|
max_position_fraction: float = Field(..., gt=0, lt=1)
|
|
|
|
|
|
class GlobalRiskRulesSchema(BaseModel):
|
|
max_drawdown_pct: float = Field(..., gt=0, lt=1)
|
|
|
|
daily_loss_limit_pct: Optional[float] = Field(None, gt=0, lt=1)
|
|
max_consecutive_losses: Optional[int] = Field(None, gt=0)
|
|
cooldown_bars: Optional[int] = Field(None, ge=0)
|
|
|
|
|
|
class CalibrationRiskInspectRequest(BaseModel):
|
|
symbol: str
|
|
timeframe: str
|
|
|
|
stop: StopConfigSchema
|
|
risk: RiskConfigSchema
|
|
global_rules: GlobalRiskRulesSchema
|
|
|
|
account_equity: float = Field(..., gt=0)
|
|
|
|
|
|
class CalibrationRiskInspectResponse(BaseModel):
|
|
valid: bool
|
|
status: Literal["ok", "warning", "fail"]
|
|
|
|
checks: Dict[str, Any]
|
|
message: str
|
|
|
|
class CalibrationRiskValidateResponse(BaseModel):
|
|
valid: bool
|
|
status: Literal["ok", "warning", "fail"]
|
|
|
|
checks: Dict[str, Any]
|
|
message: str
|
|
|
|
# ⬇️ NUEVO
|
|
series: Dict[str, Any]
|