6511a1020b
A NEUTRAL ("No Clear Setup") recommendation means the engine found no clear
directional trade, yet such setups could still qualify and even be crowned the
top pick purely on momentum rank (e.g. an extended momentum leader with a far,
5%-probability target). A NEUTRAL signal isn't actionable, so it shouldn't
qualify.
New `exclude_neutral` activation flag (default on): setup_qualifies drops setups
whose recommended_action is NEUTRAL. It lives in the shared gate, so it flows
through the dashboard's qualified/top-pick selection, the track record's
qualified stats, and the backtest (which computes recommended_action and gates on
meets_core). Toggleable in Admin → Settings → Activation; the frontend mirror and
activationSummary ("directional") match.
Re-run the backtest after enabling to confirm it holds/improves expectancy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
103 lines
3.7 KiB
Python
103 lines
3.7 KiB
Python
"""Admin request/response schemas."""
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class UserManagement(BaseModel):
|
|
"""Schema for user access management."""
|
|
has_access: bool
|
|
|
|
|
|
class PasswordReset(BaseModel):
|
|
"""Schema for resetting a user's password."""
|
|
new_password: str = Field(..., min_length=6)
|
|
|
|
|
|
class CreateUserRequest(BaseModel):
|
|
"""Schema for admin-created user accounts."""
|
|
username: str = Field(..., min_length=1)
|
|
password: str = Field(..., min_length=6)
|
|
role: str = Field(default="user", pattern=r"^(user|admin)$")
|
|
has_access: bool = False
|
|
|
|
|
|
class RegistrationToggle(BaseModel):
|
|
"""Schema for toggling registration on/off."""
|
|
enabled: bool
|
|
|
|
|
|
class SystemSettingUpdate(BaseModel):
|
|
"""Schema for updating a system setting."""
|
|
value: str = Field(..., min_length=1)
|
|
|
|
|
|
class DataCleanupRequest(BaseModel):
|
|
"""Schema for data cleanup — delete records older than N days."""
|
|
older_than_days: int = Field(..., gt=0)
|
|
|
|
|
|
class JobToggle(BaseModel):
|
|
"""Schema for enabling/disabling a scheduled job."""
|
|
enabled: bool
|
|
|
|
|
|
class RecommendationConfigUpdate(BaseModel):
|
|
high_confidence_threshold: float | None = Field(default=None, ge=0, le=100)
|
|
moderate_confidence_threshold: float | None = Field(default=None, ge=0, le=100)
|
|
confidence_diff_threshold: float | None = Field(default=None, ge=0, le=100)
|
|
signal_alignment_weight: float | None = Field(default=None, ge=0, le=1)
|
|
sr_strength_weight: float | None = Field(default=None, ge=0, le=1)
|
|
momentum_technical_divergence_threshold: float | None = Field(default=None, ge=0, le=100)
|
|
fundamental_technical_divergence_threshold: float | None = Field(default=None, ge=0, le=100)
|
|
|
|
|
|
class TickerUniverseUpdate(BaseModel):
|
|
universe: Literal["sp500", "nasdaq100", "nasdaq_all"]
|
|
|
|
|
|
class ActivationConfigUpdate(BaseModel):
|
|
"""Activation gate: what counts as an actionable signal."""
|
|
min_momentum_percentile: float | None = Field(default=None, ge=0, le=100)
|
|
min_rr: float | None = Field(default=None, ge=0)
|
|
min_confidence: float | None = Field(default=None, ge=0, le=100)
|
|
require_high_conviction: bool | None = None
|
|
exclude_conflicts: bool | None = None
|
|
exclude_neutral: bool | None = None
|
|
|
|
|
|
class ScheduleConfigUpdate(BaseModel):
|
|
"""Cron schedule for the pipelines + fundamentals. Crons are 5-field
|
|
(min hour dom month dow); timezone is an IANA name (e.g. Europe/Berlin)."""
|
|
schedule_timezone: str | None = Field(default=None, max_length=64)
|
|
schedule_daily_pipeline_cron: str | None = Field(default=None, max_length=120)
|
|
schedule_intraday_pipeline_cron: str | None = Field(default=None, max_length=120)
|
|
schedule_fundamentals_cron: str | None = Field(default=None, max_length=120)
|
|
|
|
|
|
class SentimentConfigUpdate(BaseModel):
|
|
"""Runtime sentiment LLM config. api_key is write-only; omit/empty to keep
|
|
the stored key."""
|
|
provider: Literal["openai", "gemini", "deepseek", "xai", "openai_compatible"] | None = None
|
|
model: str | None = Field(default=None, max_length=100)
|
|
api_key: str | None = Field(default=None, max_length=400)
|
|
base_url: str | None = Field(default=None, max_length=300)
|
|
|
|
|
|
class SentimentTestRequest(BaseModel):
|
|
ticker: str = Field(default="AAPL", max_length=10)
|
|
|
|
|
|
class AlertConfigUpdate(BaseModel):
|
|
"""Telegram alert config. bot_token is write-only; omit/empty to keep the
|
|
stored token."""
|
|
enabled: bool | None = None
|
|
bot_token: str | None = Field(default=None, max_length=200)
|
|
telegram_chat_id: str | None = Field(default=None, max_length=64)
|
|
qualified_enabled: bool | None = None
|
|
sr_proximity_enabled: bool | None = None
|
|
score_drop_enabled: bool | None = None
|
|
digest_enabled: bool | None = None
|
|
regime_quadrant_enabled: bool | None = None
|