Files
signal-platform/app/schemas/trade_setup.py
T
dennisthiessen da83f027e1
Deploy / lint (push) Successful in 5s
Deploy / test (push) Successful in 35s
Deploy / deploy (push) Successful in 25s
Drop over-progressed setups via live R:R; refresh trades on fetch
Answers "why does a too-far-progressed setup still show": setups are only
recalculated by the scheduled R:R scan and manual fetch; at creation
entry == current price (0% progress), so over-progression is a
between-scans drift effect and must be judged at read time.

- /trades now attaches current_price (latest close per ticker).
- Qualification drops setups whose R:R recomputed from the current price
  falls below min_rr — i.e. price already ran toward target (reward
  consumed) or through the stop. Reuses the existing min_rr threshold
  instead of a separate progress %; far cleaner (a 3:1 is already ~1:1
  by 33% progress). Skipped for historical setups (no current_price).
- Fix: useFetchSymbolData now invalidates the trades queries, so a fetch/
  recompute actually refreshes confidence/setups in the UI (was the cause
  of the stale 100% confidence lingering after recompute).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 14:02:10 +02:00

52 lines
1.3 KiB
Python

"""Pydantic schemas for trade setup endpoints."""
from __future__ import annotations
from datetime import date, datetime
from pydantic import BaseModel, Field
class TradeTargetResponse(BaseModel):
price: float
distance_from_entry: float
distance_atr_multiple: float
rr_ratio: float
probability: float
classification: str
sr_level_id: int
sr_strength: float
is_primary: bool = False
class RecommendationSummaryResponse(BaseModel):
action: str
reasoning: str | None
risk_level: str | None
composite_score: float
class TradeSetupResponse(BaseModel):
"""A single trade setup detected by the R:R scanner."""
id: int
symbol: str
direction: str
entry_price: float
stop_loss: float
target: float
rr_ratio: float
composite_score: float
detected_at: datetime
confidence_score: float | None = None
targets: list[TradeTargetResponse] = Field(default_factory=list)
conflict_flags: list[str] = Field(default_factory=list)
recommended_action: str | None = None
reasoning: str | None = None
risk_level: str | None = None
actual_outcome: str | None = None
outcome_date: date | None = None
evaluated_at: datetime | None = None
current_price: float | None = None
recommendation_summary: RecommendationSummaryResponse | None = None